Thread: Help with Classes Exercise

  1. #1
    Registered User
    Join Date
    Dec 2007
    Posts
    3

    Help with Classes Exercise

    Hello,

    First, let me thank the boards and members for their indirect help over the few months while I've been learning C++.

    Now, onto my question. I am supposed to be developing a Blackjack program. The two requirements are that it must have a class Card, which is made up of a suit and value. Then, I must have a class CardDeck, "Which is made up of an array of cards, and an int to indicate what the top card is (top of the stack)."It's constructor must initialize the deck, and it must also have a shuffleDeck and drawCard function.

    This is what I have so far for class Card...

    Code:
    enum Suit
    {
       clubs, diamonds, spades, hearts
    };
    enum Rank
    {
       two = 2, three, four, five, six, seven, eight, nine, ten, 
       jack, queen, king, ace
    };
    
    class Card{
    private:
    	Suit color;
    	Rank value;
    public:
    	Card(){}
    };

    Here is my pseudo code for CardDeck...

    Code:
    Class CardDeck {
    private:
    //Declare perhaps an array of cards of the Card type?
    public:
    //Declare int for card drawn?
    
    CardDeck(){
    //Constructor to initialize the array
    }
    
    //method to shuffle deck
    //method to draw card
    };

    1. Am I on the right track?
    2. If not, do you have any suggestions? I'm unsure of how exactly to start initializing the deck of cards (whether it's an array of the "Card" type, etc).

    Thanks a bunch,

    Mike

  2. #2
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    You're doing pretty well. A simple way of initializing the deck of cards would be to let every Card initialize itself. Or you could use a simple for loop, initializing each card to an unused card. Maybe in sequence, because you could shuffle the deck later.

    You'd almost certainly want set and get member functions, and probably this constructor as well: Card(Suit, Rank).
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  3. #3
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    The deck of cards is simple:
    Code:
    typedef std::vector<Card>   Deck;
    Although if it really needs to be a separate class, just use the std::vector<Card> as a member variable and write some functions that manipulate the vector.
    Then you could simply use std::random_shuffle() to shuffle the cards...

  4. #4
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Just a thought, but you should probably move those enums inside the class. They're class utilities, so to speak, after all.
    And if you use cpjust's typedef, be sure to put it inside the class, as well. It's not a good thing to pollute the global namespace.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  5. #5
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by Elysia View Post
    And if you use cpjust's typedef, be sure to put it inside the class, as well. It's not a good thing to pollute the global namespace.
    Oh well, the world needs a little more pollution anyways. You don't want it too clean do you?

  6. #6
    Registered User
    Join Date
    Dec 2007
    Posts
    3
    Okay, this is what I have so far....please correct me with any mistakes I may have, especially regarding the shuffle function and if that is even correct...

    Code:
    srand(time(0));
    
    
    class Card{
    	enum Suit
    		{
    		clubs, diamonds, spades, hearts
    		};
    	enum Rank
    		{
    		two = 2, three, four, five, six, seven, eight, nine, ten, 
    		jack, queen, king, ace
    		};
    private:
    
    	Suit color;
    	Rank value;
    
    public:
    
    	Card(csuit, crank){
    	csuit = color;
    	crank = value;
    	}
    
    };
    
    
    class CardDeck{
    private:
    	int cardDrawn = 0;
    	Card deck[52];
    
    	CardDeck(){
    		int d = 0;
    		for (int i = 0; i <= 3; i++){
    			for (int j=0; i<=13; j++){
    				deck[d] = new Card(i,j);
    				d++;
    			}
    		}
    	}
    
    	void shuffleDeck(){
    
    	unsigned int time = rand();
    	for (int i = 0; i < 51; i++){
    		time = i + (rand() % (52-i));
    		int temp = deck[i]; deck[i] = deck[time]; deck[time] = temp;
    	}
    	}
    
    	void drawCard(){
    	..................
    I have not written drawCard yet, as I also am unsure of how to do that. Obviously I will be drawing a card for the dealer, player, and computer, so I am unsure of how I would kind of iterate it to draw the first card (0), then next (1), etc...

  7. #7
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    OK, so a few notes.
    I would rather you put these...
    Code:
    	enum Suit
    		{
    		clubs, diamonds, spades, hearts
    		};
    ...like so:
    Code:
    	enum Suit
    	{
    		clubs, diamonds, spades, hearts
    	};
    Better indentation. Just a minor details and individual preference, though. You can do as you wish.

    Code:
    	Card(csuit, crank){
    	csuit = color;
    	crank = value;
    	}
    Indent all blocks:
    Code:
    	Card(csuit, crank){
    		csuit = color;
    		crank = value;
    	}
    Do the same for other functions.
    Code:
    int temp = deck[i]; deck[i] = deck[time]; deck[time] = temp;
    Usually hurts readability; try to avoid.

    Code:
    Card deck[52];
    Here's a problem, though. You're creating the decks as part of the class, ie the stack. Not the heap, as seems what you're trying to do.
    It should be:
    Code:
    Card* deck[52];
    Also note that some also prefer to one puts a prefix to type, so it would actually be named pDeck or something. Up to you, anyway.

    You have a constructor that allocates memory, but you don't have a destructor that deletes it. And since you're allocating on the heap, you have to worry about the copy constructor and assignment operator, too.
    What happens if you try to assign a CardDeck to another? Should it receive its own copies of the cards? (This is probably likely.) Then you must overload a copy constructor (and assignment operator) to copy the memory over the second object. Otherwise you'll copy the pointers and you'll get multiple frees and eventually, crashes. Or you can make the copy constructor and assignment operators private to ensure the class can't be assigned (or copied).
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  8. #8
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Code:
    		for (int i = 0; i <= 3; i++){
    			for (int j=0; i<=13; j++){
    				deck[d] = new Card(i,j);
    				d++;
    			}
    		}
    I believe your loop condition is not quite right. Avoid the <= operator and use less than: j < 4, i < 13. Both 4 and 13 have a nice meaning which 3 and 12 (?) wouldn't have in this context.

    If you have an array of Card objects, a pointer to Card is not expected. You might try deck[d] = Card(i, j) instead.

    For random shuffling there's a nice algorithm called random_shuffle which you might use.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  9. #9
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    There's another problem, though. Card has no default constructor, so that means they must be initialized, and not constructed in the constructor body.
    So the idea would be to create a default constructor for Card that takes no arguments and then Do what anon mentions, or simply create a function (or functions) that sets the parameters in the class.

    You could also nest Card inside CardDeck since it's meant to be a helper function. Also define it as private to make sure that it's only used by CardDeck and not outside the class.

    I also forgot to mention that it's usually better to put the declarations inside the header and put the definition inside a .cpp. There are multiple reasons including cleaner declarations (easier to navigate declarations) and faster compile time (the compiler has to parse less code each time you include the header).
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  10. #10
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by Elysia View Post
    Indent all blocks:
    Code:
    	Card(csuit, crank){
    		csuit = color;
    		crank = value;
    	}
    Well since you're on the topic of code style, I hate when people put opening braces on the end of a line rather than a new line:
    Code:
    	Card(csuit, crank)
    	{
    		csuit = color;
    		crank = value;
    	}
    But as you said:
    Just a minor details and individual preference, though. You can do as you wish.

  11. #11
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Well, same here, but many people do it and there's nothing wrong with it
    Just make sure the ending bracket is on the same level as the function.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  12. #12
    Registered User
    Join Date
    Dec 2007
    Posts
    3
    Hey all, thanks for all the help. I'm still having at least one problem, but I've "finished" the program. I'm sure that all the ifs could be cleaned up, and I'm sure there are logic errors, but right now I'm mainly just working on getting the program just to work and run. Afterwards I will work on cleaning it up. Here is code I am getting, with the line the compiler error is giving to me in bold... Specific error is...

    1>c:\users\mike\documents\visual studio 2005\projects\assignment9\assignment9\assignment9. cpp(78) : error C2106: '=' : left operand must be l-value
    1>c:\users\mike\documents\visual studio 2005\projects\assignment9\assignment9\assignment9. cpp(79) : error C2106: '=' : left operand must be l-value



    I'm guessing it has to do with assigning an array value to each other, which isn't possible, but I I guess I only understand the error for the first line it's associated with, not the second one.

    Code:
    #include "stdafx.h"
    #include <ctime>
    #include <iostream>
    #include <stdlib.h>
    #include <cstdlib>
    #include <fstream>
    using namespace std;
    
    
    class Card{
    	enum Suit
    		{
    			clubs, diamonds, spades, hearts
    		};
    	enum Rank
    		{
    			two = 2, three = 3, four = 4, five = 5, six = 6, seven = 7, eight = 8, nine = 9, ten = 10, 
    			jack = 10, queen = 10, king = 10, ace = 11
    		};
    
    
    public:
    	Suit color;
    	Rank value;
    
    	Card(){
    	}
    
    
    	Card(int csuit, int crank){
    		csuit = color;
    		crank = value;
    	}
    
    };
    
    
    class CardDeck{
    public:
    	Card deck[51];
    
    	CardDeck(){
    	//I think that it would be much easier to have the function initialize the cards rather than the constructor,
    	//   as it eases the process considerably when it comes time to create a new deck once all 52 cards have been used
    		initializeDeck();
    
    	}
    
    
    	void initializeDeck(){
    		int d = 0;
    		for (int i = 0; i < 4; i++){
    			for (int j=0; i < 13; j++){
    				deck[d] = Card(i,j);
    				d++;
    			}
    		}
    	}
    
    
    	void shuffleDeck(){
    	
    	srand(time(0));
    	int time = rand();
    	int temp = 0;
    	for (int i = 0; i < 51; i++){
    		time = i + (rand() % (52-i));
    		temp = (int)(deck[i].value); 
    		(int)deck[i].value = (int)(deck[time].value); 
    		(int)deck[time].value = temp;
    		}
    	}
    
    	int drawCard(){
    		int cardVal = 0;
    		static int _deckSize = 51;
    
    		if(_deckSize == 0){
    			initializeDeck();
    			_deckSize = 51;
    		}
    		
    		cardVal = deck[_deckSize].value;
    		return cardVal;
    		_deckSize--;
    	}
    
    
    };
    
    
    
    
    int main()
    {
    	cout << "Welcome to BlackJack!!!" << endl;
    
    	CardDeck cd;
    	cd.initializeDeck();
    	cd.shuffleDeck();
    	int playerSum;
    	int computerSum;
    	int dealerSum;
    	int temp = 0;
    	char hitOrStand;
    	bool stand = false;
    	bool playerBlackjack = false;
    	bool computerBlackjack = false;
    	char playAgain;
    
    	for(int i = 0; i < 2; i++){
    		temp += cd.drawCard();
    		playerSum += temp;
    		cout << "Player was dealt a" << temp << endl;
    		temp += cd.drawCard();
    		computerSum += temp;
    		cout << "Computer was dealt a " << temp << endl;
    		temp += cd.drawCard();
    		dealerSum += temp;
    		cout << "Dealer was dealt a " << temp << endl;
    	}
    
    	if(dealerSum == 21){
    		cout << "Dealer has blackjack! Player and Computer lose!" << endl;
    		cout << "Would you like to play again? (Press y for yes, n for no): ";
    		cin >> playAgain;
    			if(playAgain = 'y')
    				main();
    	}
    
    if(playAgain != 'y')
    {
    
    	if(playerSum == 21){
    		cout << "Player has blackjack!" << endl;
    		playerBlackjack = true;
    	}
    
    	if(computerSum == 21){
    		cout << "Computer has blackjack!" << endl;
    		computerBlackjack = true;
    	}
    
    
    	cout << "Dealer has" << dealerSum << endl;
    	cout << "\n\n Player has " << playerSum << endl;
    	cout << " \n\n Would the player like to hit or stand? (Press h for hit, s for stand) ";
    	cin >> hitOrStand;
    
    	if(hitOrStand = 'h'){
    		while(stand = false){
    			temp = cd.drawCard();
    			playerSum += temp;
    			cout << "You were dealt a " << temp << endl;
    			cout << "Player now has " << playerSum <<endl;
    			cout << "Would player like to hit or stand (Press h for hit, s for stand ) ";
    			cin >> hitOrStand;
    			if(hitOrStand = 's'){
    				stand = true;
    			}
    		}
    	}
    
    	cout << "\n\n\n Computer has " << computerSum << endl;
    	if(computerSum <= 11)
    	{
    		do
    		{
    			temp = cd.drawCard();
    			computerSum += temp;
    		}
    		while(computerSum<12);
    
    		if(computerSum == 21)
    		{
    			cout << "Computer has 21, Computer will Stand" << endl;
    		}
    		else if((dealerSum + 10 > computerSum))
    		{
    			do
    			{
    				temp = cd.drawCard();
    				computerSum += temp;
    				cout << "Computer drew a " << temp << " and now has " << computerSum << endl;
    			}
    			while((dealerSum + 10) > computerSum && computerSum <= 21);
    		}
    		else if(12 < dealerSum && dealerSum < 16 && 12 < computerSum && computerSum < 16)
    			{
    			}
    	}
    
    	cout << "Computer has " << computerSum << endl;
    
    	do
    	{
    		temp = cd.drawCard();
    		dealerSum += temp;
    		cout << "Dealer drew a " << temp << " and now has " << dealerSum << endl;
    	}
    	while(dealerSum < 17);
    
    	if(dealerSum > 21)
    	{
    		cout << "Dealer busts!" << endl;
    	}
    
    	if(dealerSum > playerSum || dealerSum > computerSum)
    	{
    		cout << "Dealer wins!" << endl;
    	}
    
    	if(playerSum > dealerSum)
    	{
    		cout << "Player wins!" << endl;
    	}
    
    	if(computerSum > dealerSum)
    	{
    		cout << "Computer wins!" << endl;
    	}
    
    	cout << "Would you like to play again? (Hit y for yes, n for no)";
    	cin >> playAgain;
    
    	if(playAgain == 'y')
    	{
    		main();
    	}
    
    
    
    	return 0;
    	}
    
    }

  13. #13
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Hold your horses for awhile: you're calling the global main() recursively, which is not allowed. Use a loop instead.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  14. #14
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    There are multiple errors in that code.
    Code:
    		(int)deck[i].value = (int)(deck[time].value); 
    		(int)deck[time].value = temp;
    So you're using an enum for the value, yes? Then you shouldn't be assigning them as ints. You should assign them with a value of the Card::Rank enum, nothing else.
    You have multiple assign instead of compare in your code, too.
    And once more, you have failed the indentation class. It really looks like a nice essay needs to be written about this.

    Consider this:
    Code:
    	void shuffleDeck(){
    	
    	srand(time(0));
    	int time = rand();
    	int temp = 0;
    	for (int i = 0; i < 51; i++){
    		time = i + (rand() &#37; (52-i));
    		temp = (int)(deck[i].value); 
    		(int)deck[i].value = (int)(deck[time].value); 
    		(int)deck[time].value = temp;
    		}
    	}
    Code is on the same level as the function. THIS IS BAD! Indent it one block!
    Indent every block ONCE and ONLY once. Not twice somewhere and once somewhere.
    And the ending } for the for loop is not on the same level as the for either! Beginning of a block and ending of a block should always be on the same level.

    Try to fix these errors first (along with main, of course, as laserlight points points out).
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Line of data input method
    By larry_2k4 in forum C Programming
    Replies: 2
    Last Post: 04-28-2009, 11:34 PM
  2. Request for comments
    By Prelude in forum A Brief History of Cprogramming.com
    Replies: 15
    Last Post: 01-02-2004, 10:33 AM
  3. include question
    By Wanted420 in forum C++ Programming
    Replies: 8
    Last Post: 10-17-2003, 03:49 AM
  4. Classes Exercise (again)
    By Excalibur XP in forum C++ Programming
    Replies: 5
    Last Post: 09-29-2002, 06:11 PM
  5. Help with Classes Exercise
    By Excalibur XP in forum C++ Programming
    Replies: 8
    Last Post: 09-26-2002, 07:22 PM