tags:

views:

2278

answers:

11

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.

+5  A: 

Use 'T' instead of 10.

Dave
+5  A: 

Have you tried replacing J with 11, Q with 12 and K with 13? Then you could use integers rather than characters. Replace 11-13 with the appropriate letter later on.

Ross
You could use a uint8_t from stdint.h as the integer type and your structure would be the same size as if you used a char.
Ted Percival
+9  A: 

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.

JtR
I think you will still have the problem with '10' in a char array.
Dave DuPlantis
Think about enums for suit and rank.
Martin York
Use sizeof(card) and sizeof(suit) instead of the magic numbers 13 and 4.
Ted Percival
+2  A: 

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).

FOR
+2  A: 

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]);
James Curran
I think this is a good approach, using strings instead of chars.
Dave DuPlantis
+26  A: 

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};
Kevin
+1  A: 

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.

Drek
Except that in blackjack several different cards have the same natural value, and one card has two values.
DJClayworth
True, but you'll have the same problem with chars, and can simplify the conditions to check as follows:1: The default value of 1 (Ace) is 11, unless your total is already greater than 21, in which case it's 1.2: If the value of the card is more than 10, make it equal 10, else use it's own value.
Drek
A: 

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.

Steve Fallows
+7  A: 

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:

  • Each card
  • A player's hand
  • The entire deck
  • The state of the table... including all player hands (including players who have split their initial hand), maybe a six-deck shoe, the discard pile, etc

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!!!

benjismith
A: 

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.

dlamblin
+2  A: 

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.