Sign in to follow this  
c4c0d3m0n

My Card Class

Recommended Posts

// cardclasses.hpp
// Classes for a card game

#include <string>
#include <sstream>
#include <cstdlib>

class Card
{
public:
    Card() // Constructor
    { // use .setCard()! This constructor only sets default values!
        card_symbol = 'e';
        card_symbol_color_black = false;
        card_value = '0';
        card_name.str("ER");
    }
    
    unsigned char getSymbol() const
    {
        return card_symbol;
    }
    bool isColorBlack() const
    {
        return card_symbol_color_black;
    }
    unsigned short int getValue() const
    {
        return card_value;
    }
    std::string getName() const
    {
        return card_name.str();
    }
    
    void setCard( unsigned char symbol, unsigned short int value )
    {
        switch( tolower( symbol ) ) { // Set the symbol
            case 'c': // Cross
            card_symbol = 'c';
            card_symbol_color_black = true;
            break;
            case 'd': // Diamond
            card_symbol = 'd';
            card_symbol_color_black = false;
            break;
            case 'h': // Hearts
            card_symbol = 'h';
            card_symbol_color_black = false;
            break;
            default: // Spades (safety feature as well)
            card_symbol = 's';
            card_symbol_color_black = true;
        }

        card_value = value; // Set the value ( 1..13 )

        card_name.str("");
        
        if( ( card_value >= 2 ) && ( card_value <= 10 ) ) { // Name the card
            card_name << card_value;
        }
        else switch( card_value ) { // Name the card (2)
            case 1:
            card_name << 'A';
            break;
            case 11:
            card_name << 'J';
            break;
            case 12:
            card_name << 'Q';
            break;
            default:
            card_name << 'K';
        }
        
        card_name << card_symbol; // Name the card's symbol.
    }


private: // Vars have std values for debugging
    unsigned char card_symbol;
    bool card_symbol_color_black; // True for black cards, false for red cards
    unsigned short int card_value;
    std::stringstream card_name;
};

class Deck
{
public:
    Deck( bool shuffle = false )
    {
        for( int i = 0; i < 13; i++ ) {
            Carddeck[i].setCard( 'c', i+1 );
        }
        for( int i = 0; i < 13; i++ ) {
            Carddeck[i+13].setCard( 'd', i+1 );
        }
        for( int i = 0; i < 13; i++ ) {
            Carddeck[i+26].setCard( 'h', i+1 );
        }
        for( int i = 0; i < 13; i++ ) {
            Carddeck[i+39].setCard( 's', i+1 );
        }
        
        if( shuffle ) {
            doShuffle();
        }
    }
    
    void doShuffle() {
        for( int i = 0; i < 52; i++ ) { // Preparation
            Tmpdeck[i].setCard( Carddeck[i].getSymbol(), Carddeck[i].getValue() );
            shuffle_used[i] = false;
        }
        
        srand( time( NULL ) );
        
        for( int i = 0; i < 52; i++ ) { // Hardcore shuffling (could take REALLY long)
            int random;
            do {
                random = rand() %52; // Get a random number 0..51
                Carddeck[i].setCard( Tmpdeck[random].getSymbol(), Tmpdeck[random].getValue() ); // Set the carddeck by it's copy
            } while( shuffle_used[random] );
            std::cout << "."; // Prehistoric progress-bar (gives 52 .'s)
        }
    }
    
    unsigned char getCardSymbol( int position ) const
    {
        return Carddeck[position].getSymbol();
    }
    bool isCardColorBlack( int position ) const
    {
        return Carddeck[position].isColorBlack();
    }
    unsigned short int getCardValue( int position ) const
    {
        return Carddeck[position].getValue();
    }
    std::string getCardName( int position ) const
    {
        return Carddeck[position].getName();
    }


private:
    Card Carddeck[51]; // No jokers
    Card Tmpdeck[51];
    bool shuffle_used[51];
};

It's pretty straight-forward, I hope you can understand my simple code. This compiles just fine with Dev-C++. When I tell my program to shuffle the deck over the constructor, the program crashes on shuffling. I've figured out that the two bits of code causing this are
Tmpdeck[i].setCard( Carddeck[i].getSymbol(), Carddeck[i].getValue() );
and
Carddeck[i].setCard( Tmpdeck[random].getSymbol(), Tmpdeck[random].getValue() ); // Set the carddeck by it's copy
. I have no idea what's wrong with this code. I had to do it this way since I wasn't able to use operator= ... I hope someone can point out my mistake. PS: I know the code can be done more professionally with #DEFINE 's or with vectors instead of arrays, I just don't have the C++ knowledge...

Share this post


Link to post
Share on other sites
  1. Your card deck only contains 51 cards. It will overflow when accessing the 52nd. This is probably causing the crash.
  2. Create a non-default constructor, so that cards can be initialized directly into their correct state.
  3. You don't need a card_symbol_color_black variable, since its value can be computed at runtime by a function from the card symbol.
  4. Why the card_ prefix in the member variables?
  5. Don't use an std::stringstream (use it locally only when needed), use std::string for storage. This will let you use the default operator=.
  6. Use operator=, and remove the setCard function.
  7. Use an enumeration instead of chaacters for the card symbol.
  8. Make the temporary array local to the function where it's used, and pass it by reference to subroutines. Same for shuffle_used.
  9. Drop all the get and is functions in the deck class. Overload operator[] instead.
  10. Don't use "safety" values in your switch statements. Write one case per correct value, and assert(false) in the default clause.

Share this post


Link to post
Share on other sites
Quote:
Original post by ToohrVyk
  1. Your card deck only contains 51 cards. It will overflow when accessing the 52nd. This is probably causing the crash.
And on that note, it also writes out of bounds of it's array for just this reason. In these lines :

for( int i = 0; i < 52; i++ ) { // Preparation
Tmpdeck[i].setCard( Carddeck[i].getSymbol(), Carddeck[i].getValue() );


and these :

for( int i = 0; i < 52; i++ ) { // Hardcore shuffling (could take REALLY long)
int random;
do {
random = rand() %52; // Get a random number 0..51
Carddeck[i].setCard( Tmpdeck[random].getSymbol(), Tmpdeck[random].getValue() ); // Set the carddeck by it's copy
} while( shuffle_used[random] );


Maybe others too, but these were the most obvious.


Share this post


Link to post
Share on other sites
1. Yes, an obvious mistake, thank you for pointing it out :) I guess this is a real killer error in a big project, since the compiler didn't tell me about it.
2. A what? This is my first Object ever, because I'm learning about OOP
3. Good point, I just felt like making it more complete. I'm programming a little poker-game, so the whole colour issue is obsolete anyway.
4. Why not? I see your point though, I migh change this design flaw later.
5. Alright :)
6. How would I go on about that? I had trouble using a constructor with Card in combination with the Card array in Deck
7. I thought of that after making this class aswell, but I haven't gotten to changing it yet. I was going to use some #DEFINE 's.
8. Okay, I don't understadn what you mean with "by reference" though.
9. This is hocuspocus to me, please explain.
10. Same as 9

Share this post


Link to post
Share on other sites
Quote:
Original post by c4c0d3m0n
1. Yes, an obvious mistake, thank you for pointing it out :) I guess this is a real killer error in a big project, since the compiler didn't tell me about it.


The compiler gives you more than enough rope to hang yourself.

That is one of the reasons why you want to add asserts, unit tests, and write your code so that you aren't directly manipulating pointers and arrays.

Pointer arithmetic is dangerous. There are techniques and practices that let you avoid writing dangerous code, and increase the ability for the compiler to detect bugs before they crash you at runtime.

Quote:
Quote:
# Use operator=, and remove the setCard function.

6. How would I go on about that? I had trouble using a constructor with Card in combination with the Card array in Deck


The default operator= will work if all of the parts of the card have the same assignment-semantics: once you change std::stringstream to std::string, this will be true.

Quote:
Quote:
# Use an enumeration instead of chaacters for the card symbol.

7. I thought of that after making this class aswell, but I haven't gotten to changing it yet. I was going to use some #DEFINE 's.


#define is an example of something you should avoid unless you don't have another choice.

enum suit { hearts, diamonds, spades, clubs };


gives you names that the compiler can understand that can be used as constants.


Quote:
Quote:
# Make the temporary array local to the function where it's used, and pass it by reference to subroutines. Same for shuffle_used.

8. Okay, I don't understadn what you mean with "by reference" though.



struct example {
int foo;
int bar[100];
};

void change_example( example& ex ) {
ex.foo = 2;
ex.bar[0] = -1;
}


I passed the struct "example" by reference into the function change_example.

A reference is somewhat like a const pointer to non-const data, with the following exceptions:


foo& a; // error, references *must* be initialized
foo c;
foo& b = c; // valid. This is analagous to foo*const x = &c;
foo d;
b = d; // this is analagous to *x = d


References must be bound. Once bound, references cannot be rebound. Assignment changes the data you are bound to, and not which item you are bound to (this is very different than pointers).

You can use reference parameters to functions to make functions that change their parameters.

Quote:
Quote:
# Drop all the get and is functions in the deck class. Overload operator[] instead.

9. This is hocuspocus to me, please explain.



struct example1 {
int one, two, three;
int& operator[](int index) {
if (index == 1) return one;
if (index == 2) return two;
if (index == 3) return three;
assert(false);
}
int const& operator[](int index)const {
if (index == 1) return one;
if (index == 2) return two;
if (index == 3) return three;
assert(false);
}
};

struct datum {
int x,y;
};

struct example2 {
datum data[100];
datum& operator[](int index) {
assert( index < 100 && index >= 0 );
return data[index];
}
datum const& operator[](int index)const {
assert( index < 100 && index >= 0 );
return data[index];
}
};

// use:

example2 foo;
datum bar = {2,3};
foo[5] = bar; // sets foo.data[5] for me


Quote:
Quote:
# Don't use "safety" values in your switch statements. Write one case per correct value, and assert(false) in the default clause.

10. Same as 9


A better switch statement pattern:

switch( card_value ) { // Name the card (2)
case 1: {
card_name << 'A';
} break;
case 11: {
card_name << 'J';
} break;
case 12: {
card_name << 'Q';
} break;
case 13: {
card_name << 'K';
} break;
default: {
assert(false); // we should never see this -- complain
card_name << 'A'; // program defensively
} break;
}

Share this post


Link to post
Share on other sites
Some miscellaneous tips:
  1. Get rid of the "card_" in your member variable names. It's redundant.
  2. Instead of setCard, create a constructor that uses the same parameters. If you must have a default constructor, it should create a valid card.
  3. Consider representing the card suit using an enum rather than a char.
  4. Make the card value an int instead of an unsigned short int. It is simpler and neither unsigned nor short gain you anything.
  5. Determine the color of the card from the suit, rather than storing it separately.
  6. Use std::random_shuffle to shuffle the deck. Your shuffle is broken, but even if it worked it would be slower and less random than std::random_shuffle.

Share this post


Link to post
Share on other sites
Wow, a lot of information suddenly...
Since 9 and 10 are still over my head, I decided to start over making my classes.

/*
** ## cardclasses.hpp
**
** Card
**
*/


enum suit { clubs, diamonds, hearts, spades };

class Card
{
public:
Card( int card_value, suit card_symbol ) { // Constructor
if( card_value > 13 )
assert( false );
else
value = card_value;

symbol = card_symbol;
}

private:
int value;
suit symbol;
};



This is as far as I have come... I kinda figured out what assert() does. My class now seems very simple, I can still easely add some get functions. You told me not to do that though. My question is: Why would I use a class over a struct or vice versa (keeping in mind I still have to make a deck)?

I don't know what pointers nor references are. I haven't been learning C++ that long, I'm trying to figure out what they are and what they are used for in this moment of my learning curve. I've programmed a little database and TicTacToe before in C++ without using this hocuspocus... :S Thanks for any help

Edit: I'm going to make an enum for the values aswell, if this still allows me to do simple mathematical comparisons (considering this is going to be a cardgame)

Share this post


Link to post
Share on other sites
Quote:
Original post by c4c0d3m0n
My question is: Why would I use a class over a struct or vice versa (keeping in mind I still have to make a deck)?


