We will create here a clone of the game Reversi for Windows Mobile using C# and the .NET Compact Framework 3.5. The Compact Framework is a subset of the .NET framework for devices that run Windows CE. Applications that use the Compact Framework are developed in pretty much the same way as normal Windows applications. Using the CF, the entire application was written in a few hours.
Reversi is an old game that was created in 1883 by Lewis Waterman. The game is played on an 8x8 board with 64 tiles that are black on one side and white on the other. The game starts with 4 tiles in the center of the board, two black and two white. Each player takes a turn placing a tile on the board. A player can only place a tile on the board if the move is valid. For the move to be valid, there must be an adjacent enemy tile and another player tile in a straight line behind it. All the enemy tiles in the line get flipped and belong to the player that made the move. The picture below shows all the possible black moves and the affected tiles.
If there are no valid moves on the board, then a player can be skipped. The game goes on until the board is filled or there are no valid moves for both players. The player with the most tiles on the board wins. You can learn more about Reversi from this Wikipedia page: http://en.wikipedia.org/wiki/Reversi.
As you can see, Reversi is an extremely simple game. The game code consists of a few files with most of the action in Game.cs. The game board is a simple two dimensional array of bytes. Each byte in the array represents the player that occupies the position. Below is the method used to make a move in the game. The method takes the location and the player that is moving. It returns
true if the move is successful. If the move is valid, we update the location on the board and set the player.
public bool Move(Point position, Player player)
// Not the current players move so ignore.
if (_currentPlayer != player)
// The move is outside the board.
if (position.X >= _board.BoardWidth ||
position.Y >= _board.BoardHeight)
// Already a player in that position.
if (_board[position.X, position.Y].Player != Player.NotSet)
bool validMove = false;
validMove |= UpdateDirection(position, Direction.East, player);
validMove |= UpdateDirection(position, Direction.North, player);
validMove |= UpdateDirection(position, Direction.NorthEast, player);
validMove |= UpdateDirection(position, Direction.NorthWest, player);
validMove |= UpdateDirection(position, Direction.South, player);
validMove |= UpdateDirection(position, Direction.SouthEast, player);
validMove |= UpdateDirection(position, Direction.SouthWest, player);
validMove |= UpdateDirection(position, Direction.West, player);
_board[position.X, position.Y] = new Position(player);
Below are the
CheckDirection methods. The
UpdateDirection checks to see if the current move will affect any cells in the specified direction. The endpoint output parameter will have the coordinates of the last affected cell. The
UpdateDirection method calls
CheckDirection and will update all the cells in a straight line from the move position to the endpoint position. These three methods make up most of the game logic.
private bool UpdateDirection(Point position, Direction direction, Player player)
if (CheckDirection(position, direction, player, out endPoint))
modifiedPositions = GetPositions(position, endPoint);
foreach (Point p in modifiedPositions)
_board[p.X, p.Y] = new Position(player, 0);
public bool CheckDirection(Point point, Direction direction,
Player player, out Point endPoint)
Point directionMod = GetDirectionModifier(direction);
int xMod = directionMod.X, yMod = directionMod.Y;
int x = point.X + xMod, y = point.Y + yMod;
Player otherPlayer = player == Player.PlayerOne ?
Player.PlayerTwo : Player.PlayerOne;
bool hasOther = false;
while (x > -1 && x < _board.BoardWidth &&
y > -1 && y < _board.BoardHeight)
currentPlayer = _board[x, y].Player;
if ( currentPlayer == Player.NotSet )
else if ( currentPlayer == otherPlayer )
hasOther = true;
else if ( currentPlayer == player )
endPoint = new Point(x-=xMod, y-=yMod);
endPoint = Point.Empty;
x += xMod;
y += yMod;
endPoint = Point.Empty;
We use GDI to render the game board. To draw the board, we simply iterate through all the board positions, draw a square, and then draw a black or white circle if a player is in the current position. We draw the game board on a backbuffer image and then draw that image on to the screen.
const float circleReduce = .2F;
Position positions = _game.Board.Data;
int boardWidth = _game.Board.BoardWidth,
boardHeight = _game.Board.BoardHeight;
int x = 0, y = 0;
for (int i = 0; i < positions.Length; i++)
positionRectangle = new Rectangle(
graphics.DrawRectangle(new Pen(Color.Black, 2),
player = positions[i].Player;
Rectangle playerPosition = positionRectangle;
if (player != Player.NotSet)
playerPosition.Inflate(-(int)(positionRectangle.Width * circleReduce),
-(int)(positionRectangle.Height * circleReduce));
new SolidBrush(player == Player.PlayerOne ? Color.Black : Color.White),
if (i != 0 && ((i + 1) % boardWidth) == 0)
x = 0;
y += (int)_positionSize.Height;
x += (int)_positionSize.Width;
For input, we subscribe to the
OnClick event of the host control. We then convert the screen coordinates in to board coordinates and call the
Move method on the game instance.
Point translatedPoint = TranslatePoint(
private Point TranslatePoint(Point point)
int x = (int)((point.X) / _positionSize.Width),
y = (int)((point.Y) / _positionSize.Height);
return new Point(x, y);
I did not really have much change to work on the AI. Currently, the computer will make the first available move. Later on, maybe will implement something better.
The latest version of the CF includes the
SoundPlayer class. We use this class to play the game sounds. There are four game sounds: game start sound, move sound, invalid move sound, and skipped turn sound. The sounds for this game were generated using sfxr. It is a freeware application used to generate sounds for video games. If you need some quick sounds for a game you are developing, I suggest you check it out: http://www.cyd.liu.se/~tompe573/hp/project_sfxr.html.