Making Pig in C++

Started by
12 comments, last by Downer 18 years, 3 months ago
Hello, I'm trying to make the Dice game Pig in C++ for a project. My idea is to have have a Roll() function using the std library to make a random number from 1-6, and then to store that value, int die, in a vector. Then, if the user wishes to roll again, I add the next roll to the vector and display the sum of both. I'm trying to use classes to accomplish it. One class will be the Die class, which rolls a Die. The next class, Round, would store the Die value in a vector series, and then calculate the sum, ask the player to roll again, and determine if the score is kept or lost. The final class would be Player, which would store the actual score. Only problem is, I can't figure out how to do that. I have Michael Dawson's Beginning C++ book and am trying to work backwards from the Blackjack program but it's still mindboggingly difficult to do something so seemingly simple as finding a sum. Any help or guidance on how to do this would be appreciated. I'd supply code but the code I have isn't anywhere near coherent thought. Rules of pig: http://en.wikipedia.org/wiki/Pig_%28dice%29
Advertisement
I think you are approaching classes and object orientation in a wrong way. Simply because C++ has classes, doesn't mean that you should use them. Sometimes, procedural programming is the best option. While using classes is good in a lot of situations, using classes simply for the sake of classes isnt good programming.

As your probably guessed, the only I dont think you need to use any classes. Why? Because most of your outlined classes were simply functions that dealt with one or so variables. Consider the following psuedo-code.

2 Variables to keep track of the player's running total, and the comp's.One more variables to keep track of the turn's totalA variable to hold the random dice roll.Some way/variable to figure out who's turn it iswhile ( both players are less than a hundred points){figure out whose turn it isReset variables (such as turnTotal = 0 or something).while ( the person [or computer] who's turn it is wants to roll and they have not rolled a zero ){Roll the dice and get the number. Display it to the screen.If it is a one, make the turn total zero and break out of the loopElse, add the dice to the turn's running total. Then prompt if they want to have another go}end while}end whileSince we got here, we know someone had to win. Figure out who it was and display the results.


Hope that helps. Note that it is quite late and i am tired, but you should be alright.
Hmm... I don't think you have quite the right understanding of classes. That wouldn't really be a practical way of using them. Perhaps you mean functions? A class is simply a struct, if that helps at all. It is a structure which can include data and actions, in essence. For example, you could have the following:

class Player
{
Player Player(char* name, int numberofdice);
void Roll();
void StoreData(int roll, int* array);
int LoadData(int* array, index);
void SetName(char* name);

char* name;
int numberofdice;
}

This would be an example of a class header file. It declares the different functions your class would have available (Roll, StoreData, LoadData, SetName, and the constructor Player()), and also declares data member values name and numberof dice. In order to use this class, you would have to implement a .cpp file to correspond to this .h file. You'll have to read up a bit on the details of how to do this (includes, etc..) but this is the basic idea. In the cpp, you would actually define the function, for example, SetName might look like:

void SetName(char* nme)
{
this.name = nme;
}

The idea is that classes give you better way to represent objects, and the things they can do. You could have a class for a ball, which might have functions allowing you to move, rotate, bounce, change color, or blow up the ball, and they can all be preformed ONLY on objects of that class type (because they are functions OF that class).

Perhaps what you might want to have, is a single class for a die. Here's a possible psuedo-header:

class Die
{
int Roll(int numSides);
void StoreNumber(int* &data, int numtostore);
int sumVector(int index1, int index2);

int* data;
int numSides;
}

This could work, and you could work with it, but I feel like your approach right now is a bit misguided. You are perhaps jumping ahead of things. I know sometimes it isn't fun to do all of the basic stuff first, but you really need to with programming. Learn how to write a simple 'Hello World' program first, then work on getting user input, then work on loops, then storing data in arrays/using math, etc. Once you accomplish all of these intermediary steps, it will be much easier to write the final code. What you are trying to do now might produce better results (because it's quicker and you have something to start with), but won't give you the level of understanding that you need, and that you would get by having done everything from the beginning.

