Program #4: Tic-Tac-Toe

Skills: 2D arrays, mouse input.

Tic-Tac-Toe and Two-dimensional arrays

The children's game of Tic-Tac-Toe is so simple that once a player learns the rules, he should never lose. If both players know the rules, every game should be a draw. A way to make Tic-Tac-Toe much more interesting is to expand the game board. We will expand the game board from a 3x3 board to a 20x20 board. We will also require that to win, a player must get five X's or O's in a row.

The Board

The playing board (on the screen) will consist of a 20x20 grid, with each cell in the grid is 23x23 white pixels, and a single black pixel on all four sides of each cell. You may use the following image:

This grid is 481 pixels by 481 pixels ((1 black pixel + 23 pixels) *20 plus the rightmost column of black pixels). The X locations as you move across a row are 1 (need to skip the black pixel in column 0), 25 (1 black pixel, 23 white pixels, and another black pixel all come before it), 49 (1 black, 23 white, 1 black, 23 white, 1 black = 49 pixels that precede it), 73, etc. The Y locations as you move down a row are the same: 1, 25, 49, 73, etc. Display the board in the center of the screen (note that it is actually one pixel taller than your screen, but that extra pixel is just a black border pixel, so we won't worry about it). You may set its color to any color you choose, as long as the grid lines are easily visible. Copy this image to the clipboard and paste it into Paint.NET. Verify that it is 481x481 pixels. If it is not, be sure to resize it.

Game States

This game will have three states: PlayerXMove, PlayerOMove, and GameOver. The game will begin in the PlayerXMove state.

The Cells

We are going to implement our game board as a 2D array (20x20) of 1-character strings. A cell in the array can hold one of several things, but initially all of the cells in the array will hold blanks. A cell may hold a blank, an "X", or an "O".

You may use the following images, each of which is 23x23 pixelsso it should fit inside of the grid lines. The backgrounds are transparent.Copy the images to the clipboard and paste them into Paint.NET. Double-check to make sure they are 23x23. If they are not, resize them.

When a player clicks on an empty cell on the playing screen, we will use the screen coordinates to determine which row and column they correspond to in the array, and copy an "X" or an "O" into the corresponding array location.

Player Input

We will not use the gamepad in this game. All input will be from the mouse or the keyboard.

Player One (X)

When the game starts, it will be in the PlayerXMove state.

The first player to move will always be the "X" player. When it is the X player's turn, he will use the mouse and click where he wants to put an X.

There are several possibilities:

(1)The player clicks off of the 481x481 grid. If this happens, ignore the click and play an unpleasant sound.

(2)The player clicks on the grid, but the cell is already occupied with an "X" or an "O". If this happens, ignore the click and play another unpleasant sound.

(3)The player clicks on the grid, and the cell is empty. This is a valid move. Put an "X" in the corresponding array location. Change the game state to PlayerOMove.

You can search for "free sound effects" on the Internet for your sounds.

When player X makes a valid move, change the game state to PlayerOMove. Display whose turn it is on the screen at all times (e.g. "X's move").

Player Two (O)

When it is player two's turn, he will also use the mouse to determine where to put the O. Follow the same rules for player O as for player X, except when player O makes a valid move, change the game state to PlayerXMove.

Ending the Game

After every move, check to see if a player has won. A player wins if any of the following is true:

  • The player has 5 in a row horizontally.
  • The player has 5 in a row vertically.
  • The player has 5 in a row slanting diagonally down.
  • The player has 5 in a row slanting diagonally up.

When a player wins, display a large message on the screen that says either "X wins!" or "O wins!"Move to the GameOverstate and wait for one of the players to press the Escape key to end the game. This is the only keyboard input we will use.

Your Update method

I will write your Update method for you:

// Allows the game to exit

if (Keyboard.GetState().IsKeyDown(Keys.Escape))

this.Exit();

if (gameState == GameState.PlayerOMove || gameState == GameState.PlayerXMove)

{

getMove();

if (gameIsWon("X"))

{

gameOverMessage = "Game over. X wins!";

gameState = GameState.GameOver;

}

if (gameIsWon("O"))

{

gameOverMessage = "Game over. O wins!";

gameState = GameState.GameOver;

}

}

base.Update(gameTime);

The getMove method

The getMove method does the following:

  • Checks to see if the mouse's left button has moved from the Released state on the previous tick to the Pressed state on this tick. If it has not just been pressed, do nothing and return.
  • If the mouse's left button has been pressed, see if it is off of the playing area. If so, play an unpleasant sound and return.
  • If the mouse's left button has been pressed and is on the playing area, check to see if the cell that it is on is occupied with an X or an O. If so, play an unpleasant sound and return.
  • If the mouse's left button has been pressed and is on the playing area and the cell it is over is unoccupied, move the appropriate string ("X" or "O") to the cell and switch to the next state (if currently in PlayerXMove state, move to the PlayerOMove state, and if currently in the PlayerOMove state, move to the PlayerXMove state).
  • After each move, you must see if there is a winner (see the gameIsWonfunction below).

Your gameIsWonfunction

This is a Boolean function (it will return true or false). Pass it a string (either "X" or "O") so it knows which player it is checking for. If the parameter is "X", look for 5 X's in a row, and if the parameter is an "O", look for 5 O's in a row. This function returns true if the player has five in a row, and false if he does not.A relatively easy way to determine if a player has won is to do the following.

  1. Check all rows. Start with row 0, but go from column 2 to column 17 (skip columns 0 and 1, and skip columns 18 and 19).For each column value, check the two cells to its left, the cell itself, and the two cells to its right. Like this:
  2. Check all columns. Start with column 0, but go from row 2 to row 17 (skip rows 0 and 1, and skip rows 18 and 19). For each row value, check the two cells above it, the cell itself, and the two cells below it.
  1. Check the down diagonals. Start in row 2 and column 2 (this will leave a 2-cell border at the top and at the left) and work your way through each cell in the 2D array (except for the two cells on each border), but stop when you get to row 17 and column 17 (this will leave a 2-cell border at the bottom and at the right).
  2. Check the up diagonals. Start in row 2 and column 2 (this will leave a 2-cell border at the top and at the left) and work your way through each cell in the 2D array (except for the two cells on each border), but stop when you get to row 17 and column 17 (this will leave a 2-cell border at the bottom and at the right).

If all five cells have the same value in any one of the above cases, then the player has won. If the player has won, return true. If the player has not won, return false.

Note that the two rows above the center cell above are Row-1 and Row-2 and the two rows below the center cell are Row+1 and Row+2. The columns to the left of the center cell above are Col-1 and Col-2. The columns to the right of the center cell above are Col+1 and Col+2.

The code for checking all five locations in all four directions may be a little tedious, but it is not hard.

11/7/2018HW05--2014--2DArrays-MouseInput--Tic-Tac-Toe.docxPage 1 of 5