diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..12ddb50 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.17) +project(Proj) + +set(CMAKE_CXX_STANDARD 17) + +file(GLOB SOURCES + sources/*.cpp + ) +include_directories(include) +add_executable(Proj ${SOURCES}) diff --git a/README.md b/README.md index 97b21fb..2b4ec54 100644 --- a/README.md +++ b/README.md @@ -1 +1,37 @@ -# Pocker-ProjectTP- +# Poker + +### Structure of the game: + + + * There is a card tableю Player is up to choose one of the 2 modes of poker to play: [**Classical Poker**](https://en.wikipedia.org/wiki/Draw_poker) and [**No Limit Texas Holdem**](https://en.wikipedia.org/wiki/Texas_hold_%27em). + In the beginning of the game, players register by entering their names. + +### Details of realization: + + * All players initially have the same amount of money, 100 conventional units. At the beginning of the game, players are randomly dealt 2 cards. + Each card has its own value and suit. Users take turns: _raising/calling/folding_, + while game stages consequently change in the following order: _preflop, flop, turn, river_. Before the move of next player, other players' moves are hidden, current best combination for this player is shown. + + * At the end of the round, based on the cards on the table and in the hands of the remaining players, the winner is determined who takes all the pot. + Players with no money left are eliminated and new round begins. + The game is played until there is only **one winner** left. + +### Useful patterns and hints used: + + 1. Observer + 2. Command - players' actions + + + We tried our best to comply with the **SOLID principles**. + +### Installation: + +> $ git clone git@github.com:tasticolly/Pocker-ProjectTP-.git +> +> $ cmake -B build +> +> $ cmake --build build + +### Run: + +> $ ./build/Proj diff --git a/description/ATP_POCKER.pdf b/description/ATP_POCKER.pdf new file mode 100644 index 0000000..01c7cf0 Binary files /dev/null and b/description/ATP_POCKER.pdf differ diff --git a/include/Card.h b/include/Card.h new file mode 100644 index 0000000..525fbd4 --- /dev/null +++ b/include/Card.h @@ -0,0 +1,27 @@ +#include +#ifndef CARD_H_ +#define CARD_H_ +using std::string; + +enum Suit{ + HEARTS=1, DIAMONDS, SPADES, CLUBS}; +enum Face{ + TWO=1, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE}; + +class Card { +private: + Suit suit; + Face face; +public: + Card(const Suit& suit, const Face& face); + Face getFace() const; + void setFace(Face face); + Suit getSuit() const; + void setSuit(Suit suit); + string getSuitString(); + string getFaceString(); + string toString(); + virtual ~Card(); +}; + +#endif /* CARD_H_ */ diff --git a/include/Deck.h b/include/Deck.h new file mode 100644 index 0000000..f0169e6 --- /dev/null +++ b/include/Deck.h @@ -0,0 +1,32 @@ +#ifndef DECK_H_ +#define DECK_H_ + +#include +#include +#include +#include +#include "Card.h" +using std::vector; +using std::cout; +using std::endl; + + +class Deck { +private: + vector deck; +public: + Deck(); + Deck(const vector& deck); + void initDeck(); + const vector& getDeck() const; + void setDeck(const vector& deck); + void shuffle(); + int cardsRemaining(); + vector dealHand(const int& size); + Card drawCard(const unsigned& index = 0); + void addCard(const Card& card); + string toString(); + virtual ~Deck(); +}; + +#endif /* DECK_H_ */ diff --git a/include/Hand.h b/include/Hand.h new file mode 100644 index 0000000..17c3e5d --- /dev/null +++ b/include/Hand.h @@ -0,0 +1,59 @@ +#ifndef HAND_H_ +#define HAND_H_ +#include "Card.h" +#include +#include +#include +using std::vector; +using std::string; +using std::cout; +using std::endl; +using std::stringstream; + +class Hand { +private: + string ownerName; + vector hand; + unsigned short countFaces[13]; + unsigned short countSuits[4]; +public: + Hand(const vector& hand); + + const vector& getHand() const; + void setHand(const vector& hand); + const string& getOwnerName() const; + void setOwnerName(const string& ownerName); + + friend Hand operator+(Hand& hand1, Hand& hand2); + friend bool operator>(Hand& hand1, Hand& hand2); + friend bool operator<(Hand& hand1, Hand& hand2); + friend bool operator>=(Hand& hand1, Hand& hand2); + friend bool operator<=(Hand& hand1, Hand& hand2); + friend bool operator==(Hand& hand1, Hand& hand2); + + void countCardProps(); + void sortBySuit(const bool& asc = false); + void sortByFace(const bool& asc = false); + void swapCards(const unsigned& index1, const unsigned& index2); + Card getCard(int index); + Card peekCard(int index); + void addCard(Card card); + int cardsRemaining(); + bool hasFaceMatch(const int& num1, const int& num2 = 0); + bool hasSuitMatch(const int& num); + bool hasStraight(); + unsigned short getHighestCard(const short& recur = 0); + unsigned short getHighestCombo(const short& recur = 0); + int evaluate(); + string printEvaluation(); + string toFaceSymbol(const Face& index); + string toSuitSymbol(const Suit& index); + string drawHand(const int& faceDown = 0); + string toString(); + static void winner(Hand& h1, Hand& h2); + static int determineWinner(Hand& hand1, Hand& hand2); + + virtual ~Hand(); +}; + +#endif /* HAND_H_ */ diff --git a/include/PokerGame.h b/include/PokerGame.h new file mode 100644 index 0000000..24599a8 --- /dev/null +++ b/include/PokerGame.h @@ -0,0 +1,39 @@ +#ifndef POKERGAME_H_ +#define POKERGAME_H_ + +#include +#include +#include +#include "Deck.h" +#include "Hand.h" +using namespace std; + +class PokerGame { +private: + Deck deck; + unsigned short numOfPlayers{}; + unsigned short gameType; + vector playerHands; + vector credit; + stringstream history; + static void splash(); + static void clearScreen(); + static void pause(); + static void dash(); +public: + PokerGame(); + unsigned short getNumOfPlayers() const; + unsigned short getGameType() const; + const vector& getPlayerHands() const; + void setNumOfPlayers(unsigned short numOfPlayers); + void setGameType(unsigned short gameType); + void setPlayerHands(const vector& playerHands); + void discardFromHand(Hand& hand, int discard); + void beginGame(); + void gameInit(); + void classicGameLoop(int turns = 1); + void texasGameLoop(int turns = 1); + virtual ~PokerGame(); +}; + +#endif /* POKERGAME_H_ */ diff --git a/sources/Card.cpp b/sources/Card.cpp new file mode 100644 index 0000000..b054545 --- /dev/null +++ b/sources/Card.cpp @@ -0,0 +1,58 @@ +#include "Card.h" + +Card::Card(const Suit& suit, const Face& face) { + setSuit(suit); + setFace(face); +} + +string Card::getSuitString() { + switch(suit){ + case HEARTS: return "Hearts"; + case DIAMONDS: return "Diamonds"; + case SPADES: return "Spades"; + case CLUBS: return "Clubs"; + default: return "Unknown"; + } +} + +string Card::getFaceString() { + switch(face){ + case TWO: return "Two"; + case THREE: return "Three"; + case FOUR: return "Four"; + case FIVE: return "Five"; + case SIX: return "Six"; + case SEVEN: return "Seven"; + case EIGHT: return "Eight"; + case NINE: return "Nine"; + case TEN: return "Ten"; + case JACK: return "Jack"; + case QUEEN: return "Queen"; + case KING: return "King"; + case ACE: return "Ace"; + default: return "Unknown"; + } +} + +string Card::toString() { + return getFaceString() + " of " + getSuitString(); +} + +Face Card::getFace() const { + return face; +} + +void Card::setFace(Face face) { + this->face = face; +} + +Suit Card::getSuit() const { + return suit; +} + +void Card::setSuit(Suit suit) { + this->suit = suit; +} + +Card::~Card() { +} diff --git a/sources/Deck.cpp b/sources/Deck.cpp new file mode 100644 index 0000000..0a1a0d7 --- /dev/null +++ b/sources/Deck.cpp @@ -0,0 +1,65 @@ +#include "Deck.h" + +Deck::Deck() { + srand(time(nullptr)); + initDeck(); +} + +Deck::Deck(const vector &deck) { + srand(time(nullptr)); + setDeck(deck); +} + +void Deck::initDeck() { + vector newDeck; + for (int i = TWO; i != ACE + 1; ++i) + for (int j = HEARTS; j != CLUBS + 1; ++j) + newDeck.emplace_back(static_cast(j), static_cast(i)); + setDeck(newDeck); +} + +void Deck::setDeck(const vector& deck_) { + this->deck = deck_; +} + +void Deck::shuffle() { + vector newDeck; + int rnum; + while (!deck.empty()) { + rnum = rand() % deck.size(); + newDeck.push_back(drawCard(rnum)); + } + setDeck(newDeck); +} + +Card Deck::drawCard(const unsigned &index) { + Card drawnCard = deck[index]; + deck.erase(deck.begin() + index); + return drawnCard; +} + +void Deck::addCard(const Card& card_) { + deck.push_back(card_); +} + +vector Deck::dealHand(const int &size) { + vector hand; + for (int i = 0; i < size; ++i) + hand.push_back(drawCard(0)); + return hand; +} + +string Deck::toString() { + string str = ""; + for (int i = 0; i < cardsRemaining(); ++i) + str += deck[i].toString() + "\n"; + return str; +} + +const vector &Deck::getDeck() const { return deck; } + +int Deck::cardsRemaining() { return deck.size(); } + +Deck::~Deck() = default; + + diff --git a/sources/Hand.cpp b/sources/Hand.cpp new file mode 100644 index 0000000..825b7a3 --- /dev/null +++ b/sources/Hand.cpp @@ -0,0 +1,403 @@ +#include "Hand.h" + +//Constructor +Hand::Hand(const vector &hand) { + setHand(hand); + countCardProps(); +} + +//Count number of faces and suits in the hand + +void Hand::countCardProps() { + for (unsigned i = 0; i < sizeof(countFaces) / sizeof(countFaces[0]); ++i) + countFaces[i] = 0; + for (unsigned i = 0; i < sizeof(countSuits) / sizeof(countSuits[0]); ++i) + countSuits[i] = 0; + for (unsigned i = 0; i < hand.size(); ++i) { + ++countFaces[hand[i].getFace() - 1]; + ++countSuits[hand[i].getSuit() - 1]; + } +} + +//Hand getter +const vector &Hand::getHand() const { + return hand; +} + +//Hand setter +void Hand::setHand(const vector &hand) { + this->hand = hand; +} + +const string &Hand::getOwnerName() const { + return ownerName; +} + +void Hand::setOwnerName(const string &ownerName) { + this->ownerName = ownerName; +} + +Hand operator+(Hand &hand1, Hand &hand2) { + Hand h1 = hand1; + Hand h2 = hand2; + while (h2.cardsRemaining() > 0) h1.addCard(h2.getCard(0)); + return h1; +} + +bool operator>(Hand &hand1, Hand &hand2) { return (Hand::determineWinner(hand1, hand2) == 1 ? true : false); } + +bool operator<(Hand &hand1, Hand &hand2) { return (Hand::determineWinner(hand1, hand2) == -1 ? true : false); } + +bool operator>=(Hand &hand1, Hand &hand2) { return (Hand::determineWinner(hand1, hand2) >= 0 ? true : false); } + +bool operator<=(Hand &hand1, Hand &hand2) { return (Hand::determineWinner(hand1, hand2) <= 0 ? true : false); } + +bool operator==(Hand &hand1, Hand &hand2) { return (Hand::determineWinner(hand1, hand2) == 0 ? true : false); } + +//Sort hand by suit +void Hand::sortBySuit(const bool &asc) { + unsigned tmp; + for (unsigned i = 0; i < getHand().size(); ++i) { + tmp = i; + for (unsigned j = i; j < getHand().size(); ++j) { + if (asc) { + if (getHand()[j].getSuit() < getHand()[tmp].getSuit()) tmp = j; + } else { + if (getHand()[j].getSuit() > getHand()[tmp].getSuit()) tmp = j; + } + } + swapCards(i, tmp); + } +} + +//Sort hand by face +void Hand::sortByFace(const bool &asc) { + unsigned tmp; + for (unsigned i = 0; i < getHand().size(); ++i) { + tmp = i; + for (unsigned j = i; j < getHand().size(); ++j) { + if (asc) { + if (getHand()[j].getFace() < getHand()[tmp].getFace()) tmp = j; + } else { + if (getHand()[j].getFace() > getHand()[tmp].getFace()) tmp = j; + } + } + swapCards(i, tmp); + } +} + +//Swap position of two cards +void Hand::swapCards(const unsigned &index1, const unsigned &index2) { + Card tmp = hand[index1]; + hand[index1] = hand[index2]; + hand[index2] = tmp; +} + +//Draw a card from the hand +Card Hand::getCard(int index) { + Card selected = hand[index]; + hand.erase(hand.begin() + index); + return selected; +} + +Card Hand::peekCard(int index) { + return hand[index]; +} + +void Hand::addCard(Card card) { + hand.push_back(card); +} + +//Number of cards remaining +int Hand::cardsRemaining() { + return hand.size(); +} + +//Find if hand has a face match +bool Hand::hasFaceMatch(const int &num1, const int &num2) { + bool flag1 = 0, flag2 = 0; + for (unsigned i = 0; i < sizeof(countFaces) / sizeof(countFaces[0]); ++i) { + if (countFaces[i] == num1 && !flag1) { + flag1 = true; + continue; + } + if (countFaces[i] == num2) flag2 = true; + } + return (flag1 & flag2); +} + +//Find if hand has a number of matching suits +bool Hand::hasSuitMatch(const int &num) { + for (unsigned i = 0; i < sizeof(countSuits) / sizeof(countSuits[0]); ++i) + if (countSuits[i] == num) return true; + return false; +} + +//Find if hand has a straight +bool Hand::hasStraight() { + unsigned iterator = 0; + while (countFaces[iterator] == 0) { ++iterator; } + for (unsigned i = iterator; i < iterator + 5; ++i) + if (countFaces[i] == 0 || i >= sizeof(countFaces) / sizeof(countFaces[0])) return false; + return true; +} + +//Find the highest card value from the hand +unsigned short Hand::getHighestCard(const short &recur) { + unsigned short count = 0; + for (unsigned short i = 0; i < sizeof(countFaces) / sizeof(countFaces[0]); ++i) + if (countFaces[i] > 0) ++count; + if (count == 0) return 0; + unsigned short index = (sizeof(countFaces) / sizeof(countFaces[0]) - 1); + while (countFaces[index] == 0) { --index; } + if (recur > 0) { + countFaces[index] = 0; + return getHighestCard(recur - 1); + } + countCardProps(); + return index; +} + +//Find the highest combo +unsigned short Hand::getHighestCombo(const short &recur) { + unsigned short count = 0; + for (unsigned short i = 1; i < sizeof(countFaces) / sizeof(countFaces[0]); ++i) + if (countFaces[i] >= countFaces[count]) count = i; + if (recur > 0) { + countFaces[count] = 0; + return getHighestCombo(recur - 1); + } + countCardProps(); + return count; +} + +//Get a hand evaluation +int Hand::evaluate() { + countCardProps(); + if (hasStraight() && hasSuitMatch(5)) return 8; + if (hasFaceMatch(4)) return 7; + if (hasFaceMatch(3, 2)) return 6; + if (hasSuitMatch(5)) return 5; + if (hasStraight()) return 4; + if (hasFaceMatch(3)) return 3; + if (hasFaceMatch(2, 2)) return 2; + if (hasFaceMatch(2)) return 1; + return 0; +} + +//Return a string evaluation +string Hand::printEvaluation() { + switch (evaluate()) { + case 0: + return "High Card"; + case 1: + return "One Pair"; + case 2: + return "Two Pair"; + case 3: + return "Three Of A Kind"; + case 4: + return "Straight"; + case 5: + return "Flush"; + case 6: + return "Full House"; + case 7: + return "Four Of A Kind"; + case 8: + return "Straight Flush"; + default: + return "Error"; + } +} + +//Convert card face index to a symbol +string Hand::toFaceSymbol(const Face &index) { + switch (index) { + case TWO: + return "2"; + case THREE: + return "3"; + case FOUR: + return "4"; + case FIVE: + return "5"; + case SIX: + return "6"; + case SEVEN: + return "7"; + case EIGHT: + return "8"; + case NINE: + return "9"; + case TEN: + return "T"; + case JACK: + return "J"; + case QUEEN: + return "Q"; + case KING: + return "K"; + case ACE: + return "A"; + default: + return "0"; + } +} + +//Convert card suit index to a symbol +string Hand::toSuitSymbol(const Suit &index) { + switch (index) { + case HEARTS: + return "♥"; + case DIAMONDS: + return "♦"; + case SPADES: + return "♠"; + case CLUBS: + return "♣"; + default: + return "O"; + } +} + +//Get a string of drawn cards from the hand +string Hand::drawHand(const int &faceDown) { + stringstream str; + for (unsigned i = 0; i < 5; ++i) { + int tmp = faceDown; + for (unsigned j = 0; j < hand.size(); ++j) { + switch (i) { + case 0: + str << "┌─────┐"; + break; + case 1: + (tmp & 1) ? str << "│░░░░░│" : str << "│" << toFaceSymbol(hand[j].getFace()) << " │"; + break; + case 2: + (tmp & 1) ? str << "│░░░░░│" : str << "│ " << toSuitSymbol(hand[j].getSuit()) << " │"; + break; + case 3: + (tmp & 1) ? str << "│░░░░░│" : str << "│ " << toFaceSymbol(hand[j].getFace()) << "│"; + break; + case 4: + str << "└─────┘"; + break; + } + tmp = tmp >> 1; + } + str << endl; + } + return str.str(); +} + +//Get a string of cards from the hand +string Hand::toString() { + string str = ""; + for (unsigned i = 0; i < hand.size(); ++i) + str += hand[i].toString() + "\n"; + return str; +} + +//Destructor +Hand::~Hand() { +} + +int Hand::determineWinner(Hand &hand1, Hand &hand2) { + if (hand1.evaluate() > hand2.evaluate()) return 1; + else if (hand1.evaluate() < hand2.evaluate()) return -1; + else { + int recur; + switch (hand1.evaluate()) { + case 1: + case 2: + case 3: + case 6: + case 7: + recur = (hand1.evaluate() == 2 ? 2 : hand1.evaluate() == 6 ? 1 : 0); + for (int i = 0; i <= recur; ++i) { + if (hand1.getHighestCombo(i) > hand2.getHighestCombo(i)) return 1; + else if (hand1.getHighestCombo(i) < hand2.getHighestCombo(i)) return -1; + } + break; + case 0: + case 4: + case 5: + case 8: + if (hand1.getHighestCard() > hand2.getHighestCard()) return 1; + else if (hand1.getHighestCard() < hand2.getHighestCard()) return -1; + else { + recur = 0; + cout << endl; + while (hand1.getHighestCard(recur) == hand2.getHighestCard(recur) && + recur < hand1.cardsRemaining()) { ++recur; } + if (hand1.getHighestCard(recur) > hand2.getHighestCard(recur)) return 1; + else if (hand1.getHighestCard(recur) < hand2.getHighestCard(recur)) return -1; + } + } + } + return 0; +} + + +//Winner logic +void Hand::winner(Hand &hand1, Hand &hand2) { + if (hand1.evaluate() > hand2.evaluate()) + cout << "1 wins with " << hand1.printEvaluation() << " against " << hand2.printEvaluation(); + else if (hand1.evaluate() < hand2.evaluate()) + cout << "2 wins with " << hand2.printEvaluation() << " against " << hand1.printEvaluation(); + else { + int recur; + switch (hand1.evaluate()) { + case 1: + case 2: + case 3: + case 6: + case 7: + recur = (hand1.evaluate() == 2 ? 2 : hand1.evaluate() == 6 ? 1 : 0); + for (int i = 0; i <= recur; ++i) { + if (hand1.getHighestCombo(i) > hand2.getHighestCombo(i)) { + cout << "1 wins with " << hand1.printEvaluation() << " and highest card " + << hand1.toFaceSymbol(static_cast(hand1.getHighestCombo(i) + 1)); + break; + } else if (hand1.getHighestCombo(i) < hand2.getHighestCombo(i)) { + cout << "2 wins with " << hand2.printEvaluation() << " and highest card " + << hand2.toFaceSymbol(static_cast(hand2.getHighestCombo(i) + 1)); + break; + } + } + break; + case 0: + case 4: + case 5: + case 8: + if (hand1.getHighestCard() > hand2.getHighestCard()) { + cout << "1 wins with " << hand1.printEvaluation() << " and highest card " + << hand1.toFaceSymbol(static_cast(hand1.getHighestCard() + 1)); + break; + } else if (hand1.getHighestCard() < hand2.getHighestCard()) { + cout << "2 wins with " << hand2.printEvaluation() << " and highest card " + << hand2.toFaceSymbol(static_cast(hand2.getHighestCard() + 1)); + break; + } else { + recur = 0; + cout << endl; + while (hand1.getHighestCard(recur) == hand2.getHighestCard(recur) && + recur < hand1.cardsRemaining()) { + //cout << "Recur: " << recur << " : " << hand1.toFaceSymbol(hand1.getHighestCard(recur)+1) << endl; + ++recur; + } + if (hand1.getHighestCard(recur) > hand2.getHighestCard(recur)) { + cout << "1 wins with " << hand1.printEvaluation() << " and highest card " + << hand1.toFaceSymbol(static_cast(hand1.getHighestCard(recur) + 1)); + break; + } else if (hand1.getHighestCard(recur) < hand2.getHighestCard(recur)) { + cout << "2 wins with " << hand2.printEvaluation() << " and highest card " + << hand2.toFaceSymbol(static_cast(hand2.getHighestCard(recur) + 1)); + break; + } else cout << "Equal standing with " << hand2.printEvaluation() << endl; + break; + } + } + } +} diff --git a/sources/Poker.cpp b/sources/Poker.cpp new file mode 100644 index 0000000..5c39fb7 --- /dev/null +++ b/sources/Poker.cpp @@ -0,0 +1,5 @@ +#include "PokerGame.h" +int main() { + PokerGame game; + game.beginGame(); +} diff --git a/sources/PokerGame.cpp b/sources/PokerGame.cpp new file mode 100644 index 0000000..6e990be --- /dev/null +++ b/sources/PokerGame.cpp @@ -0,0 +1,424 @@ +#include "PokerGame.h" + +PokerGame::PokerGame() { + setNumOfPlayers(2); + gameType = 0; +} + +void PokerGame::splash() { + cout << "╔═══════════════ C++ ════════════════╗" << '\n'; + cout << "║ ╔════╗ ╔════╗ ╔═╗╔═╗ ╔════╗ ╔════╗ ║" << '\n'; + cout << "║ ║ ╔╗ ║ ║ ╔╗ ║ ║ ║║ ║ ║ ╔══╝ ║ ╔╗ ║ ║" << '\n'; + cout << "║ ║ ║║ ║ ║ ║║ ║ ║ ╚╝ ║ ║ ║ ║ ╚╝ ║ ║" << '\n'; + cout << "║ ║ ╚╝ ║ ║ ║║ ║ ║ ╔═╝ ║ ╚══╗ ║ ╔═╝ ║" << '\n'; + cout << "║ ║ ╔══╝ ║ ║║ ║ ║ ╚═╗ ║ ╔══╝ ║ ╚═╗ ║" << '\n'; + cout << "║ ║ ║ ║ ║║ ║ ║ ╔╗ ║ ║ ║ ║ ╔╗ ║ ║" << '\n'; + cout << "║ ║ ║ ║ ╚╝ ║ ║ ║║ ║ ║ ╚══╗ ║ ║║ ║ ║" << '\n'; + cout << "║ ╚═╝ ╚════╝ ╚═╝╚═╝ ╚════╝ ╚═╝╚═╝ ║" << '\n'; + cout << "╚════════════════════════════════════╝" << '\n'; + cout << '\n'; +} + +void PokerGame::clearScreen() { + for (int i = 0; i < 50; ++i) { + cout << '\n'; + } +} + +void PokerGame::pause() { + cout << "Press enter to continue...\n" << flush; + cin.ignore(20, cin.peek()); + cin.ignore(20, '\n'); +} + +void PokerGame::dash() { + cout << "===================================\n"; +} + +void PokerGame::discardFromHand(Hand &hand, int discard) { + if (discard < 1 || discard > 3) return; + vector index(hand.cardsRemaining(), false); + for (int i = 0; i < discard; ++i) { + int choice; + cout << "\nEnter " << (i == 0 ? "first" : i == 1 ? "second" : "third") << " card index to discard: "; + cin >> choice; + cout << "- Discarding " << hand.peekCard(choice - 1).toString() << '\n'; + index[choice - 1] = true; + } + + for (int i = sizeof(index) / sizeof(index[0]) - 1; i >= 0; i--) { + if (index[i]) { + deck.addCard(hand.getCard(i)); + hand.addCard(deck.drawCard()); + } + } + hand.sortByFace(); + cout << "\n\nNew hand: (" << hand.printEvaluation() << ")" << '\n'; + cout << hand.drawHand() << '\n'; + pause(); +} + +void PokerGame::beginGame() { + splash(); + gameInit(); + switch (gameType) { + case 1: classicGameLoop(); + break; + case 2: texasGameLoop(5); + break; + } +} + +void PokerGame::gameInit() { + deck.shuffle(); + unsigned short num; + unsigned short game; + cout << "\n1 - Classic Poker " << '\n'; + cout << "2 - Texas Hold'em " << '\n'; + cout << "Input game type: "; + cin >> game; + cout << "\nInput number of players: "; + cin >> num; + setNumOfPlayers(num); + setGameType(game); + string name; + cout << '\n'; + for (int i = 0; i < numOfPlayers; ++i) { + cout << "Enter name for player " << i + 1 << ": "; + cin >> name; + playerHands.emplace_back(deck.dealHand(gameType == 1 ? 5 : 2)); + playerHands[i].setOwnerName(name); + playerHands[i].sortByFace(); + credit.push_back(100); + } +} + +void PokerGame::classicGameLoop(int turns) { + string names[numOfPlayers]; + for (int i = 0; i < numOfPlayers; ++i) names[i] = playerHands[i].getOwnerName(); + for (int i = 0; i < turns; ++i) { + for (int j = 0; j < numOfPlayers; ++j) { + pause(); + clearScreen(); + cout << "============= ROUND " << i + 1 << " =============\n\n"; + int discard; + cout << playerHands[j].getOwnerName() << "'s hand: (" << playerHands[j].printEvaluation() << ")\n\n"; + cout << playerHands[j].drawHand(); + for (int k = 0; k < playerHands[j].cardsRemaining(); ++k) { + cout << "╚═ " << k + 1 << " ═╝"; + } + cout << '\n'; + cout << "\nInput number of cards to discard (up to three): "; + cin >> discard; + discardFromHand(playerHands[j], discard); + } + + vector hands(numOfPlayers, false); + for (int j = 0; j < numOfPlayers - 1; ++j) { + if (hands[j]) continue; + for (int k = j + 1; k < numOfPlayers; ++k) { + if (playerHands[j] > playerHands[k]) hands[k] = true; + else if (playerHands[j] < playerHands[k]) { + hands[j] = true; + break; + } + } + } + + int winnerCount = 0; + for (int j = 0; j < numOfPlayers; ++j) { + if (!hands[j]) winnerCount++; + } + + clearScreen(); + cout << "============= ROUND " << i + 1 << " =============\n\n"; + for (int j = 0; j < numOfPlayers; ++j) { + cout << playerHands[j].getOwnerName() << "'s hand: (" << playerHands[j].printEvaluation() << ")\n"; + cout << playerHands[j].drawHand(); + dash(); + cout << '\n'; + } + + dash(); + if (winnerCount == 1) { + for (int j = 0; j < numOfPlayers; ++j) + if (!hands[j]) + cout << playerHands[j].getOwnerName() << " wins with " << playerHands[j].printEvaluation() << "\n"; + } else { + cout << "Tie, split the pot.\n"; + } + dash(); + + deck.initDeck(); + deck.shuffle(); + playerHands.clear(); + + for (int j = 0; j < numOfPlayers; ++j) { + playerHands.emplace_back(deck.dealHand(5)); + playerHands[j].setOwnerName(names[j]); + playerHands[j].sortByFace(); + } + + cout << "Next: Round " << i + 2 << '\n'; + } +} + +void PokerGame::texasGameLoop(int turns) { + int pot, stage, dealer, ante, limit; + bool folded[numOfPlayers]; + int foldedCount, player, loop = 0; + Hand dealerHand(deck.dealHand(5)); + + while (true) { +//Init game data + stage = 31; + pot = 0; + foldedCount = 0; + deck.initDeck(); + deck.shuffle(); + for (int i = 0; i < numOfPlayers; ++i) { + playerHands[i].setHand(deck.dealHand(2)); + playerHands[i].sortByFace(); + folded[i] = false; + } + history.str("- Begin new game -\n"); + dealer = loop % numOfPlayers; + player = (dealer + 2) % numOfPlayers; + dealerHand.setHand(deck.dealHand(5)); + + for (int i = 0; i < numOfPlayers; ++i) { + if (credit[i] <= 0) { + folded[i] = true; + foldedCount++; + } + } + + if (foldedCount == numOfPlayers - 1) { + for (int i = 0; i < numOfPlayers; ++i) + if (credit[i] > 0) { + dash(); + cout << playerHands[i].getOwnerName() << " won the game. " << '\n'; + dash(); + pause(); + return; + } + } + + for (int turn = 0; turn < 4; ++turn) { +//Init round data + limit = numOfPlayers; + history << "\n- Begin round " << turn + 1 << " -" << '\n'; + ante = 0; + if (turn == 0) { + history << "Current dealer: " << playerHands[dealer].getOwnerName() << '\n'; + for (int i = 1; i < 3; ++i) { + pot += i; + credit.at((dealer + i) % numOfPlayers) -= i; + history << (i == 1 ? "Small (1$)" : "Big (2$)") << " blind from " + << playerHands.at((dealer + i) % numOfPlayers).getOwnerName() << '\n'; + } + ante = 2; + } + + +//Betting stage + if (turn != 3) { + for (int i = 0; i < limit; ++i) { + if (foldedCount == numOfPlayers - 1) break; + player = (player + 1) % numOfPlayers; + if (folded[player]) continue; +//Temporary evaluative hand + Hand check = playerHands[player]; + for (int j = 0; j < (turn == 0 ? 0 : turn == 1 ? 3 : (turn + 2)); ++j) + check.addCard(dealerHand.peekCard(j)); + check.sortByFace(); +//Print history + clearScreen(); + cout << "============= HISTORY =============\n"; + cout << history.str(); +//Print game data + cout << "\n============= ROUND " << turn + 1 << " =============\n\n"; + cout << ((player == dealer) ? "*DEALER* " : "") << "Player: " + << playerHands[player].getOwnerName() + << " (Credit: " << credit[player] << "$)\n\n"; + cout << "Pot: " << pot << "$\n"; + cout << "Ante: " << ante << "$.\n\n"; + cout << "Dealer hand:" << '\n'; + cout << dealerHand.drawHand(stage) << '\n'; + cout << "Waiting for player " << playerHands[player].getOwnerName() << '\n'; + pause(); + cout << "Hand (" << check.printEvaluation() << "):" << '\n'; + cout << playerHands[player].drawHand() << '\n'; +//Choose action + short action = 0; + while ((action < 1 && action != -1) || action > 3) { + cout << "1 - Fold 2 - " << (ante == 0 ? "Check" : "Call") << " 3 - Raise (-1 to quit)" + << '\n'; + cout << "Choose action: "; + cin >> action; + } +//Execute action + switch (action) { + case -1: clearScreen(); + cout << "Thank you for playing!" << '\n'; + return; + //Case Fold + case 1: folded[player] = true; + cout << "You folded." << '\n'; + history << playerHands[player].getOwnerName() << " folded." << '\n'; + foldedCount++; + break; + //Case Call/Check + case 2: + if (ante == 0) { + cout << "You checked." << '\n'; + history << playerHands[player].getOwnerName() << " checked." << '\n'; + } else { + if (ante > credit[player]) { + pot += credit[player]; + credit[player] -= credit[player]; + folded[player] = true; + foldedCount++; + cout << "You went all in with " << ante << "$." << '\n'; + history << playerHands[player].getOwnerName() << " went all in with " << ante + << "$." << '\n'; + } else { + pot += ante; + credit[player] -= ante; + cout << "You called with " << ante << "$." << '\n'; + history << playerHands[player].getOwnerName() << " called with " << ante << "$." + << '\n'; + } + } + break; + //Case Raise + case 3: int raise = 0; + while (raise <= 0) { + cout << "Choose amount to raise with: "; + cin >> raise; + } + if (raise >= credit[player]) { + raise = credit[player]; + folded[player] = true; + ++foldedCount; + } + limit = numOfPlayers; + i = 0; + ante = raise; + pot += raise; + credit[player] -= raise; + cout << "You raised ante to " << ante << "$." << '\n'; + history << playerHands[player].getOwnerName() << " raised ante to " << ante << "$." + << '\n'; + break; + } + + pause(); + } + +//Enter final round + } else { + vector evaluate; + vector loser(numOfPlayers, false); + int winnerCount = 0; + + for (int i = 0; i < numOfPlayers; ++i) { + evaluate.push_back(playerHands[i] + dealerHand); + evaluate[i].sortByFace(); + } + + for (int i = 0; i < numOfPlayers - 1; ++i) { + if (folded[i] && credit[i] > 0) loser[i] = true; + if (loser[i]) continue; + for (int j = i + 1; j < numOfPlayers; ++j) { + if (folded[j] && credit[j] > 0) { + loser[j] = true; + break; + } else if (evaluate[i] > evaluate[j]) { + loser[j] = true; + break; + } else if (evaluate[i] < evaluate[j]) { + loser[i] = true; + break; + } + } + } + + for (int i = 0; i < numOfPlayers; ++i) { + if (!loser[i]) + ++winnerCount; + } + + dealerHand.sortByFace(); + + clearScreen(); + cout << "=========== FINAL ROUND ===========\n\n"; + cout << "Dealer hand: " << '\n'; + cout << dealerHand.drawHand(); + dash(); + for (int i = 0; i < numOfPlayers; ++i) { + if (folded[i] && credit[i] > 0) continue; + cout << "Player " << playerHands[i].getOwnerName() << "'s hand (" + << evaluate[i].printEvaluation() << "):" << '\n'; + cout << playerHands[i].drawHand() << '\n'; + playerHands[i] = playerHands[i] + dealerHand; + playerHands[i].sortByFace(); + } + + if (winnerCount) { + for (int i = 0; i < numOfPlayers; ++i) { + if (!loser[i]) { + cout << "Player " << playerHands[i].getOwnerName() << " wins " << pot << "$ with " + << evaluate[i].printEvaluation() << "." << '\n'; + credit[i] += pot; + break; + } + } + } else { + cout << "Tie between players: " << '\n'; + for (int i = 0; i < numOfPlayers; ++i) { + if (!loser[i]) { + cout << playerHands[i].getOwnerName() << " with " << evaluate[i].printEvaluation() + << '\n'; + credit[i] += pot / winnerCount; + } + } + cout << "Each wins " << pot / winnerCount << "$." << '\n'; + } + } +//Shift dealer mask + if (turn == 0) + stage = stage << 3; + else + stage = stage << 1; + } + pause(); + ++loop; + } +} + +const vector& PokerGame::getPlayerHands() const { + return playerHands; +} + +void PokerGame::setPlayerHands(const vector& playerHands_) { + this->playerHands = playerHands_; +} + +unsigned short PokerGame::getGameType() const { + return gameType; +} + +void PokerGame::setGameType(unsigned short gameType_) { + (gameType_ > 0 && gameType_ < 3) ? this->gameType = gameType_ : this->gameType = 1; +} + +unsigned short PokerGame::getNumOfPlayers() const { + return numOfPlayers; +} + +void PokerGame::setNumOfPlayers(unsigned short numOfPlayers_) { + (numOfPlayers_ > 1 && numOfPlayers_ < 11) ? this->numOfPlayers = numOfPlayers_ : this->numOfPlayers = 2; +} + +PokerGame::~PokerGame() = default;