Sign in to follow this  
vinb

How would you represent a deck of cards?

Recommended Posts

vinb    218
I'm experimenting with making a blackjack game and I'm not sure how I want to represent the deck of cards in a class. I was thinking either an array of 52 Card objects which have a suit and a value property. I'm sure a lot of you have done a card game before and I was just wondering what more experienced people have done in the past. Thanks.

Share this post


Link to post
Share on other sites
Fruny    1658
As a std::deque<Card>, obviously. [smile]

And you might be happy to hear that C++ does have a shuffling function, called std::random_shuffle in the <algorithm> header.

Share this post


Link to post
Share on other sites
DEVLiN    203
I actually looked at this just a few weeks ago. =)

The most natural approach would obviously be to use a std::deque of cards.

A card would then have a value and a suit.

You might not want to limit your "deck" class to 52 cards, but rather an arbitrary number of cards for blackjack where you can play with for instance 4 normal "decks" packed into one.

You then fill a deck using the rules of the current game.

Atleast that was the approach I planned on using, lemme know if it works out =)

Edit: doh, Fruny beat me to it =)

Share this post


Link to post
Share on other sites
vinb    218
I figured if I asked I could avoid making a call to wheel.reinvent(). Are there any other useful things like this that might pertain to card games? I wanted to try a few of them before getting into graphics and stuff.

Share this post


Link to post
Share on other sites
DEVLiN    203
Quote:
Original post by vinb
I figured if I asked I could avoid making a call to wheel.reinvent(). Are there any other useful things like this that might pertain to card games? I wanted to try a few of them before getting into graphics and stuff.

A wise choice. I'd suggest you implement a text version first, just to try your implementation out. =)

Share this post


Link to post
Share on other sites
vinb    218
Quote:
Original post by DEVLiN
You might not want to limit your "deck" class to 52 cards, but rather an arbitrary number of cards for blackjack where you can play with for instance 4 normal "decks" packed into one.

You then fill a deck using the rules of the current game.


Interesting. I was actually thinking of using an array of Deck objects to handle that. That way the user could set a difficulty level of choosing how many decks to play with. But for games that don't use a standard deck size, that approach would work in both situations and I wouldn't have to mess with it. I'll post the code when I'm done. Oh, that reminds me, is this the proper area of the site to post code? You know, just to share. Or is there another place to do that? I tried it a couple of times and I'm not sure how useful it was to anyone.

Share this post


Link to post
Share on other sites
Zahlman    1682
Quote:
Original post by Fruny
As a std::deque<Card>, obviously. [smile]


Booooo... bad joke. (So why can't I stop grinning?) [smile]

Share this post


Link to post
Share on other sites
capn_midnight    1707
Quote:
Original post by Zahlman
Quote:
Original post by Fruny
As a std::deque<Card>, obviously. [smile]


Booooo... bad joke. (So why can't I stop grinning?) [smile]

it's actually not a terrible idea, except you should probably store pointers to Cards. Also, this structure, since it's a double ended queue, allows for dealing from the bottom of the deck. Implement an stl-like container called a "shoe".

Share this post


Link to post
Share on other sites
ontheheap    798
I find this to be an interesting topic because I learned C before starting on C++. Because of that, I find it hard to wrap my brain around the STL. When I think of a black jack game, I think char * cards = { "Ace", "Jack" }; etc... then I think int isBeingUsed = { 0 }; And then I think int cardValue = { 11,10 }; etc.

I would never think to use a class, or anything from the STL for something like this =( Anyways, I just found that to be interesting.

Share this post


Link to post
Share on other sites
the STL isnt that complicated, and once you start using it, youll wonder how you ever got along without it... vector,list,and map are my personal favorites. i also use a deque from time to time, but thats about it. but seriously, its not hard to wrap your head around. think of them as very smart arrays.

Share this post


Link to post
Share on other sites
Guimo    463
Hi,
Do something simple:
#define SUIT_DIAMOND 0
#define SUIT_SPADE 1
#define SUIT_HEART 2
#define SUIT_FLOWER 3
#define SUIT_JOKER 4
#define CARDS_TOTAL 54
#define CARDS_X_SUIT 13
#define NUM_SUITS 4
class CARD
{ int n;
int suit;
void setCard(int ni, int suiti)
{ n = ni;
suit = suiti;
}
}

class DECK
{ CARD card[CARDS_TOTAL];
DECK()
{ for(int i=0; i<CARDS_X_SUIT;i++)
for(int j=0; j<NUM_SUITS; j++)
card[j*CARDS_X_SUIT + i].setCard(i,j);
card[52].setCard(0,SUIT_JOKER);
card[53].setCard(1,SUIT_JOKER);
}

void shuffle()
{ int p;
CARD c;
for(int i=0;i<CARDS_TOTAL;i++)
{ p=rand();
c=card[i]; //Take current card
card[i] = card[p]; //exchange
card[p] = c;
}
}
}


That slould be enough, a simple deck class. Done in less than 5 minutes... no need to add STL

Luck!
Guimo

Share this post


Link to post
Share on other sites
dan1088352    100
sory this is so lang, I dont knoe any html

this will draw the card (it is from my 5 card dd game):

//mycard[] has 5 elements, I dont use zero (dont ask)
int game::drawcard()
{
cout << " ******** ******** ******** ******** ********";
cout << "\n";
//edit the number that it will go to to make it
//go less or more
for(loop[1] =0; loop[1]<1; loop[1]++)
{
cout << " * *";
}
cout << "\n";

for(loop[8]=0; loop[8]<1; loop[8]++)
{
cout << " * *";
}
cout << "\n";

for(loop[2]=0; loop[2]<1; loop[2]++)
{
getcard();
}

cout << "\n";

for(loop[3]=0; loop[3]<1; loop[3]++)
{
cout << " * *";
}
cout << "\n";

for(loop[4]=0; loop[4]<1; loop[4]++)
{
cout << " * *";
}
cout << "\n";

for(loop[5]=0; loop[5]<1; loop[5]++)
{
cout << " ********";
}
cout << "\n";
}
//the cards are somewhere beteween 1 and 14, but you dont want
//to display a 0 or a 1, so this func will make it so that
//wont happen
//output of the cards
int game::getcard()
{

if(mycard[loop[2]] == 8)
{
cout << " * " << 10 << " *";
return 0;
}
//-----------------
if(mycard[loop[2]] == 9)
{
cout << " * J *";
return 0;
}
//----------------
else if(mycard[loop[2]] == 10)
{
cout << " * Q *";
return 0;
}
//----------------
else if(mycard[loop[2]] == 11)
{
cout << " * K *";
return 0;
}
//----------------
else if(mycard[loop[2]] == 12)
{
cout << " * A *";
return 0;
}
//----------------
else
{
cout << " * " << mycard[loop[2]]+2 << " *" ;
}
}

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
We had to develop a deck class as a project a long time ago.

This was before std library such as deque, que, vector.

This was more of a real life simulator. So the shuffle would split into 2 decks of similar size. Then randomly take 1-4 cards from each pile and put them back into the original deck.

Share this post


Link to post
Share on other sites
DEVLiN    203
Quote:
Original post by Guimo
<snip>

Pick a card... any card... and make sure it can't be picked again.

Sure, it can be done with your solution with some other ugly hack to make sure it doesn't behave odd in any given situation.

Oh btw, in your solution, a straight flush of clubs is better than a straight flush of hearts; should you re-use the class for a poker game later on. That is ofcourse, unless you use a switch section to detect which is worth more, or god forbid - tons of if statements. myCard.suit > hisCard.suit is in my opinion much cleaner. [oh]

Ugly hacks make code less (re)usable and maintainable, it's not an opinion; it's a fact.

Share this post


Link to post
Share on other sites
Fruny    1658
Quote:
Original post by graveyard filla
why would you want to store pointers to Card's??? is there some sort of inheritense tree going on with the cards that you'd like to take advantage of? otherwise, i dont see the point [smile]


One reason would be that, if you have identical cards in the deck (see post about using multiple decks) you don't really need to differenciate between them. So you can instead store the card properties separately (e.g. in a static array holding the values, the images...), and just store pointers into that array to materialize the cards.

Share this post


Link to post
Share on other sites
vinb    218
Well, as promised, here's the code. I had a question regarding using pointers to objects. I am using a pointer to the game ojbects (the house, player1, the deck) for no other reason than because it's how I saw somebody else do it. Now that I look at the code, it seems that I'm not really gaining anything because I could still pass the objects around to the functions by reference if I created the objects on the stack. Is there anything to be gained by creating the objects on the heap?

main.cpp

#include <iostream>
#include <iomanip>
#include <windows.h>
#include "blackjack.h"
#include <ctime>
#include <time.h>

using namespace std ;

//FUNCTIONS
void updateScreen(const Player &player1, const Player &player2) ;
void dealCards(Deck *theDeck, Player *player1, Player *player2) ;
void hit(Deck *theDeck, Player *thePlayer) ;
void writeGame(const Player *theHouse, const Player *player1, int totalscore) ;
void writeHeadings() ;
void gameloop(Deck *theDeck, Player *theHouse, Player *player1, int &totalscore) ;
void resetDeck(Deck *theDeck) ;
COORD setPoint(const int x, const int y) ;
void SetConsolePosition(int x, int y) ;

const WIN = 1 ;
const LOSE = 0 ;
const LEFT_MARGIN = 20 ;

/////////////////////////////////////////////
// MAIN
/////////////////////////////////////////////
void main(){

Deck *theDeck = new Deck() ;
int totalscore = 0 ;
char response ;

do {

Player *theHouse = new Player();
Player *player1 = new Player() ;

system("cls") ;

theHouse->setScore('!') ;
player1->setScore('!') ;

gameloop(theDeck, theHouse, player1, totalscore) ;
cout << "Play again? Y/N" ;
cin >> response ;
if (response == 'N' || response == 'n' ) break ;

resetDeck(theDeck);

delete theHouse ;
delete player1 ;

}while (true) ;


delete theDeck ;

system("pause") ;
}

/////////////////////////////////////////////
void gameloop(Deck *theDeck, Player *theHouse, Player *player1,int &totalscore) {

int cardCount = 0 ;

dealCards(theDeck, theHouse, player1) ;
cardCount = 2 ;

// write to screen
for (int i=0;i<2;i++){
writeGame(theHouse, player1, totalscore) ;
}

char response ;
bool hitTheHouse = true;
do{

if ( theHouse->getScore() == 21) {
cout << "YOU LOOSE!!!" << endl ;
totalscore -= 10 ;
hitTheHouse = false ;
break ;
}

if (player1->getScore() == 21){
cout << "YOU WIN!!!" << endl ;
totalscore += 10 ;
hitTheHouse = false ;
break ;
}

SetConsolePosition(0,3) ;
cout << "Hit? (Y or N)" ;
cin >> response;

if (response == 'N' || response == 'n') break ;

hit(theDeck, player1) ;

writeGame(theHouse, player1, totalscore) ;
cardCount++ ;

if (player1->getScore() > 21){
cout << "BUSTED!!!" << endl;
totalscore -= 10 ;
hitTheHouse = false ;
break ;
}
if (player1->getScore() == 21){
cout << "YOU WIN!!!" << endl ;
totalscore += 10 ;
hitTheHouse = false ;
break ;
}
} while (true) ;

// hit the house until player1 loses or the house busts.
while (hitTheHouse){

if ( theHouse->getScore() <= player1->getScore() ) {
hit(theDeck, theHouse ) ;
}

writeGame(theHouse, player1, totalscore) ;
cardCount++ ;

if ( theHouse->getScore() > 21) {
cout << "YOU WIN!!!" << endl ;
totalscore += 10 ;
break ;
}

if ( theHouse->getScore() == 21) {
cout << "YOU LOOSE!!!" << endl ;
totalscore -= 10 ;
break ;
}

if ( theHouse->getScore() > player1->getScore() && theHouse->getScore() < 21 ){
cout << "YOU LOOSE!!!" << endl ;
totalscore -= 10 ;
break ;
}

} ;

}
/////////////////////////////////////////////
void SetConsolePosition(int x, int y){

COORD point = setPoint(x, y) ;
HANDLE stdCon = GetStdHandle(STD_OUTPUT_HANDLE);

SetConsoleCursorPosition(stdCon, point);

}

/////////////////////////////////////////////
void writeHeadings(){

SetConsolePosition(LEFT_MARGIN,3) ;

cout << setw(11) << "House: " << setw(11) << "You: " << setw(11) << "Bank" << endl ;

SetConsolePosition(LEFT_MARGIN,4) ;
cout << "----------------------------------------" << endl ;
}

/////////////////////////////////////////////
COORD setPoint(const int x, const int y){
COORD point = {x,y} ;
return point ;
}

/////////////////////////////////////////////
void writeGame(const Player *theHouse, const Player *player1, int totalscore){ ;

system("cls") ;
writeHeadings() ;

cout << endl ;
int houseTotal = 0, player1Total = 0 ;
int colspace = 5;

for (int i=0;i<10;i++){

if(player1->hand[i].getName() == '!' && theHouse->hand[i].getName() == '!' ) break ;

SetConsolePosition(LEFT_MARGIN,i+6) ;

houseTotal += theHouse->hand[i].getVal() ;

cout << setiosflags (ios_base::left) ;
cout << theHouse->hand[i].getSuit() ;
cout << setw(colspace) ;
cout << setiosflags (ios_base::left);
cout << theHouse->hand[i].getName() ;

cout << setw(colspace) << setiosflags (ios_base::left);
cout << houseTotal ;

player1Total += player1->hand[i].getVal() ;

cout << setiosflags (ios_base::left);
cout << player1->hand[i].getSuit() ;
cout << setw(colspace) ;
cout << setiosflags (ios_base::left);
cout << player1->hand[i].getName() ;

cout << setw(colspace) << setiosflags (ios_base::left) ;
cout << player1Total;
cout << setiosflags (ios_base::left);

cout << setw(colspace) << setiosflags (ios_base::left) ;
cout << "$" << totalscore ;

cout << endl ;

}
}

/////////////////////////////////////////////
void dealCards(Deck *theDeck, Player *theHouse, Player *player1){

// start with 2 cards
srand(time(NULL)) ;
int index, i ;
// deal the house
for (i=0; i<2; i++){
index = rand() % DECK_SIZE ;
theHouse->hand[i] = theDeck->getCard(index);
theHouse->setScore( theDeck->getCard(index).getVal() ) ;
theDeck->getCard(index).Use() ;
}

// deal player 1
for (i=0; i<2; i++){
index = rand() % DECK_SIZE ;
player1->hand[i] = theDeck->getCard(index);
player1->setScore( theDeck->getCard(index).getVal() ) ;
theDeck->getCard(index).Use() ;
}


}
/////////////////////////////////////////////
void hit(Deck *theDeck, Player *thePlayer){

int i=0, index ;
do{
if (thePlayer->hand[i].getName() == '!') break;
i++;

}while (true);
do{
index = rand() % DECK_SIZE ;
if (!theDeck->getCard(index).Used() ){
thePlayer->hand[i] = theDeck->getCard(index);
thePlayer->setScore( theDeck->getCard(index).getVal() ) ;
theDeck->getCard(index).Use() ;
break ;
}
} while (theDeck->getCard(index).Used()) ;
}

/////////////////////////////////////////////
void resetDeck(Deck *theDeck){
for (int i=0;i<DECK_SIZE;i++){
theDeck->getCard(i).PutBack() ;
}
}
/////////////////////////////////////////////
int WinOrLose(Player *thePlayer){


return 0 ;
}



blackjack.cpp

#ifndef BLACKJACK
#define BLACKJACK

#include "blackjack.h"
#include <iostream>
#include <stdlib.h>
#include <stdio.h>

using namespace std;

////////////////////////////////////////////
// PLAYER
////////////////////////////////////////////
int Player::getScore() const {

return score ;
}

/////////////////////////////////////////////
void Player::setScore(char cardValue){
if (cardValue == '!')
score = 0 ;
}

/////////////////////////////////////////////
void Player::setScore(int cardValue){
score+=cardValue ;
}

/////////////////////////////////////////////
int Player::getStatus(){

return status ;
}

/////////////////////////////////////////////
void Player::stand(){

}
/////////////////////////////////////////////
Player::Player(){

this->score = 0 ;
this->status = 0 ;
for(int i=0;i<10;i++)
hand[i].setName('!') ;

}
/////////////////////////////////////////////
Player::~Player(){

}

/////////////////////////////////////////////
void Player::setHand(Card card){

}
////////////////////////////////////////////
// CARD
////////////////////////////////////////////
Card::Card(){
value = 0 ;
name = ' ' ;
suit = ' ';
used = false ;

}
/////////////////////////////////////////////
Card::~Card(){

}
/////////////////////////////////////////////
char Card::getName() const {

return name ;
}
/////////////////////////////////////////////
void Card::setName(int i){

if (i==0 || i==13 || i==26 || i==39) name = '2' ;
if (i==1 || i==14 || i==27 || i==40) name = '3' ;
if (i==2 || i==15 || i==28 || i==41) name = '4' ;
if (i==3 || i==16 || i==29 || i==42) name = '5' ;
if (i==4 || i==17 || i==30 || i==43) name = '6' ;
if (i==5 || i==18 || i==31 || i==44) name = '7' ;
if (i==6 || i==19 || i==32 || i==45) name = '8' ;
if (i==7 || i==20 || i==33 || i==46) name = '9' ;
if (i==8 || i==21 || i==34 || i==47) name = 'T' ;
if (i==9 || i==22 || i==35 || i==48) name = 'J' ;
if (i==10 || i==23 || i==36 || i==49) name = 'Q' ;
if (i==11 || i==24 || i==37 || i==50) name = 'K' ;
if (i==12 || i==25 || i==38 || i==51) name = 'A' ;
}

void Card::setName(char c) {
name = c ;
}

/////////////////////////////////////////////
char Card::getSuit() const {
return suit ;
}
/////////////////////////////////////////////
void Card::setSuit(int i){

if (i >=0 && i < 15) this->suit = 'H' ;
if (i >=15 && i < 28) this->suit = 'D' ;
if (i >=28 && i < 41) this->suit = 'S' ;
if (i >=41) this->suit = 'C' ;

}
/////////////////////////////////////////////
int Card::getVal() const{
return value ;
}
/////////////////////////////////////////////
void Card::setVal(int i){
if (i==0 || i==13 || i==26 || i==39) value = 2 ;
if (i==1 || i==14 || i==27 || i==40) value = 3 ;
if (i==2 || i==15 || i==28 || i==41) value = 4 ;
if (i==3 || i==16 || i==29 || i==42) value = 5 ;
if (i==4 || i==17 || i==30 || i==43) value = 6 ;
if (i==5 || i==18 || i==31 || i==44) value = 7 ;
if (i==6 || i==19 || i==32 || i==45) value = 8 ;
if (i==7 || i==20 || i==33 || i==46) value = 9 ;
if (i==8 || i==21 || i==34 || i==47) value = 10 ;
if (i==9 || i==22 || i==35 || i==48) value = 10 ;
if (i==10 || i==23 || i==36 || i==49) value = 10 ;
if (i==11 || i==24 || i==37 || i==50) value = 10 ;
if (i==12 || i==25 || i==38 || i==51) value = 11 ;
}

//////////////////////////////////////////////
void Card::Use(){
used = true ;
}

void Card::PutBack(){
used = false ;
}

//////////////////////////////////////////////
bool Card::Used(){
return (used)? true : false ;
}

////////////////////////////////////////////
// Deck
////////////////////////////////////////////
Deck::Deck(){

for (int i=0;i<DECK_SIZE;i++){

card[i].setVal(i) ;
card[i].setSuit(i) ;
card[i].setName(i) ;

// cout << card[i].getName() << " " ;
// cout << card[i].getSuit() << " " ;
// cout << card[i].getVal() << " " << endl ;

}
}
/////////////////////////////////////////////
Deck::~Deck(){

}
/////////////////////////////////////////////
void Deck::deal(){

}
/////////////////////////////////////////////
int Deck::getIndex(){
return index ;
}
/////////////////////////////////////////////
Card Deck::getCard(int i){
return this->card[i] ;
}
#endif



blackjack.h

////////////////////////////////////////////
// CARD INTERFACE
////////////////////////////////////////////
const int DECK_SIZE = 52;
class Card{

private:
char suit ;
char name ;
int value ;
bool used ;

public:

Card();
~Card();

char getSuit() const ;
void setSuit(int i) ;
char getName() const;
void setName(int i) ;
void setName(char c) ;
int getVal() const;
void setVal(int i);
void Use() ;
void PutBack() ;
bool Used() ;
};

////////////////////////////////////////////
// DECK INTERFACE
////////////////////////////////////////////
class Deck{

private:
int index ;
Card card[DECK_SIZE] ;

public:
Deck();
~Deck();

Card getCard(int card) ;
void deal() ;
int getIndex() ;

} ;

////////////////////////////////////////////
// PLAYER INTERFACE
////////////////////////////////////////////
class Player{
private:

int score ;
int status ;

public:

Player();
~Player();

Card hand[10] ;
int getStatus() ;
void stand() ;
void setScore(int cardValue) ;
void setScore(char cardValue) ;
int getScore() const ;
void setHand(Card card) ;
//void doubleDown();

} ;


Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this