1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

Creating Objects

Discussion in 'C' started by inspiration, Mar 28, 2010.

  1. inspiration

    inspiration New Member

    Joined:
    Feb 15, 2010
    Messages:
    85
    Likes Received:
    0
    Trophy Points:
    0
    Hello everyone. I realize that this topic has probably already been covered elsewhere in this forum, I am just not able to find one. Here is my problem. I am trying to create a deck of cards (Uno to be exact) using a 2-dimensional array with Deck as one class and Card as the other. The Card class creates the card and the Deck class takes the object created by the Card class and inputs it into the Deck's array. I am having trouble with allowing the Deck's constructor to be able to create a Card so that I can put it into the array. Here is part of the code that I have so far. If someone needs more, I will be happy to post it.

    Code:
    #include <iostream>
    using std::cout;
    using std::cin;
    using std::endl;
    using namespace std;
    
    #include <string>
    
    #include "Card.h"
    
    Card::Card( int theCardColor, int theCardValue  )
    {
    	setColor( theCardColor );
    	setValue( theCardValue );
    }
    
    string Card::getCard()
    {
    	return (cardColor + " " + cardValue);
    }
    void Card::setColor( int cc )
    {
    	if (cc == 0)
    		cardColor = "Red";
    	else if (cc == 1)
    		cardColor = "Green";
    	else if (cc == 2)
    		cardColor = "Blue";
    	else if (cc == 3)
    		cardColor = "Yellow";
    	else
    		cardColor = "Black";
    }
    
    void Card::setValue( int cv )
    {
    	if (cv == 0)
    		cardValue = "0";
    	else if ((cv == 1) || (cv == 2))
    		cardValue = "1";
    	else if ((cv == 3) || (cv == 4))
    		cardValue = "2";
    	else if ((cv == 5) || (cv == 6))
    		cardValue = "3";
    	else if ((cv == 7) || (cv == 8))
    		cardValue = "4";
    	else if ((cv == 9) || (cv == 10))
    		cardValue = "5";
    	else if ((cv == 11) || (cv == 12))
    		cardValue = "6";
    	else if ((cv == 13) || (cv == 14))
    		cardValue = "7";
    	else if ((cv == 15) || (cv == 16))
    		cardValue = "8";
    	else if ((cv == 17) || (cv == 18))
    		cardValue = "9";
    	else if ((cv == 19) || (cv == 20))
    		cardValue = "Skip";
    	else if ((cv == 21) || (cv == 22))
    		cardValue = "Draw 2";
    	else if ((cv == 23) || (cv == 24))
    		cardValue = "Reverse";
    	else if (cv == 25)
    		cardValue = "Wild";
    	else
    		cardValue = "Wild Draw 4";
    }
    Code:
    #include <iostream>
    using std::cout;
    using std::cin;
    using std::endl;
    using namespace std;
    
    #include <string>
    
    #include "Deck.h"
    #include "Card.h"
    
    Deck::Deck()
    {
    	originalDeck();
    }
    
    void Deck::originalDeck()
    {
    	int theColor = 0;
    	int theValue = 0;
    	int temp;
    
    	while (theColor < 4)
    	{
    		while (theValue < 27)
    		{
    			if ((theValue == 25) || (theValue == 26))
    			{
    				temp = 4;
    			}
    			else
    				temp = theColor;
    
    			Card newCard(temp, theValue)
    			theDeck[theColor][theValue] = newCard.getCard();
    		}
    	}
    }
     
  2. meyup

    meyup New Member

    Joined:
    Feb 15, 2010
    Messages:
    102
    Likes Received:
    0
    Trophy Points:
    0
    > Deck's constructor to be able to create a Card so that I can put it into the array

    just use card's constructor to create an anonymous card object and assign that card to the array element:
    Code:
    array[i][j] = card( /* constructor arguments */); 
    the number of different colours or values that cards can have are only those from a small set of permissible values; consider using an enum instead of a std::string or int for these kinds of variables. your code tends to be more type-safe (it is less likely that these might get values outside the permissible set). and you can always do a simple look-up to print out these values as a human-readable string.
    Code:
    #include <cassert>
    #include <string>
    
    struct card
    {
       enum colour_t { RED=0, GREEN, BLUE, YELLOW, BLACK } ;
       enum value_t  { ONE=1, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT,
                                   NINE, SKIP, DRAW2, REVERSE, WILD, WILD_DRAW4 } ;
       enum { NCOLOURS = 5, NVALUES = 14 } ;
    
       card() : colour(RED), value(ONE) {}
    
       card( colour_t c, value_t v ) : colour(c), value(v) {}
    
       static colour_t to_colour( int c )
       {
            assert( ( c >= RED ) && ( c <= BLACK ) ) ;
            return colour_t( c ) ;
       }
    
       static value_t to_value( int v )
       {
             // as per the logic in your code
            if( ( v > 0 ) && ( v < 26 ) ) return value_t( (v+1) / 2 ) ;
            else return WILD_DRAW4 ;
       }
    
       std::string str() const
       {
         static const char* colour_name[] = 
               { "RED", "GREEN", "BLUE", "YELLOW", "BLACK" } ;
         static const char* value_name[] =
               { "", "ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN", "EIGHT",
                  "NINE", "SKIP", "DRAW2", "REVERSE", "WILD", "WILD_DRAW4" } ;
        return std::string( colour_name[colour] ) + ' ' + value_name[value] ;
       }
    
       // other member functions
    
       private:
         colour_t colour ;
         value_t value ;
    };
    
    struct deck
    {
        typedef card::colour_t colour_t ;
        typedef card::value_t value_t ;
    
        deck()
        {
          for( colour_t c = card::RED ; c <= card::BLACK ; c = colour_t(c+1) )
             for( value_t v = card::ONE ; v <= card::WILD_DRAW4 ; v = value_t(v+1) )
                deck_of_cards[ c - card::RED ] [ v - card::ONE ] = card( c, v ) ;
        }
    
        // other member functions
    
        private: card deck_of_cards[ card::NCOLOURS ] [ card::NVALUES ] ;
    };
     
  3. inspiration

    inspiration New Member

    Joined:
    Feb 15, 2010
    Messages:
    85
    Likes Received:
    0
    Trophy Points:
    0
    Yeah, I have thought about using structures to do this program, but this is a school project. I have to use classes to do this because for our last part of this project, we have to make the shuffled deck of cards a stack, the hand that the person has a linked list, and then allow the person to play UNO. I don't need any full code help or anything, I just need a push in the right direction. :D I have updated my Deck class now so that it creates the cards and places them in the Original Deck array, but now I am having troubles creating the randomly selected cards to insert into the shuffled Deck of cards. Here's my Deck class. If you could point out what my mistake might be, I would be very grateful.

    Code:
    #include <iostream>
    using std::cout;
    using std::cin;
    using std::endl;
    using namespace std;
    
    #include <string>
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    #include "Deck.h"
    #include "Card.h"
    
    Deck::Deck()
    {
    	setOriginalDeck();
    };
    
    Deck::~Deck()
    {}
    
    void Deck::setOriginalDeck() //Sets the entire deck for checking purposes.
    {}
    
    void Deck::viewDeck() //Prints out the entire deck to the screen.
    {};
    
    
    void Deck::shuffle()
    {
    	int tempDeck[4][27]; //Creating a temporary array to ensure I am not using the same card twice in the shuffled deck.
    	int a;
    	int b;
    	int c = 0;
    	srand(time(0));
    
    	for (a = 0; a < 4; a++) //Inputting zeros into the tempDeck so that I can keep track of what cards have already been used.
    	{
    		for (b = 0; b < 27; b++)
    		{
    			tempDeck[a][b] = 0; //Zeros indicate that card hasn't been used. Ones indicate that card has been used.
    		}
    	}
    
    	while (c < 108) //c holds the number of cards that have been input into the shuffled deck already.
    	{
    
    		a = (rand() % 4); //Randomly selecting the row and column numbers for the choice card out of the deck.
    		b = (rand() % 26);
    
    		if (tempDeck[a][b] == 0) //Check to see if the card has not been used.
    		{
    			shuffledDeck[c] = theDeck[a][b]; //Inputting the random card out of the original deck into the shuffled deck.
    			tempDeck[a][b] = 1; //Making sure that the card that was just used is not used again.
    			cout << "new card inserted" << a << b << endl;
    
    			if (isFull()) //Need to check to see if the shuffled deck is full.
    			{
    				c = 108;
    			}
    			else
    			{
    				c++; //Increasing to the next spot in the array.
    			}
    		}
    		else
    		{
    		}
    
    	}
    }
    
    void Deck::viewShuffledDeck() //Outputting the deck to the screen.
    {}
    
    bool Deck::isFull() //Checking to see if the deck is full.
    {}
    I left some of the code out so that this post wouldn't turn too large because of all the code. If you need to see the rest, just let me know and I will post it. I took out the code from the functions that I know are working perfectly.
     
  4. inspiration

    inspiration New Member

    Joined:
    Feb 15, 2010
    Messages:
    85
    Likes Received:
    0
    Trophy Points:
    0
    Okay. I have the deck and it is creating a new card and inputting the card into the array, but now I can't get my random numbers to completely fill the stack of cards (shuffledDeck). It will get to 100-104 and then just stop filling the deck. Here is the code. If anyone can help me with that, I would greatly appreciate it.
    Code:
    void Deck::shuffle()
    {
    	int tempDeck[4][27]; //Creating a temporary array to ensure I am not using the same card twice in the shuffled deck.
    	int a;
    	int b;
    	int c = 0;
    	srand(time(0));
    
    	for (a = 0; a < 4; a++) //Inputting zeros into the tempDeck so that I can keep track of what cards have already been used.
    	{
    		for (b = 0; b < 27; b++)
    		{
    			tempDeck[a][b] = 0; //Zeros indicate that card hasn't been used. Ones indicate that card has been used.
    		}
    	}
    
    	while (c < 108) //c holds the number of cards that have been input into the shuffled deck already.
    	{
    		a = (rand() % 4); //Randomly selecting the row and column numbers for the choice card out of the deck.
    		b = (rand() % 26);
    
    		if (tempDeck[a][b] == 0) //Check to see if the card has not been used.
    		{
    			shuffledDeck[c] = theDeck[a][b]; //Inputting the random card out of the original deck into the shuffled deck.
    			tempDeck[a][b] = 1; //Making sure that the card that was just used is not used again.
    			cout << "new card inserted" << " " << a << " " << b << endl;
    			c++;
    
    			if (isFull()) //Need to check to see if the shuffled deck is full.
    			{
    				c = 108;
    			}
    
    		}
    
    	}
    }
     
  5. techme

    techme New Member

    Joined:
    Feb 15, 2010
    Messages:
    86
    Likes Received:
    0
    Trophy Points:
    0
    without a big spiel on it, random generator are poor in general. You have here the classic issue where most of the cards are used and the random dealer must hit the exact card that remains in the deck:

    say card #2 is the only one left unused: roll = 10, used, reroll = 7, 11,51, 1, 32, .... and an hour later, you finally roll a 2 and deal the final remaining card.

    Instead, consider an iterative approach:
    start with a deck of all cards possible, in the order you created them in (this might just be a lookup table or static array or something simple, I didnt really study your code close).

    then, truly shuffle the deck by randomly choosing a location and swapping it with another random location. Do this a few hundred times.

    Now, treat it like a true deck of cards (a stack, actually) -- pop the stack, use the card, its gone, pop next card .... until empty. (You don't have to use a stack, this is conceptual, it could be an iterator into the "deck" data structure --- consider an array, if you start at location zero, use it, move to location 1, .... until last location that is "stack like" behavior and an easy way to sove this problem).

    That prevents the reroll until you find an unused card problem and is much more efficient and is forced to always work (given some random number generator algorithm, the other method can potentially NEVER roll the final remaining card! ususally it will, since most generators touch every value eventually, but you don't know this for sure, do you? ).
     

Share This Page