CS 1063  Project 3:  Tic-Tac-Toe

The TicTacToe Class

Objectives

This is one of three major programming projects this semester.  You may NOT collaborate on this project.  While you may ask for assistance in debugging, this project should be ENTIRELY your own work.

Other objectives include:

Hand-in Requirements

All projects and laboratories will be submitted electronically through Blackboard.  Zip up your entire lab directory to submit as the source.  (Right click on the lab folder and follow the 7-Zip > Add to "project3.zip" or follow Send To > Compressed (zipped) Folder.)  The lab folder should include the following:

Introduction

The goal of this project is to implement a program that allows the user to play Tic-Tac-Toe vs. the computer.

An array of length nine is used to store the position of the game.  The first three elements of the array corresponds to the first row of the Tic-Tac-Toe board, the next three elements to the second row, and the last three elements to the last row.

A main method for this program is provided to you.  This main method calls methods implemented in ReplaceThis.class.  Full credit for your project is given when these method calls are replaced with method calls to your own code in TicTacToe.java.

Initial Zip File and TicTacToe.java

You can start your project by downloading project3.zip.  This file contains DrawingPanel.java, ReplaceThis.class, and this initial version of TicTacToe.java.

import java.util.*;
import java.awt.*;

public class TicTacToe {
  public static final Scanner CONSOLE = new Scanner(System.in);
  public static final Random RAND = new Random();
  public static final int EMPTY = 0;
  public static final int CROSS = 1;
  public static final int NAUGHT = 2;
  
  // This main method allows the user to play Tic-Tac-Toe vs.
  // the computer.  Method calls to static methods in
  // ReplaceThis.class should be replaced with your own methods
  // in this program.
  public static void main(String[] args) {
    DrawingPanel panel = new DrawingPanel(600,600);
    Graphics g = panel.getGraphics();
    
    // This draws the lines and the small numbers on the panel
    ReplaceThis.drawBoard(g);
    
    // createBoard returns an int array of length 9
    int[] board = ReplaceThis.createBoard();
    
    // font for drawing big Xs and Os
    g.setFont(new Font("SansSerif", Font.BOLD, 150));
    
    // The computer is X and moves first.
    int turn = CROSS;
    
    // gameOver is true if X or O wins or the board is filled
    while ( ! ReplaceThis.gameOver(board) ) {
      if (turn == CROSS) {
        
        // computerMove selects a random move to an empty square.
        int move = ReplaceThis.computerMove(board);
        
        // Record the computer's move.
        board[move] = CROSS;
        
        // drawX draws an X in the appropriate square.
        ReplaceThis.drawX(g, move);
        
        // Now it will be the user's turn.
        turn = NAUGHT;
      } else {
        
        // userMove inputs a move from the user.
        int move = ReplaceThis.userMove(board);
        
        // Record the user's move.
        board[move] = NAUGHT;
        
        // drawO draws an O in the appropriate square.
        ReplaceThis.drawO(g, move);
        
        // Now it will be the computer's turn.
        turn = CROSS;
      }
    }
    
    // The game is over, so print the winner.
    ReplaceThis.printWinner(board);
  } 
}

TicTacToe.java creates several class constants.  RAND is a Random object that should be used to generate the computer's moves.  Another name for Tic-Tac-Toe is Crosses and Naughts, which explains two of the names.

The main method creates a DrawingPanel object, gets the Graphics object for drawing on the window, initializes the board, and loops until the game is over.  Study the loop carefully so you understand how the program keeps track of whose turn to move it is.

A move is represented as an integer from 0 to 8.  0, 1, and 2 correspond to the first row of the Tic-Tac-Toe board.  3, 4, and 5 correspond to the second row of the Tic-Tac-Toe board.  6, 7, and 8 correspond to the third row of the Tic-Tac-Toe board.  If move contains a move, then the center of the corresponding square on the DrawingPanel can be obtained by:

int x = 100 + 200 * (move % 3);
int y = 100 + 200 * (move / 3);

Moves are stored in the board array.  Initially, the board should have all zeroes (the value of EMPTY).

index     0     1     2     3     4     5     6     7     8  
value     0   0   0   0   0   0   0   0   0

As the game proceeds, the values in the array should correspond to the moves made on the board.  For example, if this is the current position of the game (click to see full size):

Tic-Tac-Toe Position

Then there should be a 1 (the value of CROSS) at indexes 2, 3, and 8, and there should be a 2 (the value of NAUGHT) at indexes 4 and 7.  That is, the board array should look like:

index     0     1     2     3     4     5     6     7     8  
value     0   0   1   1   2   0   0   2   1

Methods

Implementing this project can proceed by coding each method separately.

The drawBoard Method

The header of this method is:

public static void drawBoard(Graphics g)
This method should draw the lines and the small numbers on the DrawingPanel, similar to the following picture (click to see full size).

Empty Tic-Tac-Toe Board

The createBoard Method

This method should return an int array of length 9.  The header for this method is:

public static int[] createBoard()
Each element of the array should be equal to the EMPTY class constant.

The computerMove Method

This method should return a move: an int between 0 and 8.  This move should be randomly generated, but it should also be an empty square.  One way to do this to generate random numbers between 0 and 8 until a number corresponds to an empty square.  The RAND class constant contains a Random object that you can use for this task.  The header for this method is:

public static int computerMove(int[] board)

The drawX and drawO Methods

The drawX method should draw an X in the square corresponding to the move.  Similarly, the draw0 method should draw an O in the square corresponding to the move.  The drawString of the Graphics class can be used to draw text on the DrawingPanel. Each X should be colored red and each O should be colored blue (or choose your own two colors).

If move contains a move, then the center of the square on the DrawingPanel can be calculated by:

int x = 100 + 200 * (move % 3);
int y = 100 + 200 * (move / 3);

The userMove Method

This method should return a move selected by the user: an int between 0 and 8.  The user should asked to enter a move until the move corresponds to an empty square.  In addition, this method should be robust; it should not crash the program if the user enter a token that is not an int.  See the getInt method in the book (p. 338) and the surrounding discussion.

The gameOver Method

This method should return true if the game is over.  Note that there are eight ways to get three in line in Tic-Tac-Toe: three rows, three columns, and two diagonals.  One way to do this is to write an if statement for each one. For example, one test can coded as:

( board[0] != EMPTY && board[0] == board[1] && board[1] == board[2] )
would test whether the top row is filled with three Xs or three Os.

This method should also return true if there are no more empty squares.

The printWinner Method

This method should print the winner of the game, or print that the game is drawn if no player has three in line.  The if statements and tests for this method should be similar to the gameOver method.

Rubric

Your program should compile without any errors.  A program with more than one or two compile errors will likely get a zero for the whole assignment.

The following criteria will also be used to determine the grade for this assignment: