Thread: I need help with a Blackjack game.

1. I need help with a Blackjack game.

I'm writing a simple Blackjack game, but I'm having a problem. This is my code so far:

Code:
```#include <iostream>
#include <cmath>
#include <ctime>
#include <cstdlib>

using namespace std;
int drawCard();

int main()
{
int i;
for(i = 1; i < 53; i++){
cout<< "Card "<< i<< " is "<< drawCard()<< ".\n";
}
}

int drawCard() {
int deck[53];
int loop;
while(loop != 0) {
int deck[53] = {0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,8,9,9,9,9,10,10,10,10,11,11,11,11,12,12,12,12,13,13,13,13};
loop = 0;
}
int cardToDraw;
time_t now;//Sets now to equal the current time.
time(&now);
srand(now++);//Uses the current time as the seed for random numbers.
cardToDraw = 0;//Draws the 0 card. This is needed to start the loop.
while(deck[cardToDraw] == 0) {//If the chosen card is gone, it will choose a new one.
cardToDraw = (rand() % 52);//Generates a random number between 0 and 52. This will be the card that is drawn.
cout<< "A card was chosen.\n";//Debugging line.
}
cout<< "cardToDraw = "<< cardToDraw<< ".\n";//Debugging line.
cout<< now;//Debugging line.
return cardToDraw;
deck[cardToDraw] = 0;//Removes the drawn card from the deck.
}```
Forgive me if it's messy or full of problems; I'm pretty new to programming.
My problem is with the while(deck[cardToDraw] == 0) loop within the drawCard function (line 29). I can't get this loop to run for some reason, even though deck[cardToDraw] should equal 0. When I run the program, every drawn card is equal to 0. Does anyone know why this loop won't run? Also, if you notice any other errors, please let me know.

2. First, you need the code to remember the current state of the cards from one call to the next.
Also, artificially starting the array at subscript 1 tends to be more trouble than it's worth (it makes your next step wrong for starters).

This you do by declaring
Code:
`static int deck[5] = {1,1,1,1`

Also,
Code:
```    return cardToDraw;
deck[cardToDraw] = 0;//Removes the drawn card from the deck.```
Swap these over, the assignment never happens as it is after the return statement.

Also
Code:
```    time_t now;//Sets now to equal the current time.
time(&now);
srand(now++);//Uses the current time as the seed for random numbers.```
Do this exactly ONCE in main().
In a fast running program such as this, the effective value of now will be a constant.
So you're always going to get the same rand()'s out of it.

FWIW, consider the idea of a deck class, with methods called shuffle and draw.

3. Originally Posted by Salem
First, you need the code to remember the current state of the cards from one call to the next.
Also, artificially starting the array at subscript 1 tends to be more trouble than it's worth (it makes your next step wrong for starters).

This you do by declaring
Code:
`static int deck[5] = {1,1,1,1`
The last line is supposed to remove the drawn card from the deck (by setting its value to 0), so it should remember the current state AFAIK. Since the while loop that initiates the array sets loop to 0, it should only run the first time, right?

I had the array start at 0 because a value of 0 is needed to run the loop that chooses a card. If the array doesn't include a value of 0, deck[cardToDraw] will never equal 0, so it will never choose a new card.

Originally Posted by Salem
Also,
Code:
```    return cardToDraw;
deck[cardToDraw] = 0;//Removes the drawn card from the deck.```
Swap these over, the assignment never happens as it is after the return statement.
I just realized that return cardToDraw should actually be return deck[cardToDraw]. I want to return the value of the card, not the position in the array.

So, if I do this:

Code:
```  deck[cardToDraw] = 0;//Removes the drawn card from the deck.
return deck[cardToDraw];```
Won't it just return 0 every time, since the value of the card is set to 0 before it's returned?

Originally Posted by Salem
Also
Code:
```    time_t now;//Sets now to equal the current time.
time(&now);
srand(now++);//Uses the current time as the seed for random numbers.```
Do this exactly ONCE in main().
In a fast running program such as this, the effective value of now will be a constant.
So you're always going to get the same rand()'s out of it.
That's why I did srand(now++);. I was hoping that that would add one to the seed every time the function is called. Is that not how it works? To be honest, I'm not exactly sure what srand does. I've looked it up and read about it, but I still don't completely understand it.

Also, doesn't now need to be in the function, since that's where the random numbers are generated? If I put it in main() instead, I'm pretty sure it would just return an undeclared variable error.

Originally Posted by Salem
FWIW, consider the idea of a deck class, with methods called shuffle and draw.
I have no idea what any of that means. I'll look it up later, but I have a feeling it will be way over my head. I have experience with HTML classes, but I have a feeling they're not similar.