The only difference between the two in C++ is that one defaults to private members (class) whilst the other default to public members (struct).

class my_class {
int my_var;
}

struct my_struct {
int my_var;
}

Since we've not specified the accessibility for these variables (public, private, protected) my_var in the class will be private, whilst in the struct it will be public.

EDIT:
Quote:
Original post by c4c0d3m0n
Edit: I'm going to make an enum for the values aswell, if this still allows me to do simple mathematical comparisons (considering this is going to be a cardgame)


Yes, you can specify the numerical value for each enum as well.

enum suit { clubs = 8, diamonds = 46, hearts = 20, spades = 12 };

Share this post


Link to post
Share on other sites
That's not what I meant. I meant weather I could use enum for the card's values aswell, since Kings, Queeens, Jacks and Aces would be nice enumerations ;)

Share this post


Link to post
Share on other sites
Quote:
Original post by c4c0d3m0n
That's not what I meant. I meant weather I could use enum for the card's values aswell, since Kings, Queeens, Jacks and Aces would be nice enumerations ;)


I think it would be more useful to keep the card value as an integer and create constants for the face cards and aces. Maybe something like this:
     class Card
{
...
static int const LOW_ACE = 1;
static int const JACK = 11;
static int const QUEEN = 12;
static int const KING = 13;
static int const HIGH_ACE = 14;
...
};
Also, rather than doing this:
    if( card_value > 13 )
assert( false );
else
value = card_value;
do this. It clearer:
    assert( card_value <= 13 );
value = card_value;


Share this post


Link to post
Share on other sites
Alright, I'm continuing the process of building the base for a game. I am going to make a class for a deck now. You told me not to use get functions, but that I should pass the information of the card on by reference. Doesn't this make the use of a class obsolete then? A struct would do fine if I am not mistaken. Can I still use a constructor with a struct then? What was wrong with using get functions anyway?

I realise that these are a lot of questions, but I want to program the right way. It's just that I am kind of overwhelmedd by the amounts of information that I received from you guys. I am honoured that you are willing to help me though :)

Share this post


Link to post
Share on other sites
Quote:
Original post by c4c0d3m0n
You told me not to use get functions, but that I should pass the information of the card on by reference


Quote:
Original post by ToohrVyk
Drop all the get and is functions in the deck class. Overload operator[] instead.


C++ FAQ Lite: Operator Overloading

Quote:
Original post by c4c0d3m0n
Doesn't this make the use of a class obsolete then? A struct would do fine if I am not mistaken.
What was wrong with using get functions anyway?


I don't know why you believe it would make the use of a class obsolete, the purpose of the class (unless it's a POD type) is to act as an abstraction layer. Putting stuff in a class and then having get functions to access them kind of beats the purpose. You will of course eventually need access to certain data, but there are better ways of doing this (see ToohrVyk's suggestion) than GetXXXX functions.

PODS (Plain Old Data Structures) other hand only serve as a way of batching data together, these structures don't have methods and present all members variables as public.

Quote:
Original post by c4c0d3m0n
Can I still use a constructor with a struct then?


Quote:
Original post by Omid Ghavami
The only difference between the two in C++ is that one defaults to private members (class) whilst the other default to public members (struct).


Share this post


Link to post
Share on other sites
Quote:
Original post by c4c0d3m0n
You told me not to use get functions, but that I should pass the information of the card on by reference. ... What was wrong with using get functions anyway?

Rather than having a different function in the Deck class for each bit of card data, just have a function that returns a whole card (or a reference to a card). That way only the Card class has to worry about what values a card holds, and the Deck class will work no matter how you implement the Card class. You could overload the [] operator, but I recommend you don't -- keep it simple.

Quote:
Original post by c4c0d3m0n
Doesn't this make the use of a class obsolete then? A struct would do fine if I am not mistaken. Can I still use a constructor with a struct then?

As pointed out before, a struct is nearly the same as a class in C++. struct is mostly for compatibility with C, but people use it for other things, too. For now, just use class. In C#, the difference is more significant.

Share this post


Link to post
Share on other sites
Instead of asking everything and letting you guys chew out the work for me, I decided to take a few steps myself. I now came this far (haven't started programming the shuffle function yet). I didn't quite understand the stuff about operator overloading at C++ FAQ Lite I must admit.

/*
** ## cardclasses.hpp
**
** Card
** Deck
**
*/


enum suit { clubs, diamonds, hearts, spades };

class Card
{
public:
Card( int card_value, suit card_symbol ) { // Constructor
assert( card_value <= 13 );
value = card_value;

symbol = card_symbol;
}

std::string getFullNameString() const {
std::stringstream ss;

if( value >= 2 && value <= 10 )
ss << value << " of ";
else switch( value ) {
case 1 :
ss << "Ace of ";
break;
case 11 :
ss << "Jack of ";
break;
case 12 :
ss << "Queen of ";
break;
case 13 :
ss << "King of ";
break;
default :
assert( false );
}

switch( symbol ) {
case clubs :
ss << "Clubs";
break;
case diamonds :
ss << "Diamonds";
break;
case hearts :
ss << "Hearts";
break;
case spades :
ss << "Spades";
break;
default :
assert( false );
}

return ss.str();
} // End of getFullNameString()

private:
int value;
suit symbol;
};

Card operator= ( Card x, const Card y );

class Deck
{
public:
Deck( bool shuffle = false ) { // Constructor
for( int i = 0; i < 14; i++ ) {
Card tmpclubcard( i, clubs );
cards[i] = tmpclubcard;
}
for( int i = 0; i < 14; i++ ) {
Card tmpdiamcard( i, diamonds );
cards[i+13] = tmpdiamcard;
}
for( int i = 0; i < 14; i++ ) {
Card tmphearcard( i, hearts );
cards[i+26] = tmphearcard;
}
for( int i = 0; i < 14; i++ ) {
Card tmpspadcard( i, spades );
cards[i+39] = tmpspadcard;
}
}

private:
Card cards[52]; // No joker
};


It doesn't compile. Damn the Dev-C++ Compiler error reports, I can't just copy it it seems. MSVS2005 had it in a nice htm file. Ah well:
28 C:\Dev-Cpp\Projects\CardGame\main.cpp In file included from main.cpp 
68 C:\Dev-Cpp\Projects\CardGame\cardclasses.hpp `Card operator=(Card, Card)' must be a nonstatic member function
C:\Dev-Cpp\Projects\CardGame\cardclasses.hpp In constructor `Deck::Deck(bool)':
73 C:\Dev-Cpp\Projects\CardGame\cardclasses.hpp no matching function for call to `Card::Card()'
note C:\Dev-Cpp\Projects\CardGame\cardclasses.hpp:12 candidates are: Card::Card(const Card&)
note C:\Dev-Cpp\Projects\CardGame\cardclasses.hpp:12 Card::Card(int, suit)
76 C:\Dev-Cpp\Projects\CardGame\cardclasses.hpp ambiguous overload for 'operator=' in '((Deck*)this)->Deck::cards[i] = tmpclubcard'
note C:\Dev-Cpp\Projects\CardGame\cardclasses.hpp:12 candidates are: Card& Card::operator=(const Card&)
note C:\Dev-Cpp\Projects\CardGame\cardclasses.hpp:12 Card operator=(Card, Card)

The last three lines repeat for each suit symbol. It all ends with Error 1

I bet that if I fix that operator, everything will be poochie :) Can someone point my mistake out?

Share this post


Link to post
Share on other sites
Quote:
Original post by c4c0d3m0n
68 C:\Dev-Cpp\Projects\CardGame\cardclasses.hpp `Card operator=(Card, Card)' must be a nonstatic member function


As mentioned, operator= must be a nonstatic member function [wink]

But you don't need it anyway, since the default one will work and do what you expect anyway: don't provide one at all.

Share this post


Link to post
Share on other sites
71 C:\Dev-Cpp\Projects\CardGame\cardclasses.hpp no matching function for call to `Card::Card()' 
note C:\Dev-Cpp\Projects\CardGame\cardclasses.hpp:12 candidates are: Card::Card(const Card&)
note C:\Dev-Cpp\Projects\CardGame\cardclasses.hpp:12 Card::Card(int, suit)


This error is still left. It's strange, since Card::Card() is actually a function o_O

Share this post


Link to post
Share on other sites
Quote:
Original post by c4c0d3m0n
71 C:\Dev-Cpp\Projects\CardGame\cardclasses.hpp no matching function for call to `Card::Card()' 
note C:\Dev-Cpp\Projects\CardGame\cardclasses.hpp:12 candidates are: Card::Card(const Card&)
note C:\Dev-Cpp\Projects\CardGame\cardclasses.hpp:12 Card::Card(int, suit)


This error is still left. It's strange, since Card::Card() is actually a function o_O


Yes, but it isn't present [smile]

As the compile errors mention, your Card class has 2 viable constructors, one that makes a copy of a card (the copy constructor, which the compiler will auto-generate for you if you don't provide one *) and the one you defined, that takes an integer and a suit.

However, when you create an array of cards, what constructor will be called?


[*] This can be dangerous, but not in your case.

Share this post


Link to post
Share on other sites
Hmm, sounds good. A deck is still a collection of cards. Should I make a dummy card, and initialize every card from the array to be a copy of that dummy card? Sounds like a lot of work and not something very optimal at all... Is this the time of the learning process where I need to know about Vectors??

Share this post


Link to post
Share on other sites

class Card {
...
public:
Card():value(0), symbol(clubs){};
...
};


That is how you create a Card::Card.

If you ever default-construct a Card, you need a default-constructed Card.

I made your default-constructed Card a zero-card: invalid. You can use the fact that the value is zero in other parts of your code, asserting that you aren't being passed an uninitialized Card.

A Deck is slightly more than a collection of cards. A fresh Deck should have 1 of each Card. Possibly it should be sorted, but it should make no sorting guarantees.

Share this post


Link to post
Share on other sites
Thank you for the fast replies. This forum is really good :)

Should I go and design a method to make sure that every card in the deck only appears one time? If I program only trivial functions for the deck, it should never contain any other cards than the ones I give.

Share this post


Link to post
Share on other sites
I would personally implement some debugging methods:

class Deck {
bool CardsAreUnique();
bool DeckIsComplete();
};

and possibly assert() them occasionally when working on new algorithms where you are afraid of things screwing up.

Having your code check itself for bugs is usually a good idea. Having those checks placed in small, tight packages that you can ignore or skip if performance becomes an issue is also a good idea.

Share this post


Link to post
Share on other sites
I will do that once I know wether my shuffle function works. I'm having trouble with my string returning function now though...

    std::string getNameString( bool full_name = false ) const {
std::stringstream ss;

if( value >= 2 && value <= 10 )
ss << value << full_name? " of " : "" ;
else switch( value ) {
case 1 :
ss << full_name? "Ace of " : "A";
break;
case 11 :
ss << full_name? "Jack of " : "J";
break;
case 12 :
ss << full_name? "Queen of " : "Q";
break;
case 13 :
ss << full_name? "King of " : "K";
break;
default :
assert( false ); // Line 42
}

switch( symbol ) {
case clubs :
ss << full_name? "Clubs" : "c";
break;
case diamonds :
ss << full_name? "Diamonds" : "d";
break;
case hearts :
ss << full_name? "Hearts" : "h";
break;
case spades :
ss << full_name? "Spades" : "s";
break;
default :
assert( false );
}

return ss.str();
} // End of getNameString()



If full_name is true, it should return strings in the fashion of King of Hearts, 6 of Spades or Ace of Clubs.
If full_name is false, it should return strings in the fashion of Kh, 6s or Ac.

I had two seperate functions before, getFullNameString and getMinNameString. I tried combining them into one function using that bool, which fails. The output code is some digits that are all dividable by 100.

C:\Dev-Cpp\Projects\CardGame>Cardgame
900
300
800
200
200
200
400
400
800
00
00
500
500
800
200
900
700
700
1000
1000
Assertion failed: false, file cardclasses.hpp, line 42

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.


The assertion fails aswell, I'll post both my source files fully once more:

/**********************             C++  **
** **
** ************** ** ## CardGame
** * * ** ## A C++ project
** * * ** ## using classes
** * ## * ** ##
** * #### * ** ## (c) Rob Spoel
** * ######## * **
** * ######## * **
** * ## * **
** * #### * **
** * * **
** * * **
** ************** **
** **
** C++ **
\********************/


// Includes

#include <iostream> // Console version
#include <cstdlib> // Standart C library

#include <string>
#include <sstream>

#include "cardclasses.hpp" // The magic header


// Namespace

using namespace std;


// Globals

/**/

// Functions

/**/

// Main function

int main( int argc, char* argv[] )
{
Deck myDeck( true );
for( int i = 0; i < 52; i++ ) {
cout << myDeck.hitMe().getNameString() << "\n";
}

system( "PAUSE" );

return 0;
}


// Functions

/**/


// End



/*
** ## cardclasses.hpp
**
** Card
** Deck
**
*/


enum suit { clubs, diamonds, hearts, spades };

class Card
{
public:
Card( int card_value, suit card_symbol ) { // Constructor
assert( card_value <= 13 );
value = card_value;

symbol = card_symbol;
}

Card(): value( 0 ), symbol( clubs ) {}; // Default constructor

std::string getNameString( bool full_name = false ) const {
std::stringstream ss;

if( value >= 2 && value <= 10 )
ss << value << full_name? " of " : "" ;
else switch( value ) {
case 1 :
ss << full_name? "Ace of " : "A";
break;
case 11 :
ss << full_name? "Jack of " : "J";
break;
case 12 :
ss << full_name? "Queen of " : "Q";
break;
case 13 :
ss << full_name? "King of " : "K";
break;
default :
assert( false ); // Line 42
}

switch( symbol ) {
case clubs :
ss << full_name? "Clubs" : "c";
break;
case diamonds :
ss << full_name? "Diamonds" : "d";
break;
case hearts :
ss << full_name? "Hearts" : "h";
break;
case spades :
ss << full_name? "Spades" : "s";
break;
default :
assert( false );
}

return ss.str();
} // End of getNameString()

private:
int value;
suit symbol;
};

class Deck
{
public:
Deck( bool shuffle = false ) { // Constructor
for( int i = 0; i < 14; i++ ) {
Card tmpcard( i, clubs );
cards[i] = tmpcard;
}
for( int i = 0; i < 14; i++ ) {
Card tmpcard( i, diamonds );
cards[i+13] = tmpcard;
}
for( int i = 0; i < 14; i++ ) {
Card tmpcard( i, hearts );
cards[i+26] = tmpcard;
}
for( int i = 0; i < 14; i++ ) {
Card tmpcard( i, spades );
cards[i+39] = tmpcard;
}

if( shuffle )
doShuffle();

counter = 0;
}

void doShuffle() {
int index[52];
Card tmp[52];
for( int i = 0; i < 52; i++ ) {
index[i] = i;
tmp[i] = cards[i];
}

srand( time( 0 ) );
std::random_shuffle( index, index +52 );

for( int i = 0; i < 52; i++ ) {
cards[i] = tmp[index[i]];
}

counter = 0;
}

Card hitMe() {
assert( counter < 52 );
counter++;
return cards[counter-1];
}

private:
Card cards[52]; // No joker
int counter;
};




I'm sorry for the poor comentation, I shall work on it as soon as possible. Thank you for all your help so far!

Share this post


Link to post
Share on other sites
Keep them seperate. Two functions, getName() and getFullName(). Don't call it getNameString(), most same people assume a name is in string form [grin].

After all, getNameString(true) isn't very meaningful, to me anyway.

Share this post


Link to post
Share on other sites
Alright, name issue resolved :)

C:\Dev-Cpp\Projects\CardGame>Cardgame
4d
Ah
10c
5d
2s
6c
Assertion failed: false, file cardclasses.hpp, line 42

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

Still the deadly line 42 error. It seems that it shuffles a random amount of cards before asserting false. It seems a card or more have values over 13 (King). It should have asserted false much earlier if this would have been the case though. I am puzzled :S

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