Goals
- Put together everything we've learned so far!
- Create many standard gameplay devices: game board, game state, textual information, user interaction sensing.
Tic-Tac-Toe
We are going to create a program to play Tic-Tac-Toe, a two-player game that is played on a 3 x 3 grid where a player wins by placing three of his or her markers in a row. If you are unfamiliar with the game or need a refresher, feel free to browse the Wikipedia article.
Step 1: Design the Game Board
Design your game layout. The image shown on the right is just an example, and we encourage you to tweak the layout and look to your liking. At minimum, you will need the following:
- 3 x 3 grid of squares for the game board.
- An indication of whose turn it is.
- An indication of the game result.
- A reset button of some sort.
We suggest that you create a separate function to draw your board, possibly named drawBoard()
, that will be called from draw()
.
If you would like to, you can also parameterize this function to make your code more flexible should you choose to later alter your layout.
Step 2: Design Your Game State
We will need to declare and initialize some variables to keep track of the current "state" of the game. You will definitely need to track the state of the board (i.e. who has played what and where), which we suggest you do using an array of size 9. The following questions are meant to help you think about the state of the game, though the exact implementation is up to you:
- How do you know whose turn it is?
- How many different "states" can each square of your board be in?
- How many different "states"/"stages" can the game be in? (e.g. game ongoing, Player 1 wins, etc.)
Step 3: Display the Board State
Before we implement user input, let's make sure we can display the correct symbols on our grid. You should have an array of size 9 that holds the current state of the board. We recommend using the following layout to relate the board to the array:
Array index: [ 0 | 1 | 2 ] [ 3 | 4 | 5 ] [ 6 | 7 | 8 ]
That is, element 4 of your array holds the current state of the middle square of your board, and element 5 of your array holds the current state of the square at row 2, column 3.
Now we need to display symbols to show the player moves ('O' for Player 1, 'X' for Player 2).
Our suggestion is to use a separate char
array:
char[] symbols = {' ','O','X'};
With this in your code, then symbols[0]
will display a space (no symbol), symbols[1]
will display an 'oh', and symbols[2]
will display an 'ex'.
Make sure that this works well in combination with the values you store in your array.
To do the actual display on your drawing canvas, we recommend using the text()
function inside of nested for-loops.
The for-loop variables will help you calculate the correct coordinates to pass to text()
, but you will also need to use them to access the correct index of your game board state.
Step 4: User Click Recognition
We can recognize user clicks using the mousePressed()
function in combination with the values of mouseX
and mouseY
.
If you are unsure about how to proceed, see the "Building an App" lecture or the "Birthday Visualization" lab.
It is easiest to start with the Reset button.
Create a separate reset()
function to call when the user clicks within the Reset button region of the drawing canvas.
This should set all of the game state variables to the values they would hold at the very beginning of a game of Tic-Tac-Toe.
When the user clicks within the game board, your program should correctly identify which square (0-8) was clicked, similar to how the Birthday Visualization recognized which month and day was being hovered over.
Write some test code so that you can verify correct behavior using either println()
or text()
.
Once that is confirmed to be working correctly, you can move on to "playing that square." Remember that we only want to update our game board if (1) the user clicked on a board square and (2) that square hasn't been played previously. Similarly, when do we want to change players?
Step 5: Checking for Endgame
After each valid play, your program should check to see if the end of the game has been reached (a player wins or there is a draw). Create a separate function to do this.
Endgame conditions can be checked using just the state of the game board. There are certainly some more clever ways to do this, but we are fine with the "brute force" method of checking every possible winning combination one-by-one.
- How many different ways can you win in Tic-Tac-Toe?
- How do you check for a winning combination?
- How do you differentiate between a Player 1 and Player 2 win?
- How do you know if a Draw has been reached?
Once the endgame has been reached, your game state should be updated to reflect this. How will this affect gameplay? Should the user still be allowed to play squares on the game board? Note: we still want to allow the user to click the Reset button while at the endgame and then start a new game.
And there you have it! You've put together a working game! Play a few rounds with a partner or friend in order to make sure your program behavior matches what you expect to happen. This is a process called testing that is really important. Make sure you take your program through every possible game state!
Submission
- Make sure that your name (and your partner's name) is included in your file.
- Make sure that most of your lines of code have comments so that someone else can understand it.
- Make sure that the game no longer accepts plays once the endgame is reached.
- Submit your finished
.pde
file from Step 5 to the Canvas assignments page.