Good luck to you,
Tim
Just an update:

Thank you both very very much for the help, I dropped most of my dependance on classes as a result. My headache is pretty much gone and the program is speeding along except for a few catches with way too many similar variables and maybe a few extras that aren't needed.

I created a classless function, Roll(), which successfully creates a random value (1-6), adds it to a vector, creates a sum, and either stores or deletes it depending on the value. The sum is returned as RScore, or round score.

I declared a class, Player, to hopefully handle the functions of displaying the player's score and adding RScore to the player's total score.

And I did read most of the book, just a little too quickly apparently :)
Sorry to double post, but I have a strange error.
I changed my program again since my last post by integrating Roll() into the Player class.

My program works except for one problem:

Ptotal (Player total, or the player's score) is somehow set to a default of 65 even though the class constructor sets it to 0.

By the end of the first gameplay loop, it is over 28,000,000!

//Pig//A simple, text-based version of the die game Pig#include <iostream>#include <stdlib.h>#include <ctime>#include <vector>#include <string>#include <algorithm>using namespace std;class Player{public:  //Begin the public access level section    Player(int Ptotal=0);  //Declares the constructor    int Roll();    int GetScore();   //Declares the function GetScore(), which calculates the constant int PScore, or the player's score    void DisplayScore();    //Declares the function DisplayScore(), which displays PScore    int Ptotal;  //Declares the integer Ptotal, which holds the total score of the playerprivate: //Begin the private access level section    int m_Score; //Declares the integer m_Score    int Rtotal;  //Declares the integer Rtotal, which holds the total score accumulated in one round    vector<int> PScore;  //Creates a vector of integers with the purpose of storing the Player's Score, Ptotal};//Defines the constructor    Player::Player(int Ptotal){    m_Score=Ptotal;    //Sets int score to int m_Score;    Ptotal=0;    PScore.empty();}//End of constructor definition//Defines the Roll() functionint Player::Roll()//This function rolls the die and returns a value{vector<int>::const_iterator iter;  srand(time(0)); //Seed random number generator based on current timeRtotal==0;char again; //Creates a char value to determine whether or not the player wishes to roll again      do       {      int randomNumber = rand(); //Generate random number      int die = (randomNumber % 6) + 1; //Get a number between 1 and 6      cout << "\nYou rolled a " << die << endl;            if (die == 1)  //If the die was a 1...      {            cout << "\nPig! Your score for this round is lost.";  //Then the round's value is lost            Rtotal = 0;      }            //If the die did not equal 1 the current round's score is calculated      else      {      vector<int> RScore;  //Creates a vector of integers with the purpose of storing the sum of the rolled values, RScore      RScore.empty();      //Empties the vector before use      RScore.push_back(die);      //Adds the die's value to the vector      for (iter = RScore.begin(); iter != RScore.end(); ++iter)      //Sets the iterator to the beginning of the vector and cycles through it            Rtotal += (*iter);      //Adds the sum of the iterator to total            cout << "\nYour score for this round is:" << Rtotal;  //Displays the round's total score      }      cout << "\nWould you like to roll? (Y/N)\n";  //Prompts the user to roll again      cin >> again;      } while (again == 'y');            cout << "\nThen you hold.";  //If the player's response was not y, then the player holds            return Rtotal;}//End of the Roll() function//Defining the GetScore() functionint Player::GetScore(){    vector<int>::const_iterator iter;      PScore.push_back(Rtotal);      //Adds the round's total value (Rtotal) to the vector      for (iter = PScore.begin(); iter != PScore.end(); ++iter)      //Sets the iterator to the beginning of the vector and cycles through it            Ptotal += (*iter);      //Adds the sum of the iterator to total       cout << "\nYour score is: " << Ptotal;    return Ptotal;}//End of GetScore() function definition//Defining the DisplayScore() functionvoid Player::DisplayScore()//This function displays the score and then shows a message either advising or congratulating the player{cout << "Your score is " << Ptotal << ".";    if (Ptotal <=99)    {        if (Ptotal == 0)                cout << "\nOink oink!\n\n";        if (Ptotal > 0  && Ptotal <= 20)                cout << "\nMaybe you should take less chances.\n\n";        if (Ptotal > 20 && Ptotal <= 40)                cout << "\nNow you're showing some progress.\n\n";        if (Ptotal > 40 && Ptotal <= 60)                cout << "\nAlmost...\n\n.";        if (Ptotal > 60 && Ptotal <= 80)                cout << "\nGo big or go home!\n\n";        if (Ptotal > 80 && Ptotal <= 99)                cout << "\nYou're so close you can almost taste the bacon!\n\n.";    }    else    {        cout << "\nCongratulations! You won!\n\n";    }}//End of DisplayScore() function definition//End of the Player classint main(int argc, char *argv[]){  Player A;  //Creates an object in the player class named A  do  //While A's score is << 99, the following gameplay loop executes  {  A.Roll();  A.GetScore();  A.DisplayScore();  } while (A.Ptotal <=99);    cout << "\nGame Over!";    system("PAUSE");	  return 0;}


Don't mind all the comments, like I said, it's for a school project and I have to comment every little thing to explain my code fully.

Once the mechanics of the game are down I'm going to implement a system to use the player's entered name, A isn't permanent. ;)
Not a bad use of classes! Here's your problem, in Roll(): Rtotal==0;
That should be Rtotal=0; It's making a comparison, and you aren't storing the return value, so it's no problem for the compiler, however, you can't notice it because of this, a common problem you'll come across. Also, you seem to be declaring RScore (the vector) in every loop of the do-while loop. This is probably going to create a problem. Just declare it once before the loop.

Good luck,
Tim
The other problem is that the variable Ptotal is declared twice.
In the constructor, you are initializing the parameter Ptotal to 0, but the Ptotal member variable is not getting initialized. The parameter to the constructor should have a different name from the member variable.
The biggest problem I have now is in regards to the random number generator.

What happens is that when the program encounters a 1, it breaks the loop and skips to the next player's turn in the while loop.

The problem is that the random number generator isn't perfect, I think (basic rand(), srand(0) functions), so it spits out the same number, reduced to a 1, about 40 times in a second.

Is there a way to avoid this?

I could insert System("pause") lines before player B's turn begins, but that's kind of a low tech, unattractive solution.

Any ideas?

Edit:

Nevermind, I added a sleep(x) line.
It pauses the system enough to at least reduce the looping to 1-3 instances.

[Edited by - berzerker4734 on January 2, 2006 5:13:44 PM]
To clear the vector, use vector.clear() - vector.empty() returns true/false depending on if there is something in the vector. So you're never emptying out your vector like you think.
int Player::Roll()//This function rolls the die and returns a value{vector<int>::const_iterator iter;  srand(time(0)); //Seed random number generator based on current time


I see this mistake fairly often. You need to call srand ONCE per run of the program. So don't put srand in your roll function, put it in the constructor, or at the start of main. Just someplace where it will only be called One Time during the program and not every time you want a new number.

Why? Well it's simple. time(0) returns the current time in seconds. So if you call time(0) more than once a second (easily done with a computer) it will return the same number. This means you seed the RNG with the exact same number in a row. And then you get the exact same 'random' number as a result. This is why they call them 'psuedo' random numbers because they aren't really random at all.

This explains why putting Sleep(x) worked. You halted the program long enough that an entire second passed allowing you to seed the generator with a different number.

Although sometimes you may want to run the program and get the same set of 'random' numbers at this stage I'll guess that isn't what you're going for. Hope this helps.

C++: A Dialog | C++0x Features: Part1 (lambdas, auto, static_assert) , Part 2 (rvalue references) , Part 3 (decltype) | Write Games | Fix Your Timestep!

This topic is closed to new replies.

Advertisement