Introduction
I enjoy having some simple, small games on my PDA to offer a few minutes of distraction when needed. PocketDice, a variant of the dice game Yacht, is offered here as an entry for the Mobile Development Competition and to offer PocketPC owners a few free diversionary minutes. Code examples for persisting high scores and displaying online help are presented following a description of the game.
Playing the Game
PocketDice is a variant on the dice game Yacht with the twist that the dice values are suited like playing cards (clubs, hearts, diamonds, and spades). On each turn the player is allowed up to three rolls of five dice. On a second or third roll, the player may re-roll any or all of the dice. Clicking the Roll button rolls all "unlocked" dice. Tapping a die toggles whether the die is locked or unlocked.
Following any of the three rolls, the player may choose to score by tapping any available scoring box. A scoring box may be used only once in a game. If following a third roll, the player must choose an available scoring box. Points are awarded for a score according to the following table:
Scoring Option
|
Description
|
Aces
|
Score one point for each Ace
|
Twos
|
Score two points for each Two
|
Threes
|
Score three points for each Three
|
Fours
|
Score four points for each Four
|
Fives
|
Score five points for each Five
|
Sixes
|
Score six points for each Six
|
3 of a Kind
|
Score the sum of the five dice values if at least three dice share the same value; if not, score 0
|
4 of a Kind
|
Score the sum of the five dice values if at least four dice share the same value; if not, score 0
|
Full House
|
Score 25 if three of the dice share a value (i.e. 3 of a Kind) and the other two share a value (i.e. a pair)
|
Straight
|
Score 40 if the five dice represent a straight in poker; in this variant, an Ace may be treated as low or high, so possible straights include A-2-3-4-5, 2-3-4-5-6, and 3-4-5-6-A
|
Flush
|
Score 40 if the five dice share the same suit; otherwise score 0
|
Chance
|
Score the sum of the five dice values.
|
Reds
|
Score the sum of the five dice values provided they all share a red suit; otherwise score 0
|
Blacks
|
Score the sum of the five dice values provided they all share a black suit; otherwise score 0
|
5 of a Kind
|
Score 50 points if all five dice show the same value; if not, score 0
|
Straight Flush
|
Score 80 if the five dice share the same suit and form an A-2-3-4-5, 2-3-4-5-6, or 3-4-5-6-A straight; score 0 otherwise
|
In addition to the points above, a Bonus value of 35 points is added if the sum of the Aces through Sixes scores total 63 or more. When scoring, an Ace is considered to have a value of one.
The game is over when all scoring boxes have been used.
Code Structure
The project, targeting the .NET Compact Framework, includes four form classes and several other supporting classes.
Forms and Control Classes
The following forms comprise the user interface for the application:
frmMain
|
Contains the application entry point and functions as the game playing surface.
|
frmHighScores
|
Dialog for displaying recorded high scores.
|
frmAbout
|
Application about box; uses the reflection method Assembly.GetName() for displaying version information.
|
frmInputBox
|
Dialog for requesting text entry from the user.
|
Supporting the main form are two custom control classes: SingleDie
and ScoringBox
. Each overrides OnPaint()
for its custom display.
Application Data
High Scores for the application are persisted in an XML file through functions in the Data
class. The Data
constructor attempts to load the scores from the persisted file with an XmlTextReader
; if the file doesn't exist, a blank score array is created.
public class Data
{
const int kMAX_HIGHSCORES = 10;
const string kDATA_FILE = @"\Program Files\PocketDice\data.xml";
private HighScoreRecord[] _list;
. . .
public Data()
{
_list = new HighScoreRecord[kMAX_HIGHSCORES];
int count = -1;
XmlTextReader xml = null;
FileStream stream = null;
try
{
stream = new FileStream(kDATA_FILE, FileMode.Open);
xml = new XmlTextReader(stream);
xml.MoveToContent();
while (xml.Read())
{
switch (xml.Name)
{
case "HighScore":
count++;
if (count < kMAX_HIGHSCORES)
{
_list[count] = new HighScoreRecord(xml);
}
break;
}
}
count++;
if (count < kMAX_HIGHSCORES)
{
for (int i=count; i<kMAX_HIGHSCORES; i++)
{
_list[i] = new HighScoreRecord();
}
}
}
catch (System.IO.FileNotFoundException)
{
for (int i=0; i<kMAX_HIGHSCORES; i++)
{
_list[i] = new HighScoreRecord();
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(
ex.ToString(), "Error Loading High Scores");
for (int i=0; i<kMAX_HIGHSCORES; i++)
{
_list[i] = new HighScoreRecord();
}
}
finally
{
if (xml != null) xml.Close();
if (stream != null) stream.Close();
}
}
. . .
}
The HighScoreRecord
class, also found in the source file Data.cs, contains a constructor which takes the XmlTextReader
as a parameter.
public HighScoreRecord(XmlTextReader xml)
{
_score = int.Parse(xml.GetAttribute("score"));
_name = xml.GetAttribute("name");
_date = XmlConvert.ToDateTime(xml.GetAttribute("date"), "yyyy-MM-dd");
}
A Data
object is created in the Load
event handler for frmMain. Its Save()
method is then called in frmMain's Closing
event handler, persisting the scores with an XmlTextWriter
:
public class Data
{
. . .
public void Save()
{
SortHighScores();
XmlTextWriter xml = null;
try
{
xml = new XmlTextWriter(kDATA_FILE, System.Text.Encoding.ASCII);
xml.WriteStartDocument();
xml.WriteStartElement("HighScores");
for (int i=0; i<_list.Length; i++)
{
_list[i].WriteXmlRecord(xml);
}
xml.WriteEndElement();
xml.WriteEndDocument();
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.ToString());
}
finally
{
if (xml != null) xml.Close();
}
}
}
Called in the Save()
method, the HighScoreRecord
object's WriteXmlRecord()
method takes care of persisting its high score properties:
public class HighScoreRecord
{
...
public void WriteXmlRecord(XmlTextWriter xml)
{
xml.WriteStartElement("HighScore");
xml.WriteStartAttribute("score","");
xml.WriteString(_score.ToString());
xml.WriteEndAttribute();
xml.WriteStartAttribute("name","");
xml.WriteString(_name);
xml.WriteEndAttribute();
xml.WriteStartAttribute("date", "");
xml.WriteString(_date.ToString("yyyy-MM-dd"));
xml.WriteEndAttribute();
xml.WriteEndElement();
}
}
Points of Interest
When considering how to display online help, I decided that I wanted some formatting and elected to use an HTML file. The article Launching Applications and Resuming Processes [^], from the .NET Compact Framework QuickStart Tutorial [^], was very useful in offering a means for launching a process. I added a function OpenWebPage()
and wrapped it in the Launcher
class of the project. This is used to open the HTML file containing game instructions.
Summary
PocketDice, a variant of the dice game Yacht for PocketPC, provides a simple diversion, taking only a few minutes to play a full game. Code samples in the article demonstrate the use of XmlTextReader
and XmlTextWriter
objects for persisting game data in an XML file, and code borrowed from the .NET Compact Framework QuickStart Tutorial to launch processes offers a solution for displaying an HTML file for online help. Enjoy the game!