BlackJack Simplified ASAP

Pages: 12
Please create a simple BlackJack code. DUE IN 12 AM NYC TIME!! Hit and stand options, must use classes, objects, public, private members. Human player versus computer.

Here is what I have so far:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>

using namespace std;

//global arrays
string r[13] ={
       "Ace","Two","Three","Four",
       "Five", "Six","Seven","Eight",
       "Nine","Ten","Jack", "Queen", "King"
};

string s[4] = {"Spades","Hearts","Clubs","Diamonds"};






//classes
class Card{
private:
   int value;
   string rank;
   string suit;

public:
   //setter functions
   void set_rank(string r){rank = r;};
   void set_suit(string s){suit = s;};
   void set_value(int v){value = v;};
  
   // getter functions
   string get_rank(){ return rank; };
   string get_suit(){ return suit; };
   int get_value(){ return value; };

   void display(){
       cout << value << " - " <<rank << " of "<< suit << endl;
   }
}; //end of Card class


//prototype
void shuffle(vector <Card> &d);
Card dealfrom(vector <Card> &d);

int main(){
   srand(time(0));
   Card temp;
   vector <Card> deck(52);
   vector <Card> hand(0);
   int count;
   bool playagain = true;
   char again;

   // assigning rank and suit and value to each Card object in vector deck
   for (int i = 0; i < 52; i++) {
       if(i % 13 == 0)
           deck[i].set_value(11);
       else if (i % 13 >= 9)
           deck[i].set_value(10);
       else
           deck[i].set_value(i%13 + 1);
       deck[i].set_rank(r[i % 13]);
       deck[i].set_suit(s[i / 13]);
   }

   shuffle(deck);

  
   //begin Black Jack Game
   while(playagain){
      
  
      
       cout << "Do you want to play another hand? (y/n)";
       cin >> again;
       if(again != 'y')
           playagain = false;
   }
  
  
  
   /*/prints every card in the deck
   count = 0;
   for(Card c: hand){
       cout << ++count<< " ";
       c.display();
   }cout << endl;
   */
  shuffle(deck);


}// end of main()

//function definitions
void shuffle(vector <Card> &d){
   Card temp;
   for (int i=0; i < d.size(); i++){
       int r = rand() % d.size();
       temp = d[i];
       d[i] = d[r];
       d[r] = temp;
   }

}

Card dealfrom(vector <Card> &d){
   Card temp;
   temp = d[d.size()-1];
   d.pop_back();
   return temp;
}

Last edited on
ASAP?
A hint from project management: to end timely you have to begin timely. Every housewife knows that, when she has to serve lunch at 12 'o clock sharp. Yes, I know, you would have asked yesterday if you needed the result yesterday, but you need it today -- surprisingly, urgently -- so you asked today. It's as simple as that.
I'm not even sure how to play blackjack.

If you actually had more code written, and were having trouble with a particular part of the logic, I'm sure we could help you, but I doubt someone is going to code an entire game of blackjack for you by midnight...
@Ganado,

Blackjack Rules and Strategy
http://www.hitorstand.net/strategy.php
@MikeStgt
Instead of lecturing me about time management, how about helping me even a little? I don't need you to say all those things. I am aware that this last minute thing is my fault, thank you very much. Don't @ me unless you gonna help.
Last edited on
@Ganado
I don't need a full-working perfect BlackJack code. I just need one that runs with proper options given and a rough counter that works. Anything that makes this code longer. I saw another BJ code that was less than 300 lines.
if you are willing to play with infinite shoes / deckless the whole thing could be literally 25 lines or less.
get user bet value.
get 2 cards (random out of 13) for house, and 2 for user
add up total/score (handle aces)
let user hit/stand/whatever
loop ai until it wins or loses or force quit rules (hard 17 stop for example).
dole out winnings.


--that logic lets you eliminate shuffle and deal logic and deck management, which is half the code.
@YeetParadox
Sure, a hint about cooking housewifes is not of much help for BlackJack now. But maybe it will help you in future. I was astonished about the ASAP in the subject. I assume it is also for you night-time from Sunday to Monday. And if it's really a matter of the utmost urgency tonite -- another hint -- I would try "c++ blackjack" in bing or google or similar.
@MikeStgt
Please excuse my time management. I did ask my teacher for extra time, so I will be more clear about what I need help on. I will come back tomorrow. Also, I did try searching but it did not help a lot, which is why I posted on this forum. I can't resort to live help because they require payment.
Last edited on
I did try searching but it did not help a lot

Quite possible that first glance and a closer look differ. But if not a fits-perfectly-ready-to-use solution
https://codereview.stackexchange.com/questions/133489/c-blackjack-game/133516
http://www.cplusplus.com/forum/general/120525/
https://sourceforge.net/directory/os:windows/?q=c%2B%2B+blackjack
could give at least some ideas, or snippets to stitch together.

Ah -- and sorry -- just found you asked already on Friday -- http://www.cplusplus.com/forum/general/252222/#msg1110346
@YeetParadox

Alas, blackjack is not as simple as everyone thinks it is. You can probably get away with ignoring a lot of the corner cases, though; just hit or stand. You still need to check for blackjack or bust, and as long as you are playing the dealer should hit if his hand < 17.

Managing a shoe of 104 cards (two decks) is not hard, just throw away all the cards when you have less than about half left and re-randomize. Keep it simple:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
typedef int Card;

enum Suit { Clubs, Diamonds, Hearts, Spades };
enum Rank { Ace = 1, Jack = 11, Queen, King };

Suit suit( Card card ) { return card / 13; }
Rank rand( Card card ) { return card % 13 + 1; }

const char* Suits[] = { "Clubs", "Diamonds", "Hearts", "Spades" };
const char* Ranks[] = { "", "Ace", "One", "Two", …, "King" };

std::ostream& operator << ( std::ostream& outs, Card card )
{
  return Rans[rank( card )] << " of " << Suits[suit( card )];
}

After that, you’ll need the dealer’s shoe. Here is a two-deck shoe, replaced when the number of cards remaining drops below 52.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct Shoe: public std::vector <Card>
{
  void init()
  {
    clear(); // edit -- I forgot this
    for (Card n = 0; n < 52+52; n++) emplace_back( n % 52 );
    std::random_shuffle( begin(), end() );
  }
  
  Card deal()
  {
    if (size() < 52) init();
    Card result = back();
    pop_back();
    return result;
  }
};

You’ll probably also want to keep track of your player’s hands:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
struct Hand: public std::vector <Card>
{
  std::string& player_name;
  bool is_hide_first_card;

  Hand( const std::string& player_name ):
    player_name(player_name),
    is_hide_first_card(player_name == "Dealer")
    { }

  int value() const
  {
    // This is where you sum the values of the cards in your hand.
    // Remember: Aces are special. They can be valued either 1 or 11,
    // whichever gets you closer to 21 without going over. Be careful
    // to sum it right.
  }
};

std::ostream& operator << ( std::operator& outs, const Dealer_Hand& hand )
{
  outs << player_name << "\n";
  int n = 0;
  for (Card card : hand) 
    if (n++ or !is_hide_first_card) outs << card << "\n";
    else                            outs << "(hidden)\n";
  return outs << "\n";
}

Now you can play easily.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
int main()
{
  Shoe shoe;

  std::cout << "Welcome to BlackJack!\n";

  Hand dealer( "Dealer" );
  Hand player( "Player" );

  double player_bet;
  // ask player for his bet

  dealer.emplace_back( shoe.draw() );
  player.emplace_back( shoe.draw() );

  while (any player is not standing)
  {
    if (dealer is not standing) dealer.emplace_back( shoe.draw() );
    if (player is not standing) player.emplace_back( shoe.draw() );

    if ((first round) and (player.value() == 21))
    {
      player wins 1.5 * player_bet. game over.
    }
    if ((first round) and (player.value() > 21))
    {
      player busts! Owes player_bet. game over.
    }
    
    …

    // dealer hits or stands based on the 17 rule
    // ask player if he wishes to hit or stand
  }

  // All done. Compare hands. Declare the winner and how much the player won/owes.
}

You can easily extend this to any number of players; store the player Hands in a vector. While you are at it, you can also keep state information with the Hand, such as whether or not the player is standing.

You can also wrap the loop in main in another loop, and keep playing until the player(s) decide to quit. (“Play again ([Y]/N)?”)


BTW, your shuffle() function is broken. Either look up Knuth-Fisher-Yates or just use one of the ones in <algorithm>. Above I have used one that is deprecated, only because it relies on rand().

Hope this helps.
Last edited on
Alas, blackjack is not as simple as everyone thinks it is.

This, if you want to handle double/split/house rules variations (hard/soft 17 rules, whatever) and insurance and all that stuff. The core game... get the core game working (hit, stand, score). Then build what you can on top of it.
This, if you want to...

The subject is BlackJack Simplified, the OP stipulates:
Hit and stand options, must use classes, objects, public, private members. Human player versus computer.
So IMO the focus is not on BJ, the main task is "must use classes, objects, public, private members".

So I also could learn something about C++.
shoe.draw()
Suppose draw() calls deal() in some obscure path. Could you pls shed some light to it?
I get the [Error] invalid conversion from 'Card {aka int}' to 'Suit' [-fpermissive]
error when running dumthomhas' code and more.
Last edited on
invalid conversion from Card to Suit

Just guessing here, but try something like
1
2
3
4
5
6
7
8
9
10
11
12
13
14
typedef int Card;

enum Suit { Clubs, Diamonds, Hearts, Spades };

Suit suit( Card card ) {
    if (card / 13 == 0)
        return Clubs;
    else if (card / 13 == 1)
        return Diamonds;
    else if (card / 13 == 2)
        return Hearts;
    else
        return Spades;
}
Last edited on
I get the [Error] invalid conversion from ...

Try this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/* 17 und 4 */
#include <iostream>	    /* cout, cin, endl */
#include <bitset>
#include <ctime>        /* time */
using namespace std;

const unsigned decks=2;
unsigned value[]{10, 11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10};
string suit("dhsc");    // Diamonds, Hearts, Spades, Clubs
string avers("JA23456789TQK");  // you know it

//------------------------------------------------------------------------------
class Shoe
{
    bitset<decks * 52 - 1> cf;  // Card-Flags, 1 - in shoe, 0 - dealt out
  public:
    void shuffle()
    {
        cout << " new deck, shuffle... ";
        cf.set();
    }
    int fortuity;
    int deal(bool hidden)
    {
        do {fortuity = rand() % (decks * 52);} while (!cf[fortuity]);
        cf[fortuity] = false;
        if (hidden)
            cout << "NOSHOW, ";
        else
            cout << suit[fortuity / 13 % 4] << avers[fortuity % 13] << ", ";
        if (cf.count() < 52) shuffle();
        return value[fortuity % 13];    // return card's value
    }
};

////////////////////////////////////////////////////////////////////////////////
int main()
{
    Shoe cards;             // see above
    unsigned sum_D, sum_P, aoh_D, aoh_P;    // value and #aces in current hand
    unsigned curav, hc;                     // current avers, hidden card of D.
    char wuw;                               // What User Wants
    bool ail_D, ail_P;      // ace is low? (flag for "hard" and "soft")

/* prepare the table */
	srand (time(NULL));     // haphazardly seed
	cout << "Start\n";      // indicate c'est parti !
    cout << "To control enter first letter: Hit or Card to get one more card,\n";
    cout << "Stand or Rest for standing, Quit to leave.\n";
    cards.shuffle();
once_more:
    ail_D = false;      // value of aces now 11
    ail_P = false;
    aoh_D = 0;          // aces on hand
    aoh_P = 0;
    sum_D = 0;          // totalized values
    sum_P = 0;

/* deviation from _all_ usual dial sequence */
    cout << "\nDialer: ";
    sum_D = cards.deal(true);
    hc = cards.fortuity;            // remember hidden card for later
    if ((hc % 13) == 1)
        aoh_D = 1;
    sum_D += cards.deal(0);         // dealer upcard
    curav = cards.fortuity % 13;
    if ((hc % 13 + curav) == 1)     // 0=J, 1 = A
    {
        cout << " BLACKJACK! ";
        cout << " Dialer uncovers: " << suit[hc / 13 % 4] << avers[hc % 13];
        goto D_wins;
    }
    if (curav == 1)
        aoh_D += 1;
    if (sum_D == 22)    // two aces trigger soft -> hard
    {
        ail_D = true;
        sum_D = 2;
    }

/* one player only */
    cout << "\nYou: ";
    sum_P = cards.deal(0);
    curav = cards.fortuity % 13;
    if (curav == 1)
        aoh_P = 1;
    sum_P += cards.deal(0);
    if ((cards.fortuity % 13 + curav) == 1)
    {
        cout << " BLACKJACK!\n";
        goto P_wins;
    }
    if (cards.fortuity % 13 == 1)
        aoh_P += 1;
    if (aoh_P == 2)    // two aces trigger low
    {
        ail_P = true;
        sum_P = 2;
    }

/* loop until player stands or busted */
    for (;;)
    {
        cin >> wuw;
        cin.clear();
        cin.ignore(999, '\n');
        switch (wuw)
        {
            case 'Q':
            case 'q':
                return (0);     // Quit silently
            case 'R':
            case 'S':
            case 'r':
            case 's':
                goto rest;
            case 'C':
            case 'H':
            case 'c':
            case 'h':
            default:
                curav = cards.deal(0);
                if (cards.fortuity % 13 == 1)
                    aoh_P += 1;
        }
        if ((curav == 11) && ail_P)
            curav -= 10;
        sum_P += curav;
        if (sum_P > 21)
        {
            if (aoh_P > 0 && !ail_P)
            {
                ail_P = true;
                sum_P -= aoh_P * 10;
            }
            else
            {
                cout << " a bust! ";
                goto D_wins;
            }
        }
    }   // end do forever

/* continue with dialers turn */
rest:
/* Would be nice for Dialer hole card to repeate also his upcard */
    cout << "\nDialer hole card: " << suit[hc / 13 % 4] << avers[hc % 13] << ", ";
    while (sum_D < 17)
    {
        curav = cards.deal(0);
        if (cards.fortuity % 13 == 1)
            aoh_D += 1;
        if ((curav == 11) && ail_D)
            curav -= 10;
        sum_D += curav;
        if (sum_D > 21)
        {
            if (aoh_D > 0 && !ail_D)
            {
                ail_D = true;
                sum_D -= aoh_D * 10;
            }
            else
            {
                cout << " a bust! ";
                goto P_wins;
            }
        }
    }

/* the hand is over, now compare sums */
    if (sum_P > sum_D)
        goto P_wins;
D_wins:
    cout << " Dialer wins " << sum_D << '/' << sum_P << '.';
    goto again;
    
P_wins:
    cout << " Player wins " << sum_P << '/' << sum_D << '.';
again:
    cout << " Again? Y/n ";
    cin >> wuw;

    if (wuw != 'N' && wuw != 'n')
        goto once_more;
//  return 0;
}

