Your code will involve writing a TTTLine class that represents vertical, horizontal, and diagonal lines of cells on the game board. Each will keep track of how many of its cells are owned by X and by O. The class contains a countCells() method to update the X and O counts, and a winner() method that invokes countCells() and then checks the ownership counts to return one of the TTTCell constants NO_ONE, X, O, or DRAW.
A win occurs when one of the lines contains three Xs or three Os. A draw occurs when each line contains both and X and an O. An array instance variable that contains eight TTTLines is declared in the TicTacToe class. Two methods, playerWins() and gameDrawn(), are added to the TicTacToe class to check for the win or draw conditions. These methods are invoked in the updateStatus() method to determine win or draw user messages and control enabling of the "Start New Game" button.
The TTTLine class should be defined in its own .java file. It does not need any imports. The class extends the Object class, so you can omit the extends clause.
This class uses an array instance variable cells to keep track of the cells in a line. It should be declared as follows.
TTTCell[] cells = new TTTCell[3];This creates an array that can contain three TTTCell objects. In addition, the class declares two int instance variables xOwns and oOwns. These variables will be used to record the number of cells that are marked with X and O. They do not need to be initialized.
In the declaration of the cells variable, the array itself is
initialized, but its entries are not because there is not enough
information to do so.
Java just places a
To make a TTTLine useful, you need to put cells into the array.
The best place to do that is in the constructor.
It should have three TTTCell parameters.
The statements in the constructor should just assign the parameters to the
three entries of cells, which are cells[0],
cells[1], and cells[2].
There are two methods defined in the TTTLine class.
The first, countCells(), has no parameters and void
return type.
It is only used inside the TTTLine class, so you do not need to declare the
method as public.
The method counts the number of cells in the line that are marked by X and
O and records the counts in xOwns and oOwns.
At the beginning of the method, both of these counts should be initialized
to 0.
Then loop through the cells in the line and increment the appropriate
count, depending on the mark in the cell.
This can be done with a for loop with the following structure.
The second method, winner(), has no parameters.
It returns one of the int constants TTTCell.X,
TTTCell.O, TTTCell.NO_ONE, or TTTCell.DRAW,
indicating who has won the line.
Since this method is invoked by the TicTacToe class, it must be declared to
be public.
The first statement of the method should invoke countCells() to
set up the xOwns and oOwns counts.
Then you need if statements to implement return values as indicated in the
following table.
After completing the TTTLine class, you should compile it to check for
syntax errors.
You will need to wait until changes are made in the TicTacToe class are
made to check for errors in logic.
To simplify setting up the entries in lines, you should write a
short method getCell().
Like the method of the same name that you have already written, this method
returns a TTTCell.
The difference is that this method has two int parameters,
r and c, that specify a row and a column in the tictactoe
board.
The method should just invoke the original getCell() method,
returning getCell(3*r + c).
Then in the setupBoard() method, assign a new TTTLines array, with
initialization, to lines.
You should have three lines for rows of the game board, three for columns,
and two for diagonals.
In the calls to the TTTLine constructor you will need to specify three
cells using getCell().
Take care when specifying the rows and columns for the cells.
The playerWins() has an int parameter plyr for specifying
a player (TTCell.X or TTTCell.O).
It checks a line by sending it a winner() message.
It returns true if the return value from winner() is equal to
plyr.
The default return statement is executed only when winner()
returns something other than plyr for all lines.
It should just return false.
The gameDrawn() method has no parameters.
If any of the winner() returned values are not
TTCell.DRAW then the method returns false.
In the default case it returns true.
To detect the end of a game, you then need three if statements.
The boolean conditions in the first two just invoke playerWins()
with parameters myMark and userMark respectively.
The boolean condition in the third just invokes gameDrawn().
Each if statement contains two nested statements, one to set the user
message and one to assign true to gameOver.
The user message is set by sending a setText() message to the
message variable.
The parameter should be one of the following.
Finally, if the gameOver local variable is true, you should
exchange marks for the myMark and userMark instance
variables and assign TTTCell.NO_ONE to the toPlay
variable.
You should also add a statement to enable the "Start New Game" button if
gameOver is true and disable the button otherwise.
After you have added code to updateStatus(), recompile your
TicTacToe class and run the applet with appletviewer.
Your applet should look and behave like the following demonstration applet.
You should play games where you win, lose, and draw, watching for the
appropriate messages and chacking the enabling of the "Start New Game"
button.
Since the computer does not yet have a good play strategy, it will be easy
to win a game.
You will have to make dumb moves to lose or draw.
The computer will always select its move in the lowest possible row.
Within that row, it will select the rightmost cell.
for (int i = 0; i < cells.length; i++; i++) {
TTTCell c = cells[i];
statements to increment the appropriate count for c
}
In order to increment the appropriate count, you will need if statements
that test whether c.getMark() is TTTCell.X or
TTTCell.O.
You can use if statements that contain return statements for the first
three situations, followed by a simple return statement to handle all other
cases.
This statement will only be executed when none of the if statements has
caused the method to return.
Situation Return
xOwns == 3 TTTCell.X
oOwns == 3 TTTCell.O
xOwns > 0 and oOwns > 0 TTTCell.DRAW
all other cases TTTCell.NO_ONE
Adding an Array of TTTLines to the TicTacToe Class
First, declare an instance variable named lines to the class.
Its type is TTTLine[] indicating an array of TTTLines.
It should be initialized to null.
Its entries cannot be created until the cells are created in the
setupBoard() method.
TicTacToe Class Methods for Detecting the End of a Game
The end of a game is detected with two methods playerWins() and
gameDrawn().
Both have boolean return type.
Both use the following loop structure to check the TTTLines.
for (int i = 0; i < lines.length; i++) {
TTTLine line = lines[i];
if statement that returns a boolean value
}
default return statement
Updating the Status in the TicTacToe Class
The remaining changes in this step are added at the beginning of the
updateStatus() method.
You should first add a local variable gameOver.
It should have boolean type and should be initialized to
false.