From d40127ed66258d4d4198d3d1ae15355504e6ad57 Mon Sep 17 00:00:00 2001 From: Youwen Wu Date: Tue, 4 Feb 2025 21:51:21 -0800 Subject: [PATCH] feat: finish chapter 4 program 3 --- meson.build | 10 ++++ src/chapter_4/program_3/Card.cpp | 65 ++++++++++++++++++++ src/chapter_4/program_3/Card.h | 48 +++++++++++++++ src/chapter_4/program_3/Deck.cpp | 29 +++++++++ src/chapter_4/program_3/Deck.h | 50 ++++++++++++++++ src/chapter_4/program_3/hands.dat | 6 ++ src/chapter_4/program_3/main.cpp | 98 +++++++++++++++++++++++++++++++ 7 files changed, 306 insertions(+) create mode 100644 src/chapter_4/program_3/Card.cpp create mode 100644 src/chapter_4/program_3/Card.h create mode 100644 src/chapter_4/program_3/Deck.cpp create mode 100644 src/chapter_4/program_3/Deck.h create mode 100644 src/chapter_4/program_3/hands.dat create mode 100644 src/chapter_4/program_3/main.cpp diff --git a/meson.build b/meson.build index 5d04055..b1903df 100644 --- a/meson.build +++ b/meson.build @@ -28,3 +28,13 @@ c_4_lab_4 = executable( ['src/chapter_4/lab_4/main.cpp', 'src/chapter_4/lab_4/Distance.cpp'], install: true, ) + +c_4_program_3 = executable( + 'c_4_program_3', + [ + 'src/chapter_4/program_3/main.cpp', + 'src/chapter_4/program_3/Card.cpp', + 'src/chapter_4/program_3/Deck.cpp', + ], + install: true, +) diff --git a/src/chapter_4/program_3/Card.cpp b/src/chapter_4/program_3/Card.cpp new file mode 100644 index 0000000..f5c8e6e --- /dev/null +++ b/src/chapter_4/program_3/Card.cpp @@ -0,0 +1,65 @@ +#include "Card.h" + +Card::Card() { + suit = 'c'; + rank = 2; +} + +Card::Card(char suit, int rank) { + char suit_lowered = tolower(suit); + if (suit_lowered != 'c' && suit_lowered != 'h' && suit_lowered != 's' && + suit_lowered != 'd') { + this->suit = 'c'; + } else { + this->suit = suit_lowered; + } + if (rank < 0 || rank > 13) { + this->rank = 2; + } else { + this->rank = rank; + } +} + +char Card::getSuit() const { return this->suit; } +int Card::getRank() const { return this->rank; } + +ostream &operator<<(ostream &stream, const Card &card) { + string suitName; + string cardName; + + switch (card.suit) { + case 'c': + suitName = "Clubs"; + break; + case 'd': + suitName = "Diamonds"; + break; + case 'h': + suitName = "Hearts"; + break; + case 's': + suitName = "Spades"; + break; + } + + switch (card.rank) { + case 1: + cardName = "Ace"; + break; + case 11: + cardName = "Jack"; + break; + case 12: + cardName = "Queen"; + break; + case 13: + cardName = "King"; + break; + default: + cardName = to_string(card.rank); + } + + stream << cardName << " of " << suitName; + + return stream; +} diff --git a/src/chapter_4/program_3/Card.h b/src/chapter_4/program_3/Card.h new file mode 100644 index 0000000..0910cbf --- /dev/null +++ b/src/chapter_4/program_3/Card.h @@ -0,0 +1,48 @@ +//Card interface file +#ifndef __CARD_H__ +#define __CARD_H__ + +#include + +using namespace std; + +class Card { + private: + char suit; + int rank; + public: + + /* Assigns a default value of 2 of Clubs + */ + Card(); + + + /* Assigns the Card the suit and rank provided. + suits: c = Clubs, d = Diamonds, h = Hearts, s = Spades + If an invalid suit is provided, sets the suit to Clubs + ranks: 1 - 13 (1 = Ace, 11 = Jack, 12 = Queen, 13 = King) + If an invalid rank is provided, sets the rank to 2 + Accepts lower or upper case characters for suit + */ + Card(char, int); + + + /* Returns the Card's suit + */ + char getSuit() const; + + + /* Returns the Card's rank as an integer + */ + int getRank() const; + + /* Outputs a Card in the following format: Rank of Suit + For example, if the rank is 3 and the suit is h: 3 of Hearts + Or, if the rank is 1 and the suit is d: Ace of Diamonds + Or, if the rank is 12 and the suit is c: Queen of Clubs + etc. + */ + friend ostream & operator<<(ostream &, const Card &); +}; + +#endif diff --git a/src/chapter_4/program_3/Deck.cpp b/src/chapter_4/program_3/Deck.cpp new file mode 100644 index 0000000..0a4178f --- /dev/null +++ b/src/chapter_4/program_3/Deck.cpp @@ -0,0 +1,29 @@ +#include "Deck.h" +#include + +Deck::Deck() { + char suits[] = {'s', 'h', 'd', 'c'}; + + for (char c : suits) { + for (int i = 13; i >= 1; i--) { + theDeck.push_back(Card(c, i)); + } + } +} + +void Deck::shuffleDeck() { + for (auto c : dealtCards) { + theDeck.push_back(c); + } + dealtCards.clear(); + random_shuffle(theDeck.begin(), theDeck.end()); +} + +unsigned Deck::deckSize() const { return theDeck.size(); } + +Card Deck::dealCard() { + Card back = theDeck.back(); + dealtCards.push_back(back); + theDeck.pop_back(); + return back; +} diff --git a/src/chapter_4/program_3/Deck.h b/src/chapter_4/program_3/Deck.h new file mode 100644 index 0000000..01bfbf2 --- /dev/null +++ b/src/chapter_4/program_3/Deck.h @@ -0,0 +1,50 @@ +#ifndef __DECK_H__ +#define __DECK_H__ + +#include +using namespace std; + +#include "Card.h" + +class Deck { + private: + vector theDeck; + vector dealtCards; + public: + /* Constructs a Deck of 52 cards: + Ace, 2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, King of each suit. + Cards should start off in this order with the order of suits being: + Clubs, Diamonds, Hearts, Spades. So, the Card at the top of the + Deck should be the Ace of Clubs. The next Card should be 2 of Clubs. + The 3rd Card should be 3 of Clubs, and so on ... + + For best efficiency, the top of Deck should be stored at + back end of vector. + */ + Deck(); + + /* Deals (returns) the top card of the deck. + Removes this card from theDeck and places it in dealtCards. + As mentioned in comments for the constructor, + for best efficiency, the top card should come from the + back end of vector. + */ + Card dealCard(); + + + /* Places all cards back into theDeck and shuffles them into random order. + Use random_shuffle function from algorithm library. + To pass test harness, this function must go forward through dealtCards + pushing each Card onto the back end of theDeck, then clear dealtCards. + Do not use pop_back on dealtCards. + */ + void shuffleDeck(); + + + /* returns the size of the Deck (how many cards have not yet been dealt). + */ + unsigned deckSize() const; +}; + +#endif + diff --git a/src/chapter_4/program_3/hands.dat b/src/chapter_4/program_3/hands.dat new file mode 100644 index 0000000..98e9394 --- /dev/null +++ b/src/chapter_4/program_3/hands.dat @@ -0,0 +1,6 @@ +Found Pair!! Ace of Hearts, 8 of Diamonds, 9 of Hearts, 3 of Hearts, 9 of Spades, 5 of Spades, 10 of Diamonds, 9 of Diamonds, Queen of Spades, 8 of Spades, +Found Pair!! 5 of Clubs, 9 of Hearts, 3 of Spades, 2 of Spades, King of Spades, 2 of Clubs, King of Diamonds, Jack of Spades, Jack of Diamonds, 5 of Diamonds, +Found Pair!! 3 of Spades, Jack of Diamonds, 9 of Spades, 4 of Spades, 10 of Clubs, 7 of Spades, 9 of Diamonds, 7 of Hearts, Ace of Clubs, 4 of Diamonds, +Found Pair!! Ace of Clubs, 9 of Hearts, 6 of Spades, 9 of Spades, 2 of Hearts, Queen of Diamonds, 4 of Spades, Jack of Spades, 8 of Diamonds, 5 of Clubs, +Found Pair!! 3 of Clubs, Ace of Spades, 6 of Hearts, 5 of Clubs, 7 of Clubs, King of Spades, 10 of Spades, Queen of Hearts, King of Clubs, Jack of Diamonds, + diff --git a/src/chapter_4/program_3/main.cpp b/src/chapter_4/program_3/main.cpp new file mode 100644 index 0000000..c321986 --- /dev/null +++ b/src/chapter_4/program_3/main.cpp @@ -0,0 +1,98 @@ +#include +#include +#include +#include + +using namespace std; + +#include "Card.h" +#include "Deck.h" + +// Returns true if vector of Cards passed in contains at least 2 Cards with the +// same rank. +bool hasPair(const vector); +double simulateMonteCarlo(Deck, int, int, bool, ostream &); + +// Sends to output stream a hand of Cards on a single line, +// each Card separated by a comma. +// If the vector is empty, do not output anything. +// Example (vector size of 3): Ace of Spades, Two of Hearts, King of Clubs +ostream &operator<<(ostream &, const vector &); + +int main() { + srand(2222); + bool toFile; + int numOfHands; + int numOfDeals; + string filename; + string in; + fstream file; + + cout << "Do you want to output all hands to a file?(Yes/No)"; + + cin >> in; + toFile = in == "Yes"; + if (toFile) { + cout << endl << "Enter name of output file: "; + cin >> filename; + file.open(filename, fstream::out); + }; + cout << endl << "Enter number of cards per hand: "; + cin >> numOfHands; + cout << endl << "Enter number of deals (simulations): "; + cin >> numOfDeals; + + double probability = + simulateMonteCarlo(Deck(), numOfHands, numOfDeals, toFile, file); + + cout << endl + << "Chances of receiving a pair in a hand of " << numOfHands + << " cards is: " << (probability * 100) << '%' << endl; + + return 0; +} + +double simulateMonteCarlo(Deck deck, int numOfHands, int numOfDeals, + bool shouldStreamOutput, ostream &stream) { + int pairCount = 0; + vector hand; + for (int i = 0; i < numOfDeals; i++) { + deck.shuffleDeck(); + for (int j = 0; j < numOfHands; j++) { + hand.push_back(deck.dealCard()); + } + if (hasPair(hand)) { + pairCount++; + if (shouldStreamOutput) { + stream << "Found Pair!! "; + } + } else { + if (shouldStreamOutput) { + stream << " "; + } + } + if (shouldStreamOutput) { + for (unsigned int i = 0; i < hand.size(); i++) { + stream << hand.at(i); + if (i < hand.size() - 1) { + stream << ", "; + } + } + stream << endl; + } + hand.clear(); + } + + return static_cast(pairCount) / static_cast(numOfDeals); +} + +bool hasPair(const vector vec) { + for (unsigned int i = 0; i < vec.size() - 1; i++) { + for (unsigned int j = i + 1; j < vec.size(); j++) { + if (vec.at(i).getRank() == vec.at(j).getRank()) { + return true; + } + } + } + return false; +}