// This class illustrates a 1- or 2-person Tic Tac Toe game // It works but it doesn't recognize a tie game. A 1-person game // is played against the computer, which never loses! The computer's // next move is made by the method 'champ'. import java.applet.*; import java.awt.*; import java.awt.event.*; public class TicTacToe extends Applet implements MouseListener, ActionListener, ItemListener { // Variables used by the Applet int last_x = 0; int last_y = 0; Button clear_button; Choice user_choices; TextArea echo_area; Grid theBoard; String current_choice = "2-player Tic Tac Toe"; Color current_color = Color.black; char current_player; // Current player: ON, OFF, EX, or OH String current_message = ""; // Initializing the Frame public void init() { // Set the background color and listen for the mouse setBackground(Color.white); addMouseListener(this); // Create a button and add it to the Frame. clear_button = new Button("New Game"); clear_button.setForeground(Color.black); clear_button.setBackground(Color.lightGray); add(clear_button); clear_button.addActionListener(this); // Create a menu of user choices and add it to the Frame. user_choices = new Choice(); user_choices.addItem("2-player Tic Tac Toe"); user_choices.addItem("1-player Tic Tac Toe"); add(user_choices); user_choices.addItemListener(this); // Create a TextArea and add it to the Frame echo_area = new TextArea(2, 40); echo_area.setEditable(false); add(echo_area); } public void mouseClicked(MouseEvent e) { Graphics g = this.getGraphics(); last_x = e.getX(); last_y = e.getY(); if (theBoard.inGrid(last_x, last_y)) if (theBoard.equals(theBoard.row, theBoard.col, theBoard.OFF)) { theBoard.set(theBoard.row, theBoard.col, current_player); if (inARow(theBoard, 3, current_player)) echo_area.setText("Player " + current_player + " wins!"); else { if (current_player==theBoard.EX) current_player = theBoard.OH; else current_player = theBoard.EX; if (current_choice.equals("2-player Tic Tac Toe")) echo_area.setText("Player " + current_player + " make your move"); else echo_area.setText("Click outside the grid for the computer's move"); } } else echo_area.setText("Invalid move, try again"); else if (current_choice.equals("1-player Tic Tac Toe") && current_player==theBoard.OH) { echo_area.setText("Here's the computer's move..."); champ(theBoard); if (inARow(theBoard, 3, current_player)) echo_area.setText(echo_area.getText() + "computer wins!"); current_player = theBoard.EX; } else echo_area.setText("Please click inside the board"); } public void mousePressed (MouseEvent e) { } public void mouseReleased (MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } // Called when the user selects a Button or TextArea public void actionPerformed (ActionEvent e) { // Clear the Frame Graphics g = this.getGraphics(); Rectangle r = this.bounds(); g.setColor(this.getBackground()); g.fillRect(r.x, r.y, r.width, r.height); g.setColor(current_color); if (e.getSource() == clear_button) { echo_area.setText("New Game button selected "); // Place a 3x3 board to the Frame, cellSize = 20 pixels // displaced horizontally 6 cells from the left margin theBoard = new Grid(g, 3, 20, 6); theBoard.cellColor(current_color); current_player = theBoard.EX; } } // Called when the user makes a Choice selection public void itemStateChanged (ItemEvent e) { Graphics g = this.getGraphics(); current_choice = (String)(e.getItem()); echo_area.setText("Choice selected: " + current_choice); if (current_choice.equals("1-player Tic Tac Toe")) echo_area.setText(echo_area.getText() + "\n" + "You're X; make your first move"); else echo_area.setText(echo_area.getText() + "\n" + "Player X, make your first move"); } public void champ (Grid g) { int [][] b = {{2,2,2}, {2,2,2}, {2,2,2}}; int turn = 1, i, j, // turn is the turn about to be played, from 1 to 9 make2 = 0, posWinEX = -1, posWinOH = -1; // these are linear indexes {0, 1, ..., 8} for (i=0; i<3; i++) for (j=0; j<3; j++) { if (g.equals(i, j, g.EX)) {b[i][j] = 3; turn++;} else if (g.equals(i, j, g.OH)) {b[i][j] = 5; turn++;} } // compute posWinEX = the position of a win by EX (-1 if none) for (i=0; i<3; i++) { if (b[i][0]*b[i][1]*b[i][2]==18) { posWinEX = 3*i; if (b[i][1]==2) posWinEX=posWinEX+1; else if (b[i][2]==2) posWinEX=posWinEX+2; } if (b[0][i]*b[1][i]*b[2][i]==18) { posWinEX = i; if (b[1][i]==2) posWinEX=posWinEX + 3; else if (b[2][i]==2) posWinEX=posWinEX + 6; } } if (b[0][0]*b[1][1]*b[2][2]==18) {posWinEX = 0; if (b[1][1]==2) posWinEX=4; else if (b[2][2]==2) posWinEX=8;} if (b[0][2]*b[1][1]*b[2][0]==18) {posWinEX = 2; if (b[1][1]==2) posWinEX=4; else if (b[2][0]==2) posWinEX=6;} // compute posWinOH = the position of a win by OH (-1 if none) for (i=0; i<3; i++) { if (b[i][0]*b[i][1]*b[i][2]==50) { posWinOH = 3*i; if (b[i][1]==2) posWinOH=posWinOH+1; else if (b[i][2]==2) posWinOH=posWinOH+2; } if (b[0][i]*b[1][i]*b[2][i]==50) { posWinOH = i; if (b[1][i]==2) posWinOH=posWinOH + 3; else if (b[2][i]==2) posWinOH=posWinOH + 6; } } if (b[0][0]*b[1][1]*b[2][2]==50) {posWinOH = 0; if (b[1][1]==2) posWinOH=4; else if (b[2][2]==2) posWinOH=8;} if (b[0][2]*b[1][1]*b[2][0]==50) {posWinOH = 2; if (b[1][1]==2) posWinOH=4; else if (b[2][0]==2) posWinOH=6;} // try to make 2 in a row, or find a blank square if (b[1][1]==2) make2=4; else if (b[0][1]==2) make2=1; else if (b[1][0]==2) make2=3; else if (b[1][2]==2) make2=5; else if (b[2][1]==2) make2=7; else if (b[0][2]==2) make2=2; else if (b[2][0]==2) make2=6; else if (b[2][2]==2) make2=8; switch (turn) { case 1: g.set(0,0,g.EX); return; case 2: if (b[1][1]==2) g.set(1,1,g.OH); else g.set(0,0,g.OH); return; case 3: if (b[2][2]==2) g.set(2,2,g.EX); else g.set(1,0,g.EX); return; case 4: if (posWinEX!=-1) g.set(posWinEX/3, posWinEX%3, g.OH); // block else g.set(make2/3, make2%3, g.OH); return; case 5: if (posWinEX!=-1) g.set(posWinEX/3, posWinEX%3, g.EX); // win else if (posWinOH!=-1) g.set(posWinOH/3, posWinOH%3, g.EX); // block // try for a fork else if (b[2][0]==2) g.set(2, 0, g.EX); else g.set(0, 2, g.EX); return; case 6: case 8: if (posWinOH!=-1) g.set(posWinOH/3, posWinOH%3, g.OH); // win else if (posWinEX!=-1) g.set(posWinEX/3, posWinEX%3, g.OH); // block else g.set(make2/3, make2%3, g.OH); return; case 7: case 9: if (posWinEX!=-1) g.set(posWinEX/3, posWinEX%3, g.EX); // win else if (posWinOH!=-1) g.set(posWinOH/3, posWinOH%3, g.EX); // block else g.set(make2/3, make2%3, g.EX); return; } } public boolean inARow (Grid g, int n, char p) { boolean result = false; for (int i=0; i<=g.size-1; i++) { for (int j=0; j<=g.size-1; j++) { // look vertically down result = true; for (int k=0; k