Thread: Poker game - Jumping into C++ practice problem

  1. #1
    Registered User
    Join Date
    Jul 2015
    Posts
    15

    Poker game - Jumping into C++ practice problem

    Hi,

    I'm learning C++ from the book of the creator of this website, Jumping into C++.

    Under chapter 8, randomizing your programs, I've stumbled upon the following practice problem:

    5. Write a program to play poker! You can provide 5 cards to the player, let that player choose new cards, and then determine how good the hand is. Think about whether this is easy to do. What problems might you have in terms of keeping track of cards that have been drawn already? Was this easier or harder than the slot machine?
    I used to play poker so I'm a little confused in what exactly is being asked here. Do I need to write a program that deals 5 random cards, gives the player the option to trash the current cards and deal 5 new cards and then evaluate whether there is a winner in these 5 cards, i.e. pair, straight etc...?

    The question before asked to create a minimalistic slot machine so I'm just wondering whether this question is cutting out some of the details of poker like dealing two cards to players etc... as well.

  2. #2
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    It sounds like he's asking for a video "draw poker" game. So you deal 5 cards, let the user exchange any of the cards for new ones (i.e., let him "draw" some cards), and then evaluate the hand for payout. This is perhaps more involved than a slot machine due to the evaluation part.

  3. #3
    Registered User
    Join Date
    Jul 2015
    Posts
    15
    Ahh, thanks for clarifying that.

  4. #4
    Registered User
    Join Date
    Jul 2015
    Posts
    15
    Back! As a novice I didn't really find this problem easy to solve, compared to the practice questions that came before. But then again, I can't help but think maybe I overcomplicated things unnecessarily. Still, I have a solution that works. Please free to critically evaluate my code and give me some tips. Remember, I was limited to the C++ taught so far by the book (and Google).

    Code:
    #include <iostream>
    #include <cstdlib>
    #include <ctime>
    #include <vector>
    #include <string>
    #include <sstream>
    
    using namespace std;
    
    string dealCard();
    bool checkDuplicate(string hand[], string aCard);
    void dealHand(string hand[]);
    void swapCards(string hand[]);
    void convertToInt(string hand[], int numHand[2][5]);
    string findWinner(string hand[]);
    
    int main()
    {
        // Generate new random numbers each time the program is run
        srand(time(NULL));
    
        // Creates an option menu
        int option = 0;
        bool stop = false;
    
        while(stop != true)
        {
            cout << "*********" << endl;
            cout << "POKER" << endl;
            cout << "*********" << endl << endl;
            cout << "1. Play" << endl;
            cout << "2. Exit" << endl << endl;
            cout << "Choose your option: ";
            cin >> option;
    
            if(option != 2) {
                // Deal 5 cards to the player
                string hand[5] = {"", "", "", "", ""};
                dealHand(hand);
                for(int i = 0; i < 5; i++)
                    cout << endl << (i + 1) << " - " << hand[i];
    
                // Give the player the option to swap their cards
                char yesOrNo;
                cout << endl << endl << "Do you want to change cards? (y/n): ";
                cin >> yesOrNo;
                if(yesOrNo == 'y') {
                    swapCards(hand);
                    cout << endl << "Your new cards are:" << endl;
                    for(int i = 0; i < 5; i++)
                        cout << (i + 1) << " - " << hand[i] << endl;
                    cout << endl;
                }
    
                // Find a winner in the hand
                cout << endl << findWinner(hand) << endl;
    
                // Pause program
                cin.ignore(256, '\n');
                cout << endl << "Hit return to continue...";
                cin.get();
                system("CLS");
            } else {
                stop = true;
            }
        }
    
        return 0;
    }
    
    // Returns a card from the deck
    string dealCard()
    {
        string card;
    
        int aSuit = (rand() % (4 - 1 + 1)) + 1;
        int aCard = (rand() % (13 - 1 + 1)) + 1;
    
        string face;
    
        switch(aSuit)
        {
            case 1: face = " of Hearts"; break;
            case 2: face = " of Spades"; break;
            case 3: face = " of Diamonds"; break;
            case 4: face = " of Clubs"; break;
        }
    
        string value;
    
        switch(aCard)
        {
            case 1: value = "Ace"; break;
            case 2: value = "2"; break;
            case 3: value = "3"; break;
            case 4: value = "4"; break;
            case 5: value = "5"; break;
            case 6: value = "6"; break;
            case 7: value = "7"; break;
            case 8: value = "8"; break;
            case 9: value = "9"; break;
            case 10: value = "10"; break;
            case 11: value = "Jack"; break;
            case 12: value = "Queen"; break;
            case 13: value = "King"; break;
        }
    
        card = (value + face);
    
        return card;
    }
    
    // Returns true when a given cards already exists within the hand
    bool checkDuplicate(string hand[], string aCard)
    {
        bool duplicate = false;
    
        for(int i = 0; i < 5; i++) {
            if(hand[i] == aCard)
                duplicate = true;
        }
    
        return duplicate;
    }
    
    // Deals five random cards to player
    void dealHand(string hand[])
    {
        for(int i = 0; i < 5; i++) {
            string j = dealCard();
            if(checkDuplicate(hand, j) == true)
                i--;
            else
                hand[i] = j;
        }
    }
    
    // Allows player to swap cards within their hand
    void swapCards(string hand[])
    {
        char yesOrNo;
    
        for(int i = 0; i < 5; i++) {
            cout << "Change card " << (i + 1) << "? (y/n): ";
            cin.ignore(256, '\n');
            cin >> yesOrNo;
    
            if(yesOrNo == 'y') {
                string j;
                do {
                    j = dealCard();
                } while(checkDuplicate(hand, j) == true);
                hand[i] = j;
            } else {
                continue;
            }
        }
    }
    
    // Translates hand into an integer array
    void convertToInt(string hand[], int numHand[2][5])
    {
        stringstream stream;
    
        for(int i = 0; i < 5; i++) {
            if(hand[i].substr(0, 2) == "10") {
                numHand[0][i] = 10;
            } else if(hand[i].substr(0, 1) == "A") {
                numHand[0][i] = 1;
            } else if(hand[i].substr(0, 1) == "J") {
                numHand[0][i] = 11;
            } else if(hand[i].substr(0, 1) == "Q") {
                numHand[0][i] = 12;
            } else if(hand[i].substr(0, 1) == "K") {
                numHand[0][i] = 13;
            } else {
                stream << hand[i].substr(0, 1);
                stream >> numHand[0][i];
                stream.str("");
                stream.clear();
            }
        }
    
        enum {HEARTS, SPADES, DIAMONDS, CLUBS};
    
        for(int i = 0; i < 5; i++) {
            if(hand[i].find("Hearts") != -1) {
                numHand[1][i] = HEARTS;
            } else if(hand[i].find("Spades") != -1) {
                numHand[1][i] = SPADES;
            } else if(hand[i].find("Diamonds") != -1) {
                numHand[1][i] = DIAMONDS;
            } else {
                numHand[1][i] = CLUBS;
            }
        }
    }
    
    // Evaluate whether there is a winner in the hand
    string findWinner(string hand[])
    {
        string result = "Sorry, better luck next time!";
    
        bool straightFlush = false;
        bool fourOfAKind = false;
        bool fullHouse = false;
        bool flush = false;
        bool straight = false;
        bool threeOfAKind = false;
        bool twoPair = false;
        bool onePair = false;
    
        enum {
            PAIR = 1,
            TWO_PAIR,
            THREE_OF_A_KIND,
            FULL_HOUSE,
            FOUR_OF_A_KIND = 6
        };
    
        int cards[2][5];
        convertToInt(hand, cards);
    
        // Looks for a pair, two pair, three of a kind,
        // full house and four of a kind.
        vector<int> winners(0);
        for(int i = 0; i < 4; i++) {
            for(int j = i; j < 4; j++) {
                if(cards[0][i] == cards[0][j + 1])
                    winners.push_back(cards[0][i]);
            }
        }
        if(winners.size() == FOUR_OF_A_KIND)
            fourOfAKind = true;
        else if(winners.size() == FULL_HOUSE)
            fullHouse = true;
        else if(winners.size() == THREE_OF_A_KIND)
            threeOfAKind = true;
        else if(winners.size() == TWO_PAIR)
            twoPair = true;
        else if(winners.size() == PAIR)
            onePair = true;
    
        // Looks for a straight
        vector<int> orderCards(0);
        for(int i = 0; i < 5; i++)
            orderCards.push_back(cards[0][i]);
        // Bubble sort algorithm
        bool swapped = true;
        int j = 0;
        int tmp;
        while(swapped) {
            swapped = false;
            j++;
            for(int i = 0; i < (orderCards.size() - j); i++) {
                if(orderCards[i] > orderCards[i + 1]) {
                    tmp = orderCards[i];
                    orderCards[i] = orderCards[i + 1];
                    orderCards[i + 1] = tmp;
                    swapped = true;
                }
            }
        }
        int checkStraight = orderCards.back();
        while(checkStraight != orderCards.front()) {
            checkStraight--;
        }
        if(checkStraight == (orderCards.back() - (orderCards.size() - 1))) {
            straight = true;
        } else if((orderCards[0] == 1) &&
                (orderCards[1] == 10) &&
                (orderCards[2] == 11) &&
                (orderCards[3] == 12) &&
                (orderCards[4] == 13)) {
                    straight = true;
        }
    
        // Looks for a flush
        for(int i = 0; i < 4; i++) {
            if(cards[1][i] == cards[1][i + 1]) {
                flush = true;
            } else {
                flush = false;
                break;
            }
        }
    
        // Looks for a straight flush
        if((straight == true) && (flush == true))
            straightFlush = true;
    
        if(straightFlush == true)
            result = "You have a Straight Flush!";
        else if(fourOfAKind == true)
            result = "You have a Four Of A Kind!";
        else if(fullHouse == true)
            result = "You have a Full House!";
        else if(flush == true)
            result = "You have a Flush!";
        else if(straight == true)
            result = "You have a Straight!";
        else if(threeOfAKind == true)
            result = "You have a Three Of A Kind!";
        else if(twoPair == true)
            result = "You have a Two Pair!";
        else if(onePair == true)
            result = "You have a Pair!";
    
        return result;
    }

  5. #5
    Guest
    Guest

    Thumbs up

    Your coding style is really good already. A few cosmetic hints:

    Line 20: Use nullptr in place of NULL; NULL is dead.
    Line 26: while(!stop) suffices and reads clearer ("don't stop") imo
    Line 38: You don't need to initialize the string array.
    Line 68: return 0; in main is implicit in C++. Consider returning explicitly only when something other than 0 is wanted.
    Line 76-77: Consider making local variables const if they don't change after their declaration.
    Line 131: like Line 26, == true is the same as the expression itself. If you rename your function, e.g. to isDuplicate or whatever makes sense, then if(isDuplicate(hand, j)) is very readable.
    Line 184: unchanging enum can be const or even constexpr
    Line 213: same^
    Line 226: An empty vector can be constructed like: vector<type> name; No (0) needed; Applies to all instances in your code.
    Line 289-306: See Line 131

    Passing around raw arrays like hand is usually not recommended. Once your book covers them, consider using std::array or std::vector for these purposes.

  6. #6
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Your program seems to work pretty well. Good job. Remember to test it by setting up hands like a full house, flush, etc, that don't come up too often randomly.

    The main simplification I would make is to retain the cards as integers at all times and translate those ints to strings only on output.

    In fact, it's possible to represent a card by a single integer between 0 and 51, incl.
    Code:
    void print_card(int n) {
        const char *suits[] = {"Clubs", "Hearts", "Diamonds", "Spades"};
        const char *values[] = {"Two", ... , "King", "Ace"};
        cout << values[n % 13] << " of " << suits[n / 13];
    }
    Note that for the values I've mapped 0 to Two, 1 to Three, ..., 12 to Ace.

    The number of pairs, trips, four of a kind, and maximum cards in a row can be determined like this (assuming the card numbering scheme described above) :
    Code:
    int valCnts[13] = {0}, suitCnts[4] = {0};
    for (int i = 0; i < 5; ++i) {
        ++valCnts[cards[i] % 13];
        ++suitCnts[cards[i] / 13];
    }
    
    int nPairs=0, nTrips=0, nFours=0, inARow=0, maxInARow=0;
    for (int i = 0; i < 13; ++i) {
        switch (valCnts[i]) {
            case 0: if (inARow > maxInARow) maxInARow = inARow;
                    inARow = 0;
                    break;
            case 1: ++inARow;           break;
            case 2: ++inARow; ++nPairs; break;
            case 3: ++inARow; ++nTrips; break;
            case 4: ++inARow; ++nFours; break;
        }
    }
    
    int maxSameSuit=0;
    for (int i = 0; i < 4; ++i)
        if (suitCnts[i] > maxSameSuit)
            maxSameSuit = suitCnts[i];
    Another little point. In dealHand, instead of decrementing i when a duplicate is found in order to counteract the increment in the for's update clause, just leave the update clause empty and increment i when appropriate.
    Code:
    void dealHand(string hand[]) {
        for(int i = 0; i < 5; ) {
            string j = dealCard();
            if (!isDuplicate(hand, j))
                hand[i++] = j;
        }
    }
    Of course, I suggest you do this with integers instead of strings.

  7. #7
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Consider generating random numbers as shown here.
    std::rand is deprecated.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  8. #8
    Registered User
    Join Date
    Jul 2015
    Posts
    15
    Thank you all for sharing your knowledge.

    I'm going to amend my program with your recommendations.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Question on "Jumping into C++" Chapter 13 practice problem 1
    By Ben Sturm in forum C++ Programming
    Replies: 9
    Last Post: 04-01-2015, 01:16 PM
  2. Linked Lists Chapter 15 Practice Problem 1 Jumping Into C++
    By ArtemisFowl2nd in forum C++ Programming
    Replies: 34
    Last Post: 04-30-2014, 12:59 PM
  3. Jumping Into C++ Chapter 14 Practice Problem 1
    By ArtemisFowl2nd in forum C++ Programming
    Replies: 5
    Last Post: 04-16-2014, 09:36 PM
  4. Replies: 2
    Last Post: 02-24-2014, 05:51 PM
  5. "Jumping into C++" Chapter 5 Practice Problem
    By Grae in forum C++ Programming
    Replies: 4
    Last Post: 09-04-2013, 01:46 PM

Tags for this Thread