• Advertisement
Sign in to follow this  

Making Pig in C++

This topic is 4433 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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

Share this post


Link to post
Share on other sites
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 total
A variable to hold the random dice roll.
Some way/variable to figure out who's turn it is

while ( both players are less than a hundred points){

figure out whose turn it is
Reset 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 loop
Else, add the dice to the turn's running total. Then prompt if they want to have another go


}end while

}end while

Since 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.

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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 :)

Share this post


Link to post
Share on other sites
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 player
private: //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() function
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
Rtotal==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() function
int 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() function
void 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 class

int 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. ;)

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
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.

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites
Thank all of you who replied very much, you pointed out some of my obvious mistakes and made this entire process much much more bearable. Hopefully my game goes over well with my school board. It's the equivalent of a thesis project.

For those who are interested, this is the current, finished product:

//Pig 1.0 - A simple, text based version of the dice game Pig
//Programmed by: Devin Gray
//Rules of Pig courtesy of www.wikipedia.com

//Design Notes

// 01/02/2006 - Pig 1.0 Completed

#include <iostream>
#include <stdlib.h>
#include <ctime>
#include <vector>
#include <string>
#include <algorithm>

using namespace std;

string Aname; //Global string Aname, or Player A's name
string Bname; //Global string Bname, or Player B's name
string Rname; //Global string Rname, or Returned name.

void Instructions();
void About();

class Player
{
public: //Begin the public access level section
Player(int Ptotal=0); //Declares the constructor
string GetName();
int Roll(); //Creates a random number from 1-6 and determines whether or not Rtotal is added to PScore
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
void Victory(); //Declares the function Victory(), which displays a congratulatory message when the player wins
int Ptotal; //Declares the integer Ptotal, which holds the total score of the player
int m_Score; //Declares the integer m_Score
string name; //Stores the result of GetName()
private: //Begin the private access level section
short int turns; //Declares the integer rolls, which holds the number of rolls it took for a player to win
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
vector<int> RScore; //Creates a vector of integers with the purpose of storing the sum of the rolled values, RScore
};


//Defines the constructor
Player::Player(int Ptotal)
{
vector<int> PScore;
vector<int> RScore;
RScore.clear();
PScore.clear();
turns = 0;
m_Score = Ptotal; //Sets int score to int m_Score
}
//End of constructor definition

//Defines the GetName() function
string Player::GetName()
{
cout << "\nWhat is your name?\n";
string name;
cin >> name;
cout << "\nGood luck, " << name << ".";
Rname = name;
return name;
}
//End of the GetName() function definition

//Defines the Roll() function
int Player::Roll()
//This function rolls the die and returns a value
{
RScore.clear(); //Empties the vector before use
vector<int>::const_iterator iter;

Rtotal=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 << "You rolled a " << die << endl;

if (die == 1) //If the die was a 1...
{
cout << "\nPig! Your score for this round is lost.\n"; //Then the round's value is lost
Rtotal = 0;
RScore.clear();
again == 'n';
Sleep(1500);
break;
}

//If the die did not equal 1 the current round's score is calculated
else
{
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
RScore.pop_back(); //This line clears the last element. If this does not happen, the previous round's score doubles.
//Example: 2. Score is 2. Next round, 4. Score is 10.
cout << "\n" << Rname << ", your score for this round is:" << Rtotal; //Displays the round's total score
cout << "\nWould you like to roll again? (Y/N)\n"; //Prompts the user to roll again
cin >> again;
if (again !='y' && again != 'Y')
cout << "\nThen you hold."; //If the player's response was not y, then the player holds
else
continue;
}

} while (again == 'y' || again == 'Y');
++ turns;

return Rtotal;
}
//End of the Roll() function

//Defining the GetScore() function
int Player::GetScore()
{
vector<int>::const_iterator iter;
PScore.push_back(Rtotal); //Adds the round's total value (Rtotal) to the vector
Rtotal = 0;
for (iter = PScore.begin(); iter != PScore.end(); ++iter) //Sets the iterator to the beginning of the vector and cycles through it
m_Score += (*iter); //Adds the sum of the iterator to total
PScore.pop_back(); //This line clears the last element. If this does not happen, the previous round's score doubles.
return m_Score;
}
//End of GetScore() function definition

//Defining the DisplayScore() function
void Player::DisplayScore()
//This function displays the score and then shows a message either advising or congratulating the player
{
cout << "\n" << Rname << ", your score is " << m_Score << ".";
if (m_Score <=99)
{
if (m_Score == 0)
cout << "\nOink oink!";
if (m_Score > 0 && m_Score <= 20)
cout << "\nStill a beginner.";
if (m_Score > 20 && m_Score <= 40)
cout << "\nNow you're showing some progress.";
if (m_Score > 40 && m_Score <= 60)
cout << "\nAlmost...";
if (m_Score > 60 && m_Score <= 80)
cout << "\nGo big or go home!";
if (m_Score > 80 && m_Score <= 99)
cout << "\nYou're so close you can almost taste the bacon!.";
}
else
{
cout << "\nYou broke 100!";
}
Sleep(500); //Pauses the program for 1/2 a second to make the program more legible
}
//End of DisplayScore() function definition

//Defining the Victory() function
void Player::Victory()
{
cout << "\nCongratulations, " << name << "! You won!\n\n";
cout << "\nIt took you " << turns << " turns to win!";
//Depending on how many turns it took the player to win, a message is displayed
if (turns >=1 && turns <=5)
cout << "\nIncredible!";
if (turns >=6 && turns <=10)
cout << "\nDefinitely impressive.";
if (turns >=11 && turns <=15)
cout << "\nNot bad.";
if (turns >=16 && turns <=20)
cout << "\nYou could do better.";
if (turns >=21)
cout << "\nWow, you had some really bad luck, huh?";
}

//End of the Player class

int main(int argc, char *argv[])
{
srand(time(0)); //Seed random number generator based on current time

Instructions();

Player A; //Creates an object in the player class named A
Player B; //Creates an object in the player class named B

char PlayAgain;
PlayAgain == 'y';
do
{
cout << "\n\nPlayer A,";
Aname = A.GetName(); //Sets global string Aname to the result of A's GetName() function
cout << "\n\nPlayer B,";
Bname = B.GetName(); //Sets global string Bname to the result of B's GetName() function
do //While both player's scores are <= 99, the following gameplay loop executes
{
cout << "\n\n" << Aname << ", you're up.\n";
Sleep(250); // Delays the loop for 1/4 of a second, or 250 milliseconds
Rname = Aname; //Sets global string Rname to Aname for the duration of A's turn so that A's name is displayed correctly during each function
A.Roll();
A.GetScore();
A.DisplayScore();
Rname = ""; //Sets Rname to blank space

cout << "\n\n" << Bname << ", do you think you can beat " << Aname << "'s roll?\n";
Sleep(250); // Delays the loop for 1/4 of a second, or 250 milliseconds
Rname = Bname; //Sets global string Rname to Bname for the duration of B's turn so that B's name is displayed correctly during each function
B.Roll();
B.GetScore();
B.DisplayScore();
Rname = ""; //Sets Rname to blank space
} while (A.m_Score <=99 && B.m_Score <=99); //The game loop continues as long as neither player has exceeded 100 points

if (A.m_Score >=100 && B.m_Score <=99) //If A exceeds 100 points but B doesn't then A wins
Rname = Aname; //Sets Rname to Aname
A.Victory();
if (B.m_Score >=100 && A.m_Score <=99) //If B exceeds 100 points but A doesn't then B wins
Rname = Bname; //Sets Rname to Bname
B.Victory();
if (A.m_Score >=100 && B.m_Score >=100) //If they both exceed 100 points, they tie.
cout << "You tie!";

cout << "\n\nGame Over\n\n!";
cout << "Would you like to play again? (Y/N)";
cin >> PlayAgain;
} while (PlayAgain == 'y' || PlayAgain == 'Y' );

About();

system("PAUSE");
return 0;
}

void Instructions()
{
cout << "\t***PIG****\n\n";
cout << "The goal of Pig is to reach 100 points before the other player does.";
cout << "\nEach time you roll the die points are added to your turn total.";
cout << "\nIf you choose to stop, the points are added to your score.";
cout << "\nBut if you roll a 1, then all your points for that turn are lost!";
cout << "\n\nJust how well can you throw the dice?";
}

void About()
{
cout << "\n\nPig is a MS-DOS game programmed by Devin Gray.";
}




There are probably better ways of programming it, more efficient ways, etc.
But I'm pretty proud of it considering this is my first real program :)

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
some suggestions:
1) dont include stdlib.h, include cstdlib
2) you shouldnt need the three global names, try to get rid of them
besides that, great game!

Share this post


Link to post
Share on other sites
I might have scanned thru the posts a little to fast so Im not sure this was mentioned, what you might want to do is have a general style guide to go by for your classes, for instances you have a member variable m_score, so why not have all member variable inside a class start with the prefix m_, that way when you have a member variable Ptotal it would be m_Ptotal, and having m_Ptotal=Ptotal; no longer becomes confusing.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement