Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Reversi for Windows Mobile

0.00/5 (No votes)
13 May 2009 1  
The game Reversi for Windows Mobile using the Compact Framework.

Introduction

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.

Background

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.

ReversiGame/ReversiMoves2.jpg

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.

Game code

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)
    {
        return false;
    }
    // The move is outside the board.
    if (position.X >= _board.BoardWidth || 
        position.Y >= _board.BoardHeight)
    {
        return false;
    }
    // Already a player in that position.
    if (_board[position.X, position.Y].Player != Player.NotSet)
    {
        return false;
    }
    
    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);
    if (validMove)
    {
        _board[position.X, position.Y] = new Position(player);
        TogglePlayer();
    }
    return validMove;
}

Below are the UpdateDirection and 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)
{
    IEnumerable<Point> modifiedPositions;
    Point endPoint;

    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);
        }
        return true;
    }
    return false;
}

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;
    Player currentPlayer;
    bool hasOther = false;

    while (x > -1 && x < _board.BoardWidth &&
            y > -1 && y < _board.BoardHeight)
    {
        // Get the current player.
        currentPlayer = _board[x, y].Player;

        // Got to the end and no match.
        if ( currentPlayer == Player.NotSet )
        {
            break;
        }
        else if ( currentPlayer == otherPlayer )
        {
            hasOther = true;
        }
        else if ( currentPlayer == player )
        {
            if (hasOther)
            {
                endPoint = new Point(x-=xMod, y-=yMod);
                return true;
            }
            endPoint = Point.Empty;
            return false;
        }

        // Move to next position.
        x += xMod;
        y += yMod;
    }
    endPoint = Point.Empty;
    return false;
}

Render code

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;
// Get the positions and board width,height
Position[] positions = _game.Board.Data;
int boardWidth = _game.Board.BoardWidth, 
    boardHeight = _game.Board.BoardHeight;
Rectangle positionRectangle;
int x = 0, y = 0;

// Draw the background.
TransparentControl.PaintBackground(graphics, _renderArea);

Player player;
for (int i = 0; i < positions.Length; i++)
{
    // Get the position rectangle.
    positionRectangle = new Rectangle(
            x, y,
            (int)(_positionSize.Width),
            (int)(_positionSize.Height));

    // Draw the grid.
    graphics.DrawRectangle(new Pen(Color.Black, 2),
                           positionRectangle);

    // Get the player.
    player = positions[i].Player;
    Rectangle playerPosition = positionRectangle;

    // Render any circles for any positions that are occupied.
    if (player != Player.NotSet)
    {
        playerPosition.Inflate(-(int)(positionRectangle.Width * circleReduce), 
                               -(int)(positionRectangle.Height * circleReduce));
        graphics.FillEllipse(
            new SolidBrush(player == Player.PlayerOne ? Color.Black : Color.White),
            playerPosition
            );
    }

    // Move to next position.
    if (i != 0 && ((i + 1) % boardWidth) == 0)
    {
        x = 0;
        y += (int)_positionSize.Height;
    }
    else
    {
        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(
      _renderArea.PointToClient(Control.MousePosition));

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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here