15,498,622 members
Articles / Desktop Programming / Windows Forms
Article
Posted 29 May 2008

63.3K views
43 bookmarked

Peg That! A Peg Solitaire Game

Rate me:
An article on creating the classic Peg Solitaire board game

Introduction

Back when I was in college, we had to create the old game of Nim as a console application in C++. I had never created any games before, nor had I ever been exposed to any game logic. As I was creating it, I learned so many different things, and it also got me very interested in making games. Years later, I made Tic Tac Toe using C#. Well, the other day, I was eating at Cracker Barrel, and I was playing their peg game on the table. I thought it would be cool if I could create this game from scratch... so that's what I decided to do.

Planning

I really didn't do that much planning for this. I knew that I had to create a bunch of pegs, and that the player needed to be able to drag a peg from one hole to another. I created the whole game and had it working, but I knew that my game logic was really sloppy. I had a huge `switch` statement that listed every possible move, and when a player would make a move, it would check to see if it was on the list. This seemed fine at the beginning, but what if I wanted to be able to add another row on the fly. I would have to go in and add every new move to the list, and it would get real big very quickly.

So, what I decided to do was search Google for the game logic. I came across an article written by Daniel O'Brien. It was very informative, and he had even written an application in C++ that would generate all the possible solutions to the game. I figured that this would be very helpful, so I took his logic and applied it to my game. Now, my game works even better, and if I ever want to add more rows to the board, I can without any code changes.

Using the Code

I just want to give a real basic overview of the code. The source code in the project is very well commented, and should be easy to follow by adding some breakpoints on the mouse events.

The backbone of the game is the board, which is a `List<T>` that contains `BitArray`s. A `BitArray` manages a compact array of bit values, which are represented as Booleans, where `true `indicates that the bit is on (1) and `false `indicates the bit is off (0). For the game's purposes, `true `represents that a peg is present and `false `represents an empty hole. Below is the function `InitializeBoard()` that sets up a new game board:

C#
```/// <summary>
/// Initializes the board layout with all the pegs and
/// leaves one peg empty.
/// </summary>
private void InitializeBoard()
{
boardLayout = new List<BitArray>();
BitArray b;

// Add all the pegs to the board.
for (int i = 0; i < Settings.BoardSize; i++)
{
b = new BitArray(Settings.BoardSize);

for (int j = 0; j <= i; j++)
b[j] = true;

}

// Take out a single peg from the board.
boardLayout[emptyPegRow][emptyPegColumn] = false;
}```

When the player moves a peg on the board, we must:

• remove the peg from the original hole
• remove the peg that was jumped
• place the peg in the last hole

The following code makes this part possible:

C#
```/// <summary>
/// Takes a peg and jumps to the ending hole.
/// </summary>
/// <param name="move">
/// Returns the move that is taking place.
/// </param>
private void Jump(Move move)
{
Position peg = new Position(move.StartPosition);

// Flip the starting hole in the move so that it
// is now empty.
Flip(peg);

// Move the peg one hole in the specific direction.
peg += move.IncrementBy;

// Flip the next hole so that it is empty.  This is
// the peg that is being jumped.
Flip(peg);

// Move the peg one more time in the specific
// direction so that it is now in the ending hole.
peg += move.IncrementBy;

// Flip the ending hole so that it contains the peg
// that was in action.
Flip(peg);
}

/// <summary>
/// Flips a hole on the board. If the hole on the board
/// contains a peg, it will flip it to be empty. If the
/// hole on the board is empty, it will flip it to contain
/// a peg.
/// </summary>
/// <param name="hole">
/// The hole on the board to flip.
/// </param>
private void Flip(Position hole)
{
boardLayout[hole.Row][hole.Column] = !boardLayout[hole.Row][hole.Column];
}```

There is one last major thing that has to happen before the player's move can be executed: the move must be validated.

We first need to create a list of all the possible directions that a peg can be moved. Next, we need to make a list of all the possible moves using the list of directions. The following code section accomplishes this:

C#
```/// <summary>
/// The collection of the possible peg movement that
/// can take place on the board.
/// </summary>
private readonly Position[] movement = new Position[] { new Position(-1, -1),
new Position(-1, 0),
new Position(1, 0),
new Position(1, 1),
new Position(0, -1),
new Position(0, 1) };

/// <summary>
/// Gets a list of all the possible moves that can be
/// made with the current board layout.
/// </summary>
/// <returns>
/// Returns the list of possible moves.
/// </returns>
private List<Move> PossibleMoves()
{
List<Move> moves = new List<Move>();

// Iterate through each hole on the board.
for (int row = 0; row < Settings.BoardSize; row++)
{
for (int column = 0; column <= row; column++)
{
Position hole = new Position(row, column);

// If the hole on the board is occupied, skip it.
if (IsOccupied(hole))
continue;

// Iterate through each type of movement to see if
// it is a possible and valid move.
for (int m = 0; m < movement.Length; m++)
{
Position move = new Position(hole);

// The first thing we do is start at the empty hole
// and move one hole in the direction of the selected
// movement.  If the movement is valid, we check to
// make sure that the hole contains a peg.  If it does,
// we move one more hole in the direction of the selected
// movement.  If the movement is valid and the hole
// contains a peg, then this is a possible move.
if (move.Move(movement[m]) && IsOccupied(move) &&
move.Move(movement[m]) && IsOccupied(move))
{
Position direction = new Position(movement[m]);

// We reverse the direction of the move.  This is
// necessary because the player will be starting
// at an occupied hole instead of an empty one.
direction *= -1;

// Add the move to the list.
}
}
}
}

return moves;
}

/// <summary>
/// Checks to see if the position on the board is occupied
/// with a peg.
/// </summary>
/// <param name="position">
/// The position on the board to check.
/// </param>
/// <returns>
/// Returns true if the position is occupied and false if
/// the position is empty.
/// </returns>
private bool IsOccupied(Position position)
{
return boardLayout[position.Row][position.Column];
}```

Conclusion

I had a lot of fun creating this game, and I learned a bunch of stuff about game logic too. I hope that this article helped you and that you will have a good time playing the game. Also, feel free to leave any feedback you might have. If you have made changes to the game, send me the copy so I can check it out.

History

• March 30, 2009 - Version 2.0
• Enhanced graphics
• Better interface for selecting the empty peg
• May 29, 2008 - Version 1.0
• Initial version

Written By
Software Developer
United States
I received an associate degree in computer programming in 2005. At work, I create and maintain software that is used in the hospital industry all across the world. I write the software using C# and ASP.NET MVC.

 Tip `leppie`29-May-08 23:19 `leppie` 29-May-08 23:19