Edit: By the way, everything in main() is for debugging purposes ATM. It's not permanent.

4. Originally Posted by wipeout4wh
The last line is supposed to remove the drawn card from the deck (by setting its value to 0), so it should remember the current state AFAIK. Since the while loop that initiates the array sets loop to 0, it should only run the first time, right?
The last line will never get run, because it is after the return.

I had the array start at 0 because a value of 0 is needed to run the loop that chooses a card. If the array doesn't include a value of 0, deck[cardToDraw] will never equal 0, so it will never choose a new card.
Use a do-while loop to do this instead.

I just realized that return cardToDraw should actually be return deck[cardToDraw]. I want to return the value of the card, not the position in the array.

So, if I do this:

Code:
```  deck[cardToDraw] = 0;//Removes the drawn card from the deck.
return deck[cardToDraw];```
Won't it just return 0 every time, since the value of the card is set to 0 before it's returned?
Save it to a temporary variable, clear it from the array, and return the temporary.

That's why I did srand(now++);. I was hoping that that would add one to the seed every time the function is called. Is that not how it works? To be honest, I'm not exactly sure what srand does. I've looked it up and read about it, but I still don't completely understand it.

Also, doesn't now need to be in the function, since that's where the random numbers are generated? If I put it in main() instead, I'm pretty sure it would just return an undeclared variable error.
srand sets a global variable. rand() will use that variable to generate a random number, and increment it itself.

You need to call srand in main so that each time you run the game, the chain of random numbers starts at a different point.

5. Originally Posted by King Mir
The last line will never get run, because it is after the return.

Use a do-while loop to do this instead.

Save it to a temporary variable, clear it from the array, and return the temporary.

srand sets a global variable. rand() will use that variable to generate a random number, and increment it itself.

You need to call srand in main so that each time you run the game, the chain of random numbers starts at a different point.
Thanks. I have the do... while loop and the temporary variable done. The return is at the end, and it's at least choosing cards now. I put the time stuff and srand(now) in main(), but now it's generating ridiculously high values for the cards. Here's the output:

Code:
```A card was chosen.
cardToDraw = 11.
Card 1 is 4674324.
A card was chosen.
cardToDraw = 43.
Card 2 is 2009310510.
A card was chosen.
cardToDraw = 7.
Card 3 is 2009339772.
A card was chosen.
cardToDraw = 43.
Card 4 is 2009310510.
A card was chosen.
cardToDraw = 45.
Card 5 is 2358800.
A card was chosen.
cardToDraw = 4.
Card 6 is 2358680.
A card was chosen.
cardToDraw = 19.
Card 7 is 2009261398.
A card was chosen.
cardToDraw = 31.
Card 8 is 2358840.
A card was chosen.
cardToDraw = 4.
Card 9 is 2358680.
A card was chosen.
cardToDraw = 31.
Card 10 is 2358840.
A card was chosen.
cardToDraw = 1.
Card 11 is 2358624.
A card was chosen.
cardToDraw = 10.
Card 12 is 2009261348
A card was chosen.
cardToDraw = 11.
Card 13 is 5316432.
A card was chosen.
cardToDraw = 29.
Card 14 is 2358708.
A card was chosen.
cardToDraw = 11.
Card 15 is 5316432.
A card was chosen.
cardToDraw = 13.
Card 16 is 5316432.
A card was chosen.
cardToDraw = 31.
Card 17 is 2358840.
A card was chosen.
cardToDraw = 9.
Card 18 is 4000.
A card was chosen.
cardToDraw = 30.
Card 19 is 1.
A card was chosen.
cardToDraw = 50.
Card 20 is 2009463968
A card was chosen.
cardToDraw = 16.
Card 21 is 4000.
A card was chosen.
cardToDraw = 47.
Card 22 is 17.
A card was chosen.
cardToDraw = 20.
Card 23 is 5316432.
A card was chosen.
cardToDraw = 0.
Card 24 is 2009471864
A card was chosen.
cardToDraw = 30.
Card 25 is 1.
A card was chosen.
cardToDraw = 34.
Card 26 is -1.
A card was chosen.
cardToDraw = 15.
Card 27 is 2009269136
A card was chosen.
cardToDraw = 16.
Card 28 is 4000.
A card was chosen.
cardToDraw = 13.
Card 29 is 5316432.
A card was chosen.
cardToDraw = 47.
Card 30 is 17.
A card was chosen.
cardToDraw = 19.
Card 31 is 2009261398
A card was chosen.
cardToDraw = 41.
Card 32 is 4649038.
A card was chosen.
cardToDraw = 0.
Card 33 is 2009471864
A card was chosen.
cardToDraw = 39.
Card 34 is 1.
A card was chosen.
cardToDraw = 30.
Card 35 is 1.
A card was chosen.
cardToDraw = 36.
Card 36 is 2009339602
A card was chosen.
cardToDraw = 40.
Card 37 is 2.
A card was chosen.
cardToDraw = 39.
Card 38 is 1.
A card was chosen.
cardToDraw = 13.
Card 39 is 5316432.
A card was chosen.
cardToDraw = 21.
Card 40 is 2358748.
A card was chosen.
cardToDraw = 23.
Card 41 is 1.
A card was chosen.
cardToDraw = 34.
Card 42 is -1.
A card was chosen.
cardToDraw = 1.
Card 43 is 2358624.
A card was chosen.
cardToDraw = 25.
Card 44 is 2.
A card was chosen.
cardToDraw = 30.
Card 45 is 1.
A card was chosen.
cardToDraw = 33.
Card 46 is 2009146752
A card was chosen.
cardToDraw = 4.
Card 47 is 2358680.
A card was chosen.
cardToDraw = 0.
Card 48 is 2009471864
A card was chosen.
cardToDraw = 4.
Card 49 is 2358680.
A card was chosen.
cardToDraw = 38.
Card 50 is 4649036.
A card was chosen.
cardToDraw = 38.
Card 51 is 4649036.
A card was chosen.
cardToDraw = 8.
Card 52 is 2358765.```
And here's drawCard():

Code:
```int drawCard() {
int deck[52];
int cardToDraw;
int drawnCard;
int loop;
while (loop != 0) {
int deck[52] = {1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,8,9,9,9,9,10,10,10,10,11,11,11,11,12,12,12,12,13,13,13,13};
loop = 0;
}
do {
cardToDraw = (rand() % 52);//Generates a random number between 0 and 51. This will be the card that is drawn.
cout<< "A card was chosen.\n";//Debugging line.
} while (deck[cardToDraw] == 0);
cout<< "cardToDraw = "<< cardToDraw<< ".\n";//Debugging line.
drawnCard = deck[cardToDraw];
deck[cardToDraw] = 0;//Removes the drawn card from the deck.
return drawnCard;
}```
main() is the same as before, but with time_t now;, time(&now);, and srand(now); added.

Edit: it's also repeating cards... none of the cards are being set to 0 after they're drawn.

Edit: Also, am I using the right modulus for rand()? I want it to generate values from 0 - 51. It seems to be doing that so far, but I figured I would ask just to be sure.

6. You never initialize the value of your deck of cards to anything. (You do temporarily create a brand new array, also called deck, that isn't the same as the deck you started with, but that new deck is destroyed when the while loop stops, and the original uninitialized deck remains.) The normal thing to do, I think, would be to pass the deck back and forth from main to your draw function (this would also allow you to pass the deck to, say, a "shuffle" function as well).

7. Originally Posted by tabstop
You never initialize the value of your deck of cards to anything. (You do temporarily create a brand new array, also called deck, that isn't the same as the deck you started with, but that new deck is destroyed when the while loop stops, and the original uninitialized deck remains.) The normal thing to do, I think, would be to pass the deck back and forth from main to your draw function (this would also allow you to pass the deck to, say, a "shuffle" function as well).
Code:
```    while (loop != 0) {
deck[52] = {1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,8,9,9,9,9,10,10,10,10,11,11,11,11,12,12,12,12,13,13,13,13};
loop = 0;
}```
Would leaving the int out work?

Edit: Leaving int and [52] out works fine. It's still repeating numbers, though.

I don't know how to pass variables between functions yet, but wouldn't a shuffle function be kind of pointless since it's already choosing the cards in a random order?

8. No, leaving the int out would not work.

A shuffle function would not normally be pointless, since most players frown at you dealing cards out of the middle of the deck. Also, sometimes people play so many games that you run out of cards.

9. Leaving both int and [52] out works, leaving this:

Code:
```    while (loop != 0) {
deck = {1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,8,9,9,9,9,10,10,10,10,11,11,11,11,12,12,12,12,13,13,13,13};
loop = 0;
}```
I see your point about running out of cards, though... if this deck runs out of cards, it will get stuck in an infinite loop trying to draw a new card.

10. Define "works". It doesn't compile, unless you've changed a definition above it somewhere.

11. It compiles in Code::Blocks with one warning.

Code:
`C:\Documents and Settings\David\My Documents\Programming\Blackjack\main.cpp|28|warning: extended initializer lists only available with -std=c++0x or -std=gnu++0x|`
It even initiates the array.

Code:
```cardToDraw = 21.
Card 1 is 6.
cardToDraw = 43.
Card 2 is 11.
cardToDraw = 19.
Card 3 is 5.
cardToDraw = 40.
Card 4 is 11.
cardToDraw = 30.
Card 5 is 8.
cardToDraw = 1.
Card 6 is 1.
cardToDraw = 41.
Card 7 is 11.
cardToDraw = 11.
Card 8 is 3.
cardToDraw = 11.
Card 9 is 3.
cardToDraw = 30.
Card 10 is 8.
cardToDraw = 17.
Card 11 is 5.
cardToDraw = 33.
Card 12 is 9.
cardToDraw = 42.
Card 13 is 11.
cardToDraw = 2.
Card 14 is 1.
cardToDraw = 34.
Card 15 is 9.
cardToDraw = 16.
Card 16 is 5.
cardToDraw = 4.
Card 17 is 2.
cardToDraw = 13.
Card 18 is 4.
cardToDraw = 7.
Card 19 is 2.
cardToDraw = 24.
Card 20 is 7.
cardToDraw = 3.
Card 21 is 1.
cardToDraw = 7.
Card 22 is 2.
cardToDraw = 34.
Card 23 is 9.
cardToDraw = 4.
Card 24 is 2.
cardToDraw = 25.
Card 25 is 7.
cardToDraw = 22.
Card 26 is 6.
cardToDraw = 9.
Card 27 is 3.
cardToDraw = 24.
Card 28 is 7.
cardToDraw = 5.
Card 29 is 2.
cardToDraw = 43.
Card 30 is 11.
cardToDraw = 42.
Card 31 is 11.
cardToDraw = 26.
Card 32 is 7.
cardToDraw = 16.
Card 33 is 5.
cardToDraw = 11.
Card 34 is 3.
cardToDraw = 51.
Card 35 is 13.
cardToDraw = 48.
Card 36 is 13.
cardToDraw = 6.
Card 37 is 2.
cardToDraw = 37.
Card 38 is 10.
cardToDraw = 37.
Card 39 is 10.
cardToDraw = 34.
Card 40 is 9.
cardToDraw = 2.
Card 41 is 1.
cardToDraw = 37.
Card 42 is 10.
cardToDraw = 8.
Card 43 is 3.
cardToDraw = 12.
Card 44 is 4.
cardToDraw = 49.
Card 45 is 13.
cardToDraw = 50.
Card 46 is 13.
cardToDraw = 0.
Card 47 is 1.
cardToDraw = 23.
Card 48 is 6.
cardToDraw = 19.
Card 49 is 5.
cardToDraw = 11.
Card 50 is 3.
cardToDraw = 22.
Card 51 is 6.
cardToDraw = 44.
Card 52 is 12.```
My only problem now is getting it to set each card to 0 as it's drawn.

12. Then you have done something other than you posted. Even in Code::Blocks you get two errors (expected primary-expression before curlybrace, expected semicolon before curlybrace). It is never legal to assign to an actual array.

13. This is the full code:

Code:
```#include <iostream>
#include <cmath>
#include <ctime>
#include <cstdlib>

using namespace std;
int drawCard();

int main()
{
time_t now;//Sets now to equal the current time.
time(&now);
srand(now);//Uses the current time as the seed for random numbers.
int i;
for(i = 1; i < 53; i++){
cout<< "Card "<< i<< " is "<< drawCard()<< ".\n";
}
}

int drawCard() {

int deck[52];
int cardToDraw;
int drawnCard;
int loop;

while (loop != 0) {
deck = {1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,8,9,9,9,9,10,10,10,10,11,11,11,11,12,12,12,12,13,13,13,13};
loop = 0;
}
do {
cardToDraw = (rand() % 52);//Generates a random number between 0 and 51. This will be the card that is drawn.
} while (deck[cardToDraw] == 0);//If the card is already gone (equal to 0), a new one will be chosen.
cout<< "cardToDraw = "<< cardToDraw<< ".\n";//Debugging line.
drawnCard = deck[cardToDraw];
deck[cardToDraw] = 0;//Removes the drawn card from the deck.
return drawnCard;
}```
This compiles with one warning in Code::Blocks (for me), but repeats cards.

Originally Posted by tabstop
expected semicolon before curlybrace
Are you missing a semicolon?

14. Yeah that's not legal c++. I'm amazed that it compiles, since even c++0x should not allow assigning to an array.

Also, as salem said, deck needs to be static and initialised.
Code:
```static int deck[52] = {1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,
8,8,8,8,9,9,9,9,10,10,10,10,11,11,11,11,12,12,12,12,13,13,13,13};```
You don't need that while loop.

15. I didn't use that before because I didn't know what static was. I just looked it up and did it, and you're both right. It compiles without any warnings now, and it doesn't repeat any cards. Thanks for your help, everyone. Now I can get started on the actual game.

I don't really understand why the other way isn't legal, though. Doesn't this way assign to the array too, just in the same line as it's declared?