Java Programming Challenge: Adding Class to the Simple Tic-Tac-Toe Program

By Doug Lowe

In this challenge, you improve your Tic-Tac-Toe game by adding a Java programming class, which allows the program to make a rudimentary effort toward strategy when determining the computer’s moves.

In Java Programming Challenge: A Simple Tic-Tac-Toe Game you’re challenged to write a program to play the simple game of Tic-Tac-Toe. In this challenge, you modify the source code for your previous solution to help the computer strategize.

Although the rules of the game are very simple, creating a computer program that can play the game can be complex. A number of potentially complicated details need to be incorporated into the program. Specifically:

  • The program must have a way to internally represent the status of each of the nine squares that make up the Tic-Tac-Toe board.

  • The program must provide a way to register a move for either player, and must ensure that each move is valid (for example, a player is not allowed to play in a square that is already occupied by an X or an O.

  • The program must be able to determine when either player has won by looking at all eight of the possible three-in-a-row combinations: The three rows, the three columns, and the two diagonals.

  • The program must also be able to determine when the game is a draw — that is, when all nine squares have been played and neither player has won.

At the same time, the program has to manage the details of interacting with the user by asking the user to enter his or her move, announcing the computer’s play, displaying an updated representation of the board after each play, and declaring a winner or announcing a draw when the game is over.

In this challenge, you’re asked to separate these two elements of the Tic-Tac-Toe program: the part of the program that manages the status and progress of the game and the part of the program that handles the interaction with the user. You will do that by creating a class named TicTacToeBoard which provides methods that can be called to play a complete game. Then, you are asked to write a program that uses the TicTacToeBoard class to allow a human opponent to play a game of Tic-Tac-Toe against the computer.

From the user’s perspective, this program will operate identically to the program created to solve the simple Tic-Tac-Toe game challenge, with one difference: For this version of the game, the program makes a rudimentary effort toward strategy when determining the computer’s moves. The computer doesn’t play perfectly, so it’s still easily beatable. But it does make some effort beyond simply playing in the first empty square it sees.

The following table lists the methods that the TicTacToeBoard class should implement. Remember, you will need to create two .java files to solve this challenge. The first, TicTacToeBoard.java, implements the TicTacToeBoard class. The second, named simply TicTacToe.java, is the program the user will run to play a game of Tic-Tac-Toe against the computer.

The TicTacToeBoard Class
Constructor Description
TicTacToeBoard Creates a new TicTacToeBoard with all squares empty.
   
Method Description
void reset() Resets the status of each square to empty.
int getSquare(String square) Returns the status of the square specified by square, which must be one of the strings A1, A2, A3, B1, B2, B3, C1, C2, or C3. Returns 0 if the square is empty, 1 if it contains an X, and 2 if it contains an O. Throws IllegalArgumentException if square is not one of the allowable values.
void playAt(String square, int player) Marks the specified square (A1, A2, A3, B1, B2, B3, C1, C2, or C3) for the specified player (1 for X, 2 for O). Throws IllegalArgumentException if square is not one of the allowable values, player is not 1 or 2, or the specified square is not empty.
int isGameOver() Determines whether the game is over. Returns 0 if the game is not over, 1 if X has won the game, 2 if O has won the game, and 3 if the game is a draw. The game-ending conditions are as follows:
1: If any row, column, or diagonal contains all Xs.
2: If any row, column, or diagonal contains all Os.
3: If there are no empty squares and neither X nor O has won.
int getNextMove() Returns an integer representing the next move for the computer opponent. This method should make a rudimentary effort to select a good move, according to the following strategy:
* If the center (square B2) is empty, play the center square.
* If the center is not empty but any of the four corners (squares A1, A3, C1, or C3) are empty, play one of the corners (it doesn’t matter which).
* If the center is not empty and no corners are empty, play one of the edges (squares A2, B1, B3, or C2).
String toString() Returns a string that represents the current status of the board. The string includes new-line characters to display the rows, as well as separator lines on separate console lines, as in this example:
O | | O
—|—|—
| X |
—|—|—
| X |

If you’re stumped, you can find the solution on the Downloads tab of the Java All-in-One For Dummies, 4th Edition product page.

Good luck!