import java.io.*; interface TTTConstants { static final int N = 3; static final int SIZE = N*N; static final byte BLANK = 0; static final byte X = 1; static final byte O = -X; } class IllegalMoveException extends RuntimeException { IllegalMoveException(String s) { super("Illegal move: " + s); } } class TTTBoard implements /* imports */ TTTConstants { byte[] squares; int numOfMoves; byte next = X; TTTBoard() { // create an empty board squares = new byte[SIZE]; // default byte value is BLANK numOfMoves = 0; } TTTBoard(TTTBoard s) { // clone an existing board squares = new byte[SIZE]; System.arraycopy(s.squares,0,squares,0,SIZE); numOfMoves = s.numOfMoves; next = s.next; } void move(int i, int j) { int k = index(i,j); move(k); } void move(int k) { if (numOfMoves == SIZE) throw new IllegalMoveException( "board is full implying that the game is over"); if (squares[k] != BLANK) throw new IllegalMoveException( "square [" + k/N + "," + k%N + "] occupied"); squares[k] = next; next = opposite(next); numOfMoves++; } byte winner() { // not parameterized with respect to N, SIZE byte bl = BLANK; if (squares[index(0,0)] != bl) { if ((squares[index(0,1)] == squares[index(0,0)] && squares[index(0,2)] == squares[index(0,0)]) || (squares[index(1,0)] == squares[index(0,0)] && squares[index(2,0)] == squares[index(0,0)])) return squares[index(0,0)]; } if (squares[index(2,2)] != bl) { if ((squares[index(2,1)] == squares[index(2,2)] && squares[index(2,0)] == squares[index(2,2)]) || (squares[index(1,2)] == squares[index(2,2)] && squares[index(0,2)] == squares[index(2,2)])) return squares[index(2,2)]; } if (squares[index(1,1)] != bl) { if ((squares[index(0,0)] == squares[index(1,1)] && squares[index(2,2)] == squares[index(1,1)]) || (squares[index(0,2)] == squares[index(1,1)] && squares[index(2,0)] == squares[index(1,1)]) || (squares[index(0,1)] == squares[index(1,1)] && squares[index(2,1)] == squares[index(1,1)]) || (squares[index(1,0)] == squares[index(1,1)] && squares[index(1,2)] == squares[index(1,1)])) return squares[index(1,1)]; } return bl; } int bestMove() { if (numOfMoves == SIZE) throw new RuntimeException("No move is possible"); int bestValue = next == X ? -1 : 1; int bestMove = -1; for (int i = 0; i < SIZE; i++) if (squares[i] == BLANK) { // i is legal move TTTBoard b = new TTTBoard(this); b.move(i); int value = b.eval(); if (next == X) { if (value > bestValue) { bestMove = i; bestValue = value; } } else if (value < bestValue) { bestMove = i; bestValue = value; } } return bestMove; } int eval() { byte win = winner(); if (win != 0 || numOfMoves == SIZE) return win; int bestValue = next == X ? -1 : 1; for (int i = 0; i < SIZE; i++) if (squares[i] == BLANK) { // i is legal move TTTBoard b = new TTTBoard(this); b.move(i); int value = b.eval(); if (next == X) { if (value > bestValue) { bestValue = value; } } else if (value < bestValue) { bestValue = value; } } return bestValue; } static StreamTokenizer in = new StreamTokenizer( new BufferedReader(new InputStreamReader(System.in))); void play() throws IOException { int move; while ( numOfMoves < SIZE && winner() == 0) { System.out.println("The board position is: \n" + this); do { System.out.println("What is your move (a number 0-8)?"); int token = in.nextToken(); while ((token != in.TT_NUMBER)) token = in.nextToken(); move = (int) in.nval; } while ((move < 0) || (move > 8) || squares[move] != BLANK); move(move); System.out.println("The board position after your move is: \n" + this); if (numOfMoves < SIZE) { int response = bestMove(); move(response); System.out.println( "The board position after my response is:\n" + this); } } System.out.println("The game is over. " + (winner() == O ? "I won." : "It was a draw.")); } public String toString() { StringBuffer result = new StringBuffer(); result.append("+-+-+-+\n"); for (int i = 0; i < N; i++) { result.append("|"); for (int j = 0; j < N; j++) { byte sq = squares[index(i,j)]; result.append( sq == X ? "X|" : sq == O ? "O|" : " |"); } result.append("\n"); result.append("+-+-+-+\n"); } return result.toString(); } static int index(int i, int j) { return i*N + j; } static byte opposite(byte player) { return player == X ? O : X; } public static void main(String[] args) throws IOException { TTTBoard b1 = new TTTBoard(); b1.play(); } }