|
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionThis is a simple version of Yahtzee that includes a high score table. Enjoy. BackgroundThis is my second article that I have written for CodeProject, so I hope some of you find it useful or at least fun. One day, my daughter asked me if we could get Yahtzee for the computer. I thought instead of buying something, why not write it. She has beta tested it quite well, so hopefully most of the bugs have been ironed out in the process. This has took me a while to write, and if you want to see the history of how I got to where the program is now, you can see this on my website. The RulesThe full rules for the Yahtzee game can be downloaded from Hasbro's website. This version of the game will only allow one Yahtzee bonus, and does not include the Joker rules. The Game
The program is made up of four forms and two rather useful classes that do most of the work. One of these classes does all of the work for the dice that you see at the top of the form, whilst the other does all of the work checking scores. The DiceThe public void InitializeRandomRoll( int nSeed )
{
DateTime aTime = new DateTime(1000);
aTime = DateTime.Now;
nSeed += (int)(aTime.Millisecond);
RandomPick = new Random(nSeed);
}
And since the initial seed is always different, the main form has its own random number generator, and seeds the method above with the next number. Another problem in Yahtzee is, each turn you roll the dice three times. The first time, you roll all five dice. You then select some of the dice and keep them to one side. The others you put back in the cup and roll again. From the second roll, you may or may not keep some of these dice to one side, and roll whatever dice are left a third time. We need to be able to hold a dice, so that it does not roll when the roll button is pressed. So, we add a variable to hold the state of the dice. private bool m_bHoldState = false;
public bool HoldState
{
get { return m_bHoldState; }
set { m_bHoldState = value; }
}
Now, we need to make sure that if the dice is held, it does not get rolled. This is simply a matter of adding an public void Roll()
{
// If the dice is not held, roll it
if( !HoldState )
{
RollNumber = RandomPick.Next(1,7);
this.Invalidate();
}
}
Finally, the dice is drawn in black if the dice is not held, and in red if it is. The following method draws a single dot at a given point: public void DrawDot( Graphics g, Point p )
{
SolidBrush myBrush;
if( HoldState )
{
myBrush = new SolidBrush( Color.Red );
}
else
{
myBrush = new SolidBrush( Color.Black );
}
g.FillEllipse( myBrush, p.X, p.Y, dotWidth, dotWidth );
myBrush.Dispose();
}
The rest of the dice code is pretty easy to follow. Calculating The ScoreTo calculate the scores, a class was created. The class has many functions that calculate the individual scores, it also keeps a tally of the total, upper and lower scores. The algorithm used to add up the total scores of five dice when the same number is needed is shown below. The total of all of the dice that have the same number is returned to the form, or zero if none of the dice are the same as that needed. public int AddUpDice( int DieNumber, Dice[] myDice )
{
int Sum = 0;
for( int i = 0; i < 5; i++ )
{
if( myDice[i].RollNumber == DieNumber )
{
Sum += DieNumber;
}
}
return Sum;
}
The algorithms for Three of a Kind and Four of a Kind are very similar. They are based on the above algorithm, but do not know which number that the three or four of a kind are meant to be. So, two loops are used to determine if indeed three or four of the dice are the same. public int CalculateThreeOfAKind( Dice[] myDice )
{
int Sum = 0;
bool ThreeOfAKind = false;
for( int i = 1; i <= 6; i++ )
{
int Count = 0;
for( int j = 0; j < 5; j++ )
{
if( myDice[j].RollNumber == i )
Count++;
if( Count > 2 )
ThreeOfAKind = true;
}
}
if( ThreeOfAKind )
{
for( int k = 0; k < 5; k++ )
{
Sum += myDice[k].RollNumber;
}
}
return Sum;
}
The algorithm for calculating a Full House is slightly more complicated than the previous one. The basis relies on the fact that if we sort the dice numbers into ascending order, then the first two dice will be the same and the last three dice will be the same, but the second and third dice must be different. Alternatively, the first three dice will be the same and the last two dice will be the same, but the third and fourth dice must be different. This can be done in a simple Instead of returning the sum of the dice, we return a fixed score, which is 25. public int CalculateFullHouse( Dice[] myDice )
{
int Sum = 0;
int[] i = new int[5];
i[0] = myDice[0].RollNumber;
i[1] = myDice[1].RollNumber;
i[2] = myDice[2].RollNumber;
i[3] = myDice[3].RollNumber;
i[4] = myDice[4].RollNumber;
Array.Sort(i);
if( (((i[0] == i[1]) && (i[1] == i[2])) && // Three of a Kind
(i[3] == i[4]) && // Two of a Kind
(i[2] != i[3])) ||
((i[0] == i[1]) && // Two of a Kind
((i[2] == i[3]) && (i[3] == i[4])) && // Three of a Kind
(i[1] != i[2])) )
{
Sum = 25;
}
return Sum;
}
The algorithm for calculating a Large Straight is similar to that of calculating a Full House, but much simpler. The basis for the Again, instead of returning the sum of the dice, we return a fixed score, which is 40. public int CalculateLargeStraight( Dice[] myDice )
{
int Sum = 0;
int[] i = new int[5];
i[0] = myDice[0].RollNumber;
i[1] = myDice[1].RollNumber;
i[2] = myDice[2].RollNumber;
i[3] = myDice[3].RollNumber;
i[4] = myDice[4].RollNumber;
Array.Sort(i);
if( ((i[0] == 1) &&
(i[1] == 2) &&
(i[2] == 3) &&
(i[3] == 4) &&
(i[4] == 5)) ||
((i[0] == 2) &&
(i[1] == 3) &&
(i[2] == 4) &&
(i[3] == 5) &&
(i[4] == 6)) )
{
Sum = 40;
}
return Sum;
}
The algorithm for calculating a Small Straight is more complicated than the Large Straight algorithm. The basis for the Again, instead of returning the sum of the dice, we return a fixed score, which is 30. public int CalculateSmallStraight( Dice[] myDice )
{
int Sum = 0;
int[] i = new int[5];
i[0] = myDice[0].RollNumber;
i[1] = myDice[1].RollNumber;
i[2] = myDice[2].RollNumber;
i[3] = myDice[3].RollNumber;
i[4] = myDice[4].RollNumber;
Array.Sort(i);
// Problem can arise hear, if there is more than one of the same number, so
// we must move any doubles to the end
for( int j = 0; j < 4; j++ )
{
int temp = 0;
if( i[j] == i[j+1] )
{
temp = i[j];
for( int k = j; k < 4; k++ )
{
i[k] = i[k+1];
}
i[4] = temp;
}
}
if( ((i[0] == 1) && (i[1] == 2) && (i[2] == 3) && (i[3] == 4)) ||
((i[0] == 2) && (i[1] == 3) && (i[2] == 4) && (i[3] == 5)) ||
((i[0] == 3) && (i[1] == 4) && (i[2] == 5) && (i[3] == 6)) ||
((i[1] == 1) && (i[2] == 2) && (i[3] == 3) && (i[4] == 4)) ||
((i[1] == 2) && (i[2] == 3) && (i[3] == 4) && (i[4] == 5)) ||
((i[1] == 3) && (i[2] == 4) && (i[3] == 5) && (i[4] == 6)) )
{
Sum = 30;
}
return Sum;
}
The algorithm for Yahtzee is the same as for Three of a Kind and Four of a Kind. Again, instead of returning the sum of the dice, we return a fixed score, which is 50. public int CalculateYahtzee( Dice[] myDice )
{
int Sum = 0;
for( int i = 1; i <= 6; i++ )
{
int Count = 0;
for( int j = 0; j < 5; j++ )
{
if( myDice[j].RollNumber == i )
Count++;
if( Count > 4 )
Sum = 50;
}
}
return Sum;
}
We do not really need to do any checking when calculating the Chance score, we simply add up the dice and return it as a number. public int AddUpChance( Dice[] myDice )
{
int Sum = 0;
for( int i = 0; i < 5; i++ )
{
Sum += myDice[i].RollNumber;
}
return Sum;
}
Counting the scoresSo that we know when the game is over, we keep count of how many scores have been allocated. As there are only fourteen possible scores, we know when to stop. The score count is kept in the following variable: private int ScoreCount = 0;
After each score is allocated, the if( ScoreCount == 14 )
{
DialogResult result;
// Displays the MessageBox.
result = MessageBox.Show( "Your Score is " + TotalScore.Text + ".
Would You like to play again?",
"End Of Game",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question );
if( result == DialogResult.Yes )
{
// Reset Everything
. . .
}
else
{
this.Close();
}
}
Enjoy the game!
|
|||||||||||||||||||||||||||||||||||||||||||