Advertisement

poker game

Started by November 01, 2024 12:29 AM
169 comments, last by pbivens67 1 hour, 21 minutes ago

I am working with the above code

I dont know if it matters or not but in the book accelerated c++ there is a card project at the end of the book. the entire game works and gives full source code. the idea is its a final project a summery of everything you learned. in the book it builds up to it,. you could always check that source code and get some ideas of what to do and maybe even improve on it. the book is before c++11 so its very core c++ code. It does not use templates just basic c++ classes and basic enum i believe.

Advertisement

@komatsu Nice. I used to love the old Charles Petzold win32 stuff. Must have missed Koenig and Moo as I didn't remember their names. Today I find myself actually using a c++20 thing here and there and c++23 modules might be neat to try some day also.

Staying on topic, I had a play with more of this last night. I was hoping that the ranking concept would be the easy way to know a winner but there's a hick-up where straight and flush rank values won't fit in between three-of-a-kind and full-house as whole integers. I might consider changing rank to float to get every win type in ascending order. Still holding back a final solution with the outstanding checks for win so I don't ruin the experience for you. 🙂

#include <iostream>                                          // for std::cout
#include <vector>                                            //
#include <string>                                            //
#include <random>                                            // for default random engine
#include <chrono>                                            // for time
#include <io.h>                                              // for _setmode
#include <fcntl.h>                                           // for _O_U16TEXT and _O_TEXT
#define _ec(x) "\x1b["#x"m"                                  // console color manipulator


std::vector<int> deck_indices = 
{//     2,  3,  4,  5,  6,  7,  8,  9, 10,  J,  Q,  K,  A    // 1=>13 index draw ID mapping
 // A,  2,  3,  4,  5,  6,  7,  8,  9, 10,  J,  Q,  K        // 0=>12 modulo(13) value mapping
        1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13,   // club grouping
       14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,   // diamond grouping
       27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,   // spade grouping
       40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52    // heart grouping
};
unsigned deal_index = 0;                                     // used to walk through shuffled deck_indices
std::default_random_engine rng;                              // store an instance of the random engine

const char* PokerHandName[15] =                              // used to put a name to value
{
    "nothing", "",                // 0
    "one pair", "",               // 2
    "two pair", "",               // 4
    "three of a kind",            // 6
    "straight",                   // 7
                                  //    <--.
    "full house",                 // 8     |
    "flush", "", "",              // 9 ----' todo: redesign this 
    "four of a kind",             // 12
    "staight flush",              // 13
    "royal straight flush"        // 14
};

struct HandInfo
{
    int card_indices[5];                                      // actual card ID from the deck
    int highest_card_index;                                   // used on zero ranking
    int rank;                                                 // used for determining hand strength 
};
HandInfo player_hand = { 0 };                                 // player instance representing a hand
HandInfo dealer_hand = { 0 };                                 // dealer instance representing a hand



static void DealHands()                                       // initialize both hands
{
    for (int i = 0; i < 5; ++i)
    {
        player_hand.card_indices[i] = deck_indices[deal_index++]; 
        if (deal_index == 52) { deal_index = 0; std::shuffle(deck_indices.begin(), deck_indices.end(), rng); }
        dealer_hand.card_indices[i] = deck_indices[deal_index++];
        if (deal_index == 52) { deal_index = 0; std::shuffle(deck_indices.begin(), deck_indices.end(), rng); }
    }

    player_hand.highest_card_index = 0;
    player_hand.rank = 0;
    dealer_hand.highest_card_index = 0;
    dealer_hand.rank = 0;
}


/* WIP eval func */
static void RankHand(HandInfo& hand)                           // score the passed in hand
{
    //   solveable by comparison   |   determine by additional steps                    
    // ============================|=================================
    // nothing        =  0         |         (highest card)
    // one pair       =  2         |
    // two pair       =  4         |
    // three of kind  =  6         |
    //                             |         (straight)
    //                             |         (flush)                        
    // full house     =  8         |
    // four of a kind = 12         |
    //                             |         (straight flush)
    //                             |         (royal straight flush)

    hand.highest_card_index = 0;
    hand.rank = 0;

    // process wins solvable by comparison
    for (int i = 0; i < 5; i++)
    {   // indices are ordered assending. Actual value = (card_indices % 13) + 1
        if (hand.card_indices[i] > hand.highest_card_index) hand.highest_card_index = hand.card_indices[i];  //    <----------------.
                           // todo: fix this. wrong compare with card id instead of card value. suit would be a secondary check.  --'

        for (int j = 0; j < 5; j++)
            if (i != j && ((hand.card_indices[j] % 13) == (hand.card_indices[i] % 13)))
                hand.rank++;
    }
    
    // todo: straight
    // todo: flush
    // todo: straight flush
    // todo: royal straight flush
}


void PutCardLabel(HandInfo& hand, unsigned i)                         // per card draw method
{
    if (hand.card_indices[i] < 14) std::cout << _ec(34);
    if (hand.card_indices[i] > 13 && hand.card_indices[i] < 27) std::cout << _ec(31);
    if (hand.card_indices[i] > 26 && hand.card_indices[i] < 40) std::cout << _ec(34);
    if (hand.card_indices[i] > 39) std::cout << _ec(31);

    int val = hand.card_indices[i] % 13;
    if (val > 0 && val < 10) std::cout << (val+1);
    if (val == 0)  std::cout << "A";
    if (val == 10) std::cout << "J";
    if (val == 11) std::cout << "Q";
    if (val == 12) std::cout << "K";
    
    int ret;
    ret = _setmode(_fileno(stdout), _O_U16TEXT);
    if (hand.card_indices[i] < 14) std::wcout << L"\u2663" << _ec(37) << L" ";
    if (hand.card_indices[i] > 13 && hand.card_indices[i] < 27) std::wcout <<  L"\u2666" << _ec(37)<< L" ";
    if (hand.card_indices[i] > 26 && hand.card_indices[i] < 40) std::wcout << L"\u2660" << _ec(37) << L" ";
    if (hand.card_indices[i] > 39) std::wcout << L"\u2665" << _ec(37) << L" ";
    ret = _setmode(_fileno(stdout), _O_TEXT);
}


void DisplayHand(HandInfo& hand)                                       // draw entire hand and rank string                                                                       
{
    RankHand(hand);
    PutCardLabel(hand, 0);
    PutCardLabel(hand, 1);
    PutCardLabel(hand, 2);
    PutCardLabel(hand, 3);
    PutCardLabel(hand, 4);
    std::cout << "  rank: " << PokerHandName[hand.rank] << "\n";
}


int main()
{    
    // setup the deck by shuffling sequential deck array
    unsigned seed = (unsigned)std::chrono::system_clock::now().time_since_epoch().count();
    std::default_random_engine rng(seed);
    std::shuffle(deck_indices.begin(), deck_indices.end(), rng);
    // fill the global instances of hand information for both dealer and player
    DealHands();
    std::cout << "Dealer: "; DisplayHand(dealer_hand);
    std::cout << "Player: "; DisplayHand(player_hand);

    // start main loop
    char ch;
    int num;
    bool quit = false;
    while (!quit)
    {
        std::cout << "\n[" << _ec(33) << "d" << _ec(37) << "]raw card(s), [" 
                           << _ec(33) << "r" << _ec(37) << "]eload, ["
                           << _ec(33) << "q" << _ec(37) << "]uit ";
        std::cin >> ch;
        if (ch == 'r') {                                                               // reload --------------------------------
            system("cls");
            DealHands();
            std::cout << "Dealer: "; DisplayHand(dealer_hand); 
            std::cout << "Player: "; DisplayHand(player_hand);
        }
        
        if (ch == 'q') quit = true;                                                    // quit -----------------------------------
        
        if (ch == 'd') {                                                               // ask for card replacements --------------
            std::cout << "Number of Cards (" << _ec(33) << "1=>5" << _ec(37) << ") ";
            std::vector<int> card_ids;
            std::cin >> num;
            for (int i = 0; i < num; i++)
            {
                std::cout << "Which Card (" << _ec(33) << "0=>4" << _ec(37) << ") ";
                int which;
                std::cin >> which;
                card_ids.push_back(which);
            }
            // update with new cards, display and continue
            for (int id : card_ids)
            {
                player_hand.card_indices[id] = deck_indices[deal_index++];
                if (deal_index == 52) { deal_index = 0; std::shuffle(deck_indices.begin(), deck_indices.end(), rng); }
            }
            std::cout << "Player: "; DisplayHand(player_hand);           
        }
        
    }
    return 0;
}

Dev careful. Pixel on board.

Dev careful. Pixel on board.