Start
To control enter first letter: Hit or Card to get one more card,
Stand or Rest for standing, Quit to leave.
 new deck, shuffle... 
Dialer: NOSHOW, sT, 
You: cK, hJ, s

Dialer hole card: hT,  Dialer wins 20/20. Again? Y/n y

Dialer: NOSHOW, d7, 
You: c9, d7, s

Dialer hole card: c7, d2, c8,  a bust!  Player wins 16/24. Again? Y/n n
 
Exit code: 0 (normal program termination)

Work in progress as you see, but it compiles, it runs, and needs some shiny finish. (I would prefere that Enter without entry would also do. Also missing, unhide dialer's NO SHOW card.)

Edit: Ah, yes, BJ is also shown with ace + any value of 10. And, the way I shuffle the deck is not Richard Durstenfeld's variant of Fisher and Yates' method. For sure not ;)
Edit: typos and more
Edit: another day another darling... another town another Blackjack flavour? I modified the code here and there, BJ now only with ace and jack.
Last edited on
How about making players an object, so several may be easily added, joining the table via network..
When I change the avers word to rank, I discovered this error:
29 48 C:\Users\Bob\Documents\pg2.cpp [Error] reference to 'rank' is ambiguous
When I change the avers word to rank, I discovered this error:

Short answer: If it ain't broke don't fix it -- if you changed variable name avers to rank it is no longer my program, all errors you discover now are yours.
Long answer: Error messages indicate something the compiler can't handle. If you like to change something, not too much at once, so you may see reason-impact-relation. Next, error message could be cryptic, but if the compiler complains about something ambiguous just make it unambiguous.
BTW, I first had a look about restricted strings not usable as variable names, for nothing. Then I asked "the Internet" where to find something about 'C++ rank' -- strike -- http://www.cplusplus.com/reference/type_traits/rank/

One more word, I intentionally baptized that string avers (the opposite of reverse) as it is only a assemblage of single letter shortcuts of the card face (Jack-Ass-2..9-Ten-Queen-King), it is not a ranking order. I moved Jack to the left for simpler Blackjack identification (Jack+Ace), what seems to be wrong, every value of 10 and an Ace as the first two cards denote BJ. You see, there is still a lot to do for you. For example the default "Yes" when nothing entered.

For me as C++ novice it was fun (but needless) to define for the first time an objct in C++.
Pages: 12