views:

123

answers:

4

Hey you guys were absolutely great with my last problem so hopefully you can help clarify something else to me.

Classes confuse me! For this particular assignment, we are to do the classic 'Cards in a Deck' program. We are to make two classes, one called 'Card' and the other 'Deck'. Now I've gotten a large chunk of this done so far but a concept seems to be escaping me.

When we call a default constructor for the Card class, all 52 cards are to be created so that the Deck class may use these objects and... well create a deck! Now I attended a session with our TA and he stressed the fact that the default constructor is to initialize the values while the Deck class takes these objects and loops through them to use a function that assigns real card values to the Card objects.

My question is this: what is the best approach for creating these objects so that Deck may reference them? My idea right now is to create a fixed array called 'initialCard[4][13]'. From there, the Deck class will pick a value - say 'initialCard[0][0]' and assign it to an Ace of Spades solely from the row and column of the two-dimensional array. However, my TA keep saying 'create an array of Card objects'. What could he mean by that? I have a slight grasp but I'm just unsure... anyone have any ideas? Thanks!

Maybe this will help... straight from the assignment page:


Your card class should have public getter and setter functions for both of these variables (getValue, setValue, etc), as well as a function that will return a c-string representation of the card. (You can call it toCString if you want.) It should work something as follows:

void toCString(char cardString[]) INPUT: A character array for storing the output OUTPUT: NONE This function should return a character string representing the card object. This string must have the following form: two characters followed by a third null byte. The first character represents suit; the second represents value. Suits should be “S”, “H”, “C”, or “D” for spades, hearts,

clubs, diamonds. The second character represents value: “A” for Ace, 2-9 for numbered cards, “T” for 10, “J” for Jack, “Q” for Queen”, “K” for King. Some examples: 2 of spades = 'S2' 10 of hearts = 'HT' Jack of diamonds = 'DJ' Queen of clubs = 'CQ' Ace of spades = 'SA' etc.

In addition to these, you should have at least a default constructor to initialize the values. You are welcome to create other constructors (perhaps one that initializes a card from it's c-string representation?) but it is not required.

Deck Class: In addition to your card class, you will need to create a Deck class to encapsulate all of your card objects. In this object you should have a private member multi-dimensional array (of size SUITS by VALUES) of your Card objects. When a Deck object is created, you should have it initialize the multi- dimensional array of Cards. Card suits are represented by an enumerated type; card values are represented by an integer from 1 to 13 (1 is an Ace, 2-10 are numbered values, 11 is the Jack, 12 is the Queen, and 13 is the King).

Your constructor should loop over the multi-dimensional array and initialize all values so that the complete deck of cards is represented.


So maybe you can see why I am confused... I swear I understand these concepts but argh... this is killing me. After this, the rest of the project should be cake I'm confident...

A: 
Class Deck {
private:
  Card cardArray[52];
public:
  Card* getCard(int n) { ... };
    ...

An array of Card objects.

Deck::Deck() {
  for (int i=0;i<52;i++) {
    cardArray[i].setValue(i);
  }
}

Assigning each one a value.

Simple?

Alexander Rafferty
do you know the difference between assignment and initialization? (...the fact that the default constructor is to initialize the values...)
Chubsdad
He said that the values are set after initialization. This isn't assignment though.
Alexander Rafferty
+2  A: 

It doesn't sound like you're getting the best advice.

It's always cleaner to construct an object into a truly valid state. So, rather than default-constructing the cards with a nonsense value and later filling in, construct them with the proper value. This can be done with vector, which has most of the advantages of an array.

So, you would have

class deck {
    std::vector< Card > cards;
    ...
    deck() {
        // no cards yet at this point
        for ( size_t i = 0; i < 52; ++ i ) {
            cards.push_back( Card( i ) );
        }
        // now array is valid
        ...

Avoid C-style arrays of classes with non-trivial constructors.

Potatoswatter
They may be disallowed from using STL, and need to learn how to do these beginner type problems using standard arrays. At least I had those restrictions when I learned. Restrictions like that may or may not be dumb, but regardless sometimes students have to program under those conditions.
SauceMaster
A: 

There are always a hundred ways to do something. For me, when creating classes and the structure of my program, I always think how things are related to each other.

In your problem, Cards in a Deck, the relationship is stated. Each Card object belongs to a Deck. I would start by creating the Card class as it has nothing lower than it then the Deck class. It sounds like you have gotten this far.

I would design the Card class to describe just a card, nothing else. The value and the suit. The Deck class i would have a private variable holding an array of cards. In the Deck classes constructor i would create the 52 cards. If you want to get fancy use a List rather than an array so you can add as many cards as you like. Not all card games use 52 cards in a deck.

Once the Deck is instantiated all of its methods will have access to the array of cards.

Justin808
This is precisely what I would like to do but now I'm doubting myself!
nanerj
don't doubt yourself. When you're learning, try something. If it works great, if not, great... either way you learned something :)
Justin808
Based on the bold line "In addition to these, you should have at least a default constructor to initialize the values" You just need to make sure the card is valid, not that the deck if valid... Your Card constructor could make the card a "D2" so all cards during instantiation would be "D2". Once instantiated, call a member function setValue(char suit, char value) to setup the car how you want. The setup for the cards would be done in the Deck constructor.
Justin808
A: 

Think about using the STL containers

class deck{
   private:
       std::vector<Card>;
       int card_pointer; //points to the element in the vector that is the "top" card in the deck
   public:
       shuffle_cards();//shuffles the deck
       deal_a_card(); //deals out one card and increments card_pointer

       deck();//initialize the deck in here and set card_pointer to 0

       ~deck();
};

Card can just be an int from 1 to 52 in order to represent all the cards. There is no need for a 2 dimensional array.

shuttle87