thanks for the code but it is too much for me to digest at this time, I liked your code you posted above. I like to break things down into small manageable chunks before I put them into my code. thanks for all the help

I am working with a small code snippet, in the cout line of code the h_one and h_two variables are undefined, I am unsure of how to proceed. I get a compile time error. here is my code.

#include <iostream>

using namespace std;

class Hand
{
public:
    int handClass;
    int h_one;
    int h_two;
};

int CompareHands(Hand h1, Hand h2) {
    if (h1.handClass > h2.handClass) {
        return -1;
    }
    else if (h1.handClass < h2.handClass) {
        return 1;
    }
    else {
        return 0; 
    }
}

int main()
{
    Hand hand;
    hand.h_one = 1;
    hand.h_two = 2;
    
    cout << CompareHands(h_one,h_two);
    
    return 0;
}
Advertisement

Two things.

  • h_one and h_two are member variables of your Hand class. They don't exist without a class instance in main.
  • CompareHands wants a pair of type Hand as arguments, not int arguments.

Try to explain to yourself (or us) what each member variable of your Hand class is trying to represent.
Try to explain what you would do with the return value of the CompareHands function.
The member integer handClass of the Hand class is never initialized and is a garbage value when you use your compare function.
The way you're set up here, there is only one hand.

Dev careful. Pixel on board.

A variable is like a box with a type and a label.

The line “int h_one” says you have a box that contains integers, and the name of the box is “h_one”.

The lines “class Hand { … };” says you CAN HAVE boxes of type “Hand”. Inside it are 3 boxes named “handClass”, “h_one”, and “h_two”. Each of the inner boxes can store an integer.

Inside main(), you create a box “hand” of type “Hand”. Due to the “Hand” type you know that inside “hand” there are 3 boxes, “hand.handClass”, “hand.h_one”, and “hand.h_two”.

Next you do “hand.h_one = 1”. You grab the "hand" box, open it, open the “h_one” box inside, and you store the “1” inside the inner box.

Next you do “hand.h_two = 2”. You grab the "hand" box, open it, open the “h_two” box inside, and you store the “2” inside the inner box.

Then you call “CompareHands”. The line “int CompareHands(Hand h1, Hand h2)” says it needs two box of type “Hand”. You try to give it a “h_one” box and a “h_two” box.

The compiler doesn't look inside boxes, it only reads the labels at the outermost boxes that you created. Inside the main function, you only created a “hand” box (from the “Hand hand” line).

@pbivens67 I am glad that you are trying to use classes with data inside it. Keep it up!

@nubdevice pbivens67 has a long history of struggling with basic concepts in programming. Use of smartly chosen data structures and enums is good to demonstrate, but may need much more explanation.

@alberth Yes, I know. I'm familiar with the behavior of many here over the last ten(+) years and have lurked under a few different names. (same account)
It has been suggested that it's one of two things. As you say or a master troll. Jury is still out, and I'd like to be there for the reveal.
Someone one day will crack the code. I'm just keeping the kettle warm. Zero desire to teach, but have noticed we stick with a project for longer durations.
Possibly due to the patient human interactions. Improvements are slow but happily appear somewhat steady.
Agreed. ‘type’ is probably a better descriptive term. 11:11

@pbivens67 Alberth has advised that much more explanation may be needed to grasp some of the proposed concepts.
Is this something that you would want to talk about? I've observed abusive behavior in your threads which is why I'm still here.
We want you to be successful in your creations. Please, if you don't understand something, don't just skip over it. Together we can dissect it into smaller pieces.
My last code post has it's own set of design issues and needs work to make usable. No question about that. The comments reflect key areas.
For example, the deck representation is employing some ‘magic’ that is not obvious at first or second glance.
If you don't know what the modulo operator is, you wouldn't understand.
The rank counting loop may also not be intuitive.
This thread began with the shuffle code presented in http://gamedev.net/forums/topic/717507-blackjack/5466527/?page=2
Also, on the previous page of this thread, you wanted to print the card values, but “didn't know where to begin”
That has been the focus. Where to begin. That is all I've done. Given a couple of suggestions in code form.
If you do want to talk about it, that's fine. Otherwise, I'll assume you're “making great progress”.

Dev careful. Pixel on board.

well I have read and studied alberth's post and it is very to the point the only thing I dont understand is what is a label of the outermost box?

Advertisement