Reputation: 6515
I'm trying to make a simple blackjack program. Sadly, I'm having problems right off the bat with generating a deck of cards.
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<char> deck;
char suit[] = {'h','d','c','s'};
char card[] = {'2','3','4','5','6','7','8','9','10','J','Q','K','A'};
for (int j=0; j<13; j++) {
for (int i=0; i<4; i++) {
deck.push_back(card[j] suit[i]);
}
}
return 0;
}
I know my problem begins with me trying to assign the value '10' to a char. Obviously I couldn't get this to compile but I'm sure when I try to assign the card values to the vector deck I'll also get an error since I used variable type 'char'. Knowing what kind of variable type to use seems to be killing me. Also, would 'deck.push_back(card[j] suit[i]);' be the correct code to combine the card and suit, or do you have to put something between card[j] and suit[i]? I'd appreciate it if any of you could lead me in the right direction. Also as a little side note, this is part of a homework assignment so please don't just give me entire blocks of code. Thanks for your help.
Upvotes: 9
Views: 27976
Reputation: 924
When I created my C++ Deck of cards class, I ran into a few problems of my own. First off I was trying to convert my PHP deck of cards class to C++, with minimal luck. I decided to sit down and just put it on paper. I decided to go with an Object Oriented setup, mostly because I feel it's the easiest to use for expansion. I use the objects Card and Deck, so, for instance, if you want to put 10 decks into the Shoe of your blackjack game, you could create 10 decks, which would be simple enough, because I decided to make everything self contained. In fact, it's so self contained, to create your shoe the code would be:
#include "AnubisCards.cpp"
int main() {
Deck *shoe = new Deck(10);
}
But, that was for simplicity, not exactly necessary in smaller games where you only need a single deck.
ANYWAY, How I generated the deck was by creating an array of 52 Card objects. Decks are easy enough, because you know that you have 4 Suits and 13 Cards in each suit, you also know that you have 2,3,4,5,6,7,8,9,10,Jack,Queen,King,Ace in every single suit. Those will never change. So I used two loops, one for the Suit and the other for the Value.
It was something like this:
for(int suit = 1; suit <= 4; suit++){
for(int card = 1; card <= 13; card++){
// Add card to array
}
}
Now, you'll notice in every single one of those loops, I use an integer value. The reason is simple, cards are numbers. 4 suits. 13 values. Even the numerical value in the game of Blackjack. Face value, until you hit Face cards, which are numerical value 10 until you hit Ace which is numerical value 1 or 11. Everything is numbers. So you can use those numbers to not only assign the value of the card, but the suit of the card, and the number in the numerical sequence.
One idea would be to store a map in the Card class, with the char or String names of the cards, with 1,2,3... being the indexes for each.
Upvotes: 1
Reputation: 45321
Since this is homework for C++ I am going to guess you are expected to use classes. Otherwise use the enums, and if this were C use a struct or something.
And for some games, apart from points value, you'd want to store some kind of rank for the card, which would depend on the current mode of play.
I haven't done plain C in forever, but I mean something like this:
typedef struct struct_card {
unsigned short int suit:2;
unsigned short int card:4;
// unsigned short int valu:4;
} card;
int main() {
card a_card;
card std_deck[52];
const unsigned short int rummy_value[13] = {1,2,3,4,5,6,7,8,9,10,10,10,10};
const char *std_card_name[13] = {"Ace","Two","Three","Four","Five","Six",
"Seven","Eight","Nine","Ten","Jack","Queen","King"};
const char *std_suit_name[4] = {"Spades","Clubs","Hearts","Diamonds"};
int j, k, i=0;
for(j=0; j<4; j++){
for(k=0; k<13; k++){
a_card.suit=j; a_card.card=k;
std_deck[i++] = a_card;
}
}
//check our work
printf("In a game of rummy:\n");
for(i=0;i<52;i++){
printf(" %-5s of %-8s is worth %2d points.\n",
std_card_name[std_deck[i].card],
std_suit_name[std_deck[i].suit],
rummy_value[std_deck[i].card]);
}
//a different kind of game.
enum round_mode {SHEILD_TRUMP, FLOWER_TRUMP, BELL_TRUMP, ACORN_TRUMP, BOCK, GEISS} mode;
const card jass_deck[36]={
{0,0},{0,1},{0,2},{0,3},{0,4},{0,5},{0,6},{0,7},{0,8},
{1,1},{1,1},{1,2},{1,3},{1,4},{1,5},{1,6},{1,7},{1,8},
{2,2},{2,1},{2,2},{2,3},{2,4},{2,5},{2,6},{2,7},{2,8},
{3,3},{3,1},{3,2},{3,3},{3,4},{3,5},{3,6},{3,7},{3,8},
};
#define JASS_V {11,0,0,0,0,10,2,3,4}
const unsigned short int jass_value[9] = JASS_V;
#define JASS_TRUMP_V {11,0,0,0,14,10,20,3,4}
const unsigned short int jass_trump_value[9] = JASS_TRUMP_V;
#define JASS_BOCK_V {11,0,0,8,0,10,2,3,4}
const unsigned short int jass_bock_value[9] = JASS_BOCK_V;
#define JASS_GEISS_V {0,11,0,8,0,10,2,3,4}
const unsigned short int jass_geiss_value[9] = JASS_GEISS_V;
const char *jass_card_name[9] = {"Ace","Six","Seven","Eight","Nine","Banner",
"Under","Ober","King"};
const char *jass_suit_name[4] = {"Sheilds","Flowers","Bells","Acorns"};
const unsigned short int jass_all_value[6][4][9] = {
{ JASS_TRUMP_V, JASS_V, JASS_V, JASS_V },
{ JASS_V, JASS_TRUMP_V, JASS_V, JASS_V },
{ JASS_V, JASS_V, JASS_TRUMP_V, JASS_V },
{ JASS_V, JASS_V, JASS_V, JASS_TRUMP_V },
{ JASS_BOCK_V, JASS_BOCK_V, JASS_BOCK_V, JASS_BOCK_V },
{ JASS_GEISS_V, JASS_GEISS_V, JASS_GEISS_V, JASS_GEISS_V }
};
//check our work 2: work goes on summer vacation
printf("In a game of jass with trump (Sheilds | Flowers | Bells | Acorns) | Bock | Geiss\n");
for(i=0;i<36;i++){
printf(" %-6s of %-7s is worth %8d%10d%8d%9d%8d%8d\n",
jass_card_name[jass_deck[i].card],
jass_suit_name[jass_deck[i].suit],
jass_all_value[SHEILD_TRUMP][jass_deck[i].suit][jass_deck[i].card],
jass_all_value[FLOWER_TRUMP][jass_deck[i].suit][jass_deck[i].card],
jass_all_value[BELL_TRUMP][jass_deck[i].suit][jass_deck[i].card],
jass_all_value[ACORN_TRUMP][jass_deck[i].suit][jass_deck[i].card],
jass_all_value[BOCK][jass_deck[i].suit][jass_deck[i].card],
jass_all_value[GEISS][jass_deck[i].suit][jass_deck[i].card]);
}
return 0;
}
Output looks like:
In a game of rummy:
Ace of Spades is worth 1 points.
Two of Spades is worth 2 points.
Three of Spades is worth 3 points.
Four of Spades is worth 4 points.
Five of Spades is worth 5 points.
...
Nine of Diamonds is worth 9 points.
Ten of Diamonds is worth 10 points.
Jack of Diamonds is worth 10 points.
Queen of Diamonds is worth 10 points.
King of Diamonds is worth 10 points.
In a game of jass with trump (Sheilds | Flowers | Bells | Acorns) | Bock | Geiss
Ace of Sheilds is worth 11 11 11 11 11 0
Six of Sheilds is worth 0 0 0 0 0 11
Seven of Sheilds is worth 0 0 0 0 0 0
Eight of Sheilds is worth 0 0 0 0 8 8
Nine of Sheilds is worth 14 0 0 0 0 0
Banner of Sheilds is worth 10 10 10 10 10 10
...
Under of Acorns is worth 2 2 2 20 2 2
Ober of Acorns is worth 3 3 3 3 3 3
King of Acorns is worth 4 4 4 4 4 4
Blackjack is boring. This code does compile.
Upvotes: 0
Reputation:
This might not compile, but here is the approach I would (and have used). You're going to want to use ints to represent your cards, but you can easily abstract this in a class. Which I'll write for you.
class Card
{
public:
enum ESuit
{
kSuit_Heart,
kSuit_Club,
kSuit_Diamond,
kSuit_Spade,
kSuit_Count
};
enum ERank
{
kRank_Ace,
kRank_Two,
kRank_Three,
kRank_Four,
kRank_Five,
kRank_Six,
kRank_Seven,
kRank_Eight,
kRank_Nine,
kRank_Ten,
kRank_Jack,
kRank_Queen,
kRank_King,
kRank_Count
};
static int const skNumCards = kSuit_Count * kRank_Count;
Card( int cardIndex )
: mSuit( static_cast<ESuit>( cardIndex / kRank_Count ) )
, mRank( static_cast<ERank>( cardIndex % kRank_Count ) )
{}
ESuit GetSuit() const { return mSuit );
ERank GetRank() const { return mRank );
private:
ESuit mSuit;
ERank mRank;
}
Now its very simple to add to this class to get everything you want out of it. To generate the list its as simple as below.
rstl::vector<Card> mCards;
mCards.reserve( Card::skNumCards );
for ( int cardValue = 0; cardValue < Card::skNumCards; ++cardValue )
{
mCards.push_back( Card( cardValue ) );
}
Do you need to shuffle?
#include <algorithm>
std::random_shuffle( mCards.begin(), mCards.end() );
How about see what the value of the first card is?
if ( mCards[0].GetSuit() == Card::kRank_Club && mCards[0].GetRank() == Card::kRank_Ace )
{
std::cout << "ACE OF CLUBS!" << std::endl;
}
I didn't compile any of this, but it should be close.
Upvotes: 2
Reputation: 16735
The way you model it really depends on what you're trying to do.
Are you creating an actual game, and the data structures just need to support the gameplay?
If so, I'd create a card class, with an enum field for the suit and a numeric type (with values 1 - 13) for the face value.
On the other hand, if you're building an analysis application or an AI player, then the model might be a little bit different.
A few years ago, I wrote a simulator to calculate probabilities in various Texas Holdem scenarios, and I wanted it to crunch numbers REALLY quickly. I started out with a very straightforward model (card class, suit enum, etc) but after a lot of profiling and optimization, I ended up with a bitwise representation.
Each card was a sixteen-bit value, with the thirteen high-order bits representing the face value, the two low order bits representing the suit, and with bit[2] as a special flag indicating an ace (used only in cases where the ace might appear in an A2345 straight).
Here are a few examples:
0000000000001001 <---- Two of hearts
0100000000000011 <---- King of spades
1000000000000110 <---- Ace of diamonds
^^^^^^^^^^^^^ ("face-value" bits)
^ ("low-ace" flag)
^^ ("suit" bits)
You can imagine how, with a design like this, it's lighting fast to look for pairs, threes-of-a-kind, and straights (flushes are slightly more tricky).
I won't go into all the particular operations, but suffice it to say that this kind of model supports millions of operations per second...
Of course, keep in mind, I'm not actually advocating that you use a design like this in a straightforward game implementation. The only reason I ended up with this design is because I needed to conduct massive statistical simulations.
So think carefully about how you want to model:
The overall application model, and the goals of the application in general, will determine to a large extent the types of data structures that'll be most appropriate.
Have fun!!!
Upvotes: 11
Reputation: 103495
Well, first of all, deck[0] is one char, yet you are trying, to stuff "2h" into it. (for the moment, we'll ignore that how you are doing that is wrong.)
Basically, you'll need to make deck a vector<std::string>
. Make card an array of const char*s, and convert the elements to string.
then use:
deck.push_back(std::string(card[j]) + suit[i]);
Upvotes: 3
Reputation: 4368
As mentioned by others, you can use 'T' for ten, J, Q, and K for the figures. As far as push_back.. since deck is a vector of chars, you can pass only one char to push_back as argument. Passing both the card value (1...9, T, J, Q, K) and its suite doesn't work.
I personally would create a little struct, to represent a Card, with a Value and a Suite property. Then, you can make your deck a vector of Cards .
Edited: fixing last word since vector (less-than) Card (greater-than) was rendered as vector (nothing).
Upvotes: 2
Reputation: 6424
I would go with Ross's suggestion to use integers. Most card games will involve some bits of math so that's a better representation.
Convert to 'A' or 'ACE' etc. on output.
Upvotes: 0
Reputation: 269
Since this is a blackjack program, you will be adding and comparing the value of the cards.
That being the case, you can save yourself some additional programming and pain by giving the cards int values (1-13) instead of char values.
Upvotes: 1
Reputation: 20676
Try to create class of Card with suit and card as a member and set it as a type of vector. Like
public class Card {
public:
Card(char suit, char card);
char suit, card;
};
int main() {
vector<Card> deck;
char suit[] = {'h','d','c','s'};
char card[] = {'2','3','4','5','6','7','8','9','T','J','Q','K','A'};
for (int j=0; j<13; j++) {
for (int i=0; i<4; i++) {
deck.push_back(new Card(card[j],suit[i]));
}
}
return 0;
}
also using enums instead of chars in suit and card would make it clearer.
Upvotes: 12
Reputation: 7946
I think what you are looking to use is an enumeration. It will make your code clearer and resolve your problem.
enum SUIT { HEART, CLUB, DIAMOND, SPADE };
enum VALUE { ONE, TWO, THREE, ..., TEN, JACK, QUEEN, KING};
Upvotes: 31
Reputation: 46987
Have you tried replacing J with 11, Q with 12 and K with 13? Then you could use int
egers rather than char
acters. Replace 11-13 with the appropriate letter later on.
Upvotes: 5