Assignment 3: Tic-tac-toe
Fall 2007, David Matuszek

Purpose of this assignment:

General idea of the assignment:

Write a program to allow the human to play tic-tac-toe (also called "naughts and crosses") with the computer. The computer will always play 'X'; the human will always play 'O'. The computer and human will alternate taking the first move, with the computer having the first move in the first game. After each game, print out how many games have been won by each player, and how many ended in a tie.

Details:

Use Eclipse.

In Eclipse, create a project with this name: LastName_FirstInitial_TicTacToe, where LastName and FirstInitial are the name of one (either one) of the partners. Use the default package.

Use the following classes and methods. Put both your names in (separate) @author tags in the comment for the TicTacToe class. Be very careful with spelling and capitalization; your names and parameter lists must match the specification exactly. You may write additional methods if you like.

class TicTacToe

public static void main(String[] args)
Creates an object of type TicTacToe and tells it to run().

void run()
Does all the top-level organization of playing multiple tic-tac-toe games:
  • Creates a new board for each game.
  • Keeps track of whose turn it is to start the game.
  • Keeps track of whose turn it is to play.
  • Tells each player when to make a move.
  • Prints the game board after each move.
  • Test whether the game is over.
  • When a game ends, prints who won.
  • When a game ends, prints how many games were won, lost, and tied.
  • Decides whether to play again.
Most of this work is done by talking to the HumanPlayer, the ComputerPlayer, and the TicTacToeBoard.

class TicTacToeBoard

The following methods and constructor have been provided for you here, because they require the use of an array, and we haven't covered arrays yet. Your additional methods should use these predefined methods, and should not directly access the array.

TicTacToeBoard()
Constructor for a TicTacToeBoard. This constructor has been provided for you.

void set(int row, int column, char ch)
Sets the square in the given row and column of the tic-tac-toe board to the given character. The row and column must be integers in the range 1 to 3; the character must be either 'X' or 'O'.

char get(int row, int column)
Returns the character in the given row (1, 2, or 3) and the given column (1, 2, or 3) of the tic-tac-toe board. The return value will be one of 'X', 'O', or ' ' (space).

boolean isEmpty(int row, int column)
Tests whether the square in the given row and column of the tic-tac-toe board is empty, that is, available to be moved in.

void print()
Prints the tic-tac-toe board.

The following methods should be added by you or by your partner.

boolean gameIsOver()
Tests whether the game is over, either because someone has won, or because there is no remaining move possible.

boolean computerHasWon()
Tests if the computer has won the game.

boolean humanHasWon()
Tests if the human has won the game.

class HumanPlayer

Use the default constructor, new HumanPlayer(), for this class.

void makeMove(TicTacToeBoard board)
Asks the player for a row and a column and, if that move is legal, puts an 'O' in that location.

boolean ask(String question)
Asks the player a yes-no question, and returns true for a yes answer, false for a no answer. (This is for use in asking whether to play another game.)

You are using a Scanner in the TicTacToe class, but that Scanner is not immediately available here. I'm told that it is okay to have more than one Scanner, so that you can create a new Scanner in the Human's ask method. (I still want to check this out myself.)

Better than creating a new Scanner every time you call ask, you might just create a static Scanner in the Human class (not in a method of the class):
     static Scanner scanner = new Scanner(System.in);
and use that.

class ComputerPlayer

void makeMove(TicTacToeBoard board)
Makes a move for the computer. Here is the logic you should use:
  • If the center square is available, move there.
  • [optional] If there is a move that will win the game for the computer, move there.
  • [optional] If there is a move that would win the game for the human, prevent the win by moving there.
  • If there is a corner square available, move there.
  • If there is an edge square available (and there should be, because you shouldn't call this method if there are no more moves possible), move there.

The makeMove method should do its job by calling "helper" methods. Use these method signatures:

For each of these, the method should return true if the requested move was made, and false if it was not possible. (This is so the makeMove method knows whether it is done, or whether it should keep trying.) I have marked two methods "optional" because, while they will improve the computer's play, the methods are likely to be quite long and tedious, and you won't learn that much from writing them.

Due date:

Thursday, September 27, before midnight. Turn in your program electronically, using Blackboard. (See my Instructions for Using Zip Files and Blackboard). Put your partner's name in Blackboard's comment field when you submit the program. Only assignments submitted via Blackboard will be accepted--do not send your program by email. The usual late penalty of 5 points per day (out of 100 points) will apply.