Wednesday, November 2, 2011

Tic-Tac-Toe: A Simple Java Program

This is a simple tic-tac-toe program written in Java to show how to code the 2-persons game (1 human, 1 computer).

The emphasis is to show a typical control mechanism that handles the states change between the human player and the computer player. User interface is minimum and no image is used. This program runs as a java Application and SWING is used.

Programming Language: JavaSE 1.6;
IDE used: Eclipse SDK 3.7.0
Additional API or Packages: None.


There are only 2 classes in my tictactoe package: Class TicTacToe and Class Board.

(1) Class TicTacToe extends the JFrame class and acts as the main program. See Figure 1 below.


package tictactoe;

import javax.swing.*;

@SuppressWarnings("serial")
public class TicTacToe extends JFrame  {

 public TicTacToe() {
        add(new Board());
  setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
  setTitle("TicTacToe");
  setSize(295,240);
  setLocationRelativeTo(null);
  setVisible(true);
  setResizable(false);
 }
 
 public static void main(String[] args) {
  new TicTacToe();
 }

}
Fig 1. Class TicTacToe



(2) Class Board extends a JPanel class. It handles the UI (user interface) and the control. Most of the 2D Board Games programming in Java use this structure. (See Figure 2 below)

By using simply JButtons, I handled the flow control in the mouseClicked method. I did not use any image in the UI portion and thus does not need to deal with the paint() method.


package tictactoe;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.*;

@SuppressWarnings("serial")
public class Board extends JPanel implements MouseListener {

 private JPanel upperPanel;
 private JPanel centerPanel;
 private JLabel label;
 private JButton startButton;
 private JButton button[] = new JButton[9];
 
 private String[][] value = new String[][] { 
   {"", "", ""}, {"", "", ""}, {"", "", ""} };
 private int[][] winMatrixX = new int[][] { // 8 is correct, not 9
   {0,0,0},{1,1,1},{2,2,2},{0,1,2},
   {0,1,2},{0,1,2},{0,1,2},{0,1,2} }; 
 private int[][] winMatrixY = new int[][] { 
   {0,1,2},{0,1,2},{0,1,2},{0,0,0},
   {1,1,1},{2,2,2},{0,1,2},{2,1,0} };

 private boolean startGame = false;
 private boolean nextMoveIsComputer = false;
 private String msg;
 
 public Board() {
  setLayout(new BorderLayout());
  upperPanel = new JPanel();
  startButton = new JButton("Start Game");
  startButton.setName("StartButton");
  startButton.addMouseListener(this);
  
  upperPanel.add(startButton);
  add(upperPanel,BorderLayout.NORTH);

  // create an invisible area
  add(Box.createRigidArea(new Dimension(15, 0)), BorderLayout.WEST); 
  add(Box.createRigidArea(new Dimension(15, 0)), BorderLayout.EAST);

  msg =" Click Start Button to start the game.";
  label = new JLabel(msg);
  add(label, BorderLayout.SOUTH);

  centerPanel = new JPanel();
  centerPanel.setLayout(new GridLayout(3, 3, 0, 0));

  add(centerPanel, BorderLayout.CENTER);
  for (int i = 0; i < 9; i++) {
    button[i]= new JButton();
    centerPanel.add(button[i]); 
    button[i].setName(String.valueOf(i));
    button[i].addMouseListener(this);
  }
 }

 private void initGame() {
  startGame = true; // first click start the game
  nextMoveIsComputer = false;
  value = new String[][] { 
    {"", "", ""}, {"", "", ""}, {"", "", ""} };
  resetAllButtons();
  msg=" Your turn ";
  label.setText(msg);
 }

 private void resetAllButtons() {
  for (int i = 0; i < 9; i++) {
   button[i].setText("");
  }
 }

 private void computerMoveNow() {
  boolean stillInGame = true;
  if (nextMoveIsComputer && stillInGame) {
   decideMove();
  }
  nextMoveIsComputer = false;
 }
 
 private void decideMove() {
  // Rule 0. Decide winner
  if ( gameOver() ) return;
  
  // Rule 1. Win: If computer player has two O in a row, 
  //    play the third to get three in a row.
  if (value[0][0].equals("") && value[0][1].equals("O") && 
    value[0][2].equals("O")) { 
   value[0][0]="O";button[0].setText("0");
   msg=" I won !";label.setText(msg); 
   nextMoveIsComputer=false;startGame=false;return;}
  if (value[0][0].equals("O") && value[0][1].equals("") && 
    value[0][2].equals("O")) { 
   value[0][1]="O";button[1].setText("0");
   msg=" I won !"; label.setText(msg); 
   nextMoveIsComputer=false; startGame=false; return;
  }
  if (value[0][0].equals("O") && value[0][1].equals("O") && 
    value[0][2].equals("")) { 
   value[0][2]="O";button[2].setText("0");
   msg=" I won !"; label.setText(msg); 
   nextMoveIsComputer=false; startGame=false; return;
  }
  if (value[1][0].equals("") && value[1][1].equals("O") && 
    value[1][2].equals("O")) 
   {value[1][0]="O";button[3].setText("0");
   msg=" I won !"; label.setText(msg); 
   nextMoveIsComputer=false; startGame=false; return;
  }
  if (value[1][0].equals("O") && value[1][1].equals("") && 
    value[1][2].equals("O")) 
   {value[1][1]="O";button[4].setText("0");
   msg=" I won !"; label.setText(msg); 
   nextMoveIsComputer=false; startGame=false; return;
  }
  if (value[1][0].equals("O") && value[1][1].equals("O") && 
    value[1][2].equals("")) 
   {value[1][2]="O";button[5].setText("0");
   msg=" I won !"; label.setText(msg); 
   nextMoveIsComputer=false; startGame=false; return;
  }
  
  if (value[2][0].equals("") && value[2][1].equals("O") && 
    value[2][2].equals("O")) 
   {value[2][0]="O";button[6].setText("0");
   msg=" I won !"; label.setText(msg); 
   nextMoveIsComputer=false; startGame=false; return;
  }
  if (value[2][0].equals("O") && value[2][1].equals("") && 
    value[2][2].equals("O")) 
   {value[2][1]="O";button[7].setText("0");
   msg=" I won !"; label.setText(msg); 
   nextMoveIsComputer=false; startGame=false; return;
  }
  if (value[2][0].equals("O") && value[2][1].equals("O") && 
    value[2][2].equals("")) 
   {value[2][2]="O";button[8].setText("0");
   msg=" I won !"; label.setText(msg); 
   nextMoveIsComputer=false; startGame=false; return;
  }
  
  if (value[0][0].equals("") && value[1][0].equals("O") && 
    value[2][0].equals("O")) 
   {value[0][0]="O";button[0].setText("0");
   msg=" I won !"; label.setText(msg); 
   nextMoveIsComputer=false; startGame=false; return;
  }
  if (value[0][0].equals("O") && value[1][0].equals("") && 
    value[2][0].equals("O")) 
   {value[1][0]="O";button[3].setText("0");
   msg=" I won !"; label.setText(msg); 
   nextMoveIsComputer=false; startGame=false; return;
  }
  if (value[0][0].equals("O") && value[1][0].equals("O") && 
    value[2][0].equals("")) 
   {value[2][0]="O";button[6].setText("0");
   msg=" I won !"; label.setText(msg); 
   nextMoveIsComputer=false; startGame=false; return;
  }

  if (value[0][1].equals("") && value[1][1].equals("O") && 
    value[2][1].equals("O")) 
   {value[0][1]="O";button[1].setText("0");
   msg=" I won !"; label.setText(msg); 
   nextMoveIsComputer=false; startGame=false; return;
  }
  if (value[0][1].equals("O") && value[1][1].equals("") && 
    value[2][1].equals("O")) 
   {value[1][1]="O";button[4].setText("0");
   msg=" I won !"; label.setText(msg); 
   nextMoveIsComputer=false; startGame=false; return;
  }
  if (value[0][1].equals("O") && value[1][1].equals("O") && 
    value[2][1].equals("")) 
   {value[2][1]="O";button[7].setText("0");
   msg=" I won !"; label.setText(msg); 
   nextMoveIsComputer=false; startGame=false; return;
  }

  if (value[0][2].equals("") && value[1][2].equals("O") && 
    value[2][2].equals("O")) 
   {value[0][2]="O";button[2].setText("0");
   msg=" I won !"; label.setText(msg); 
   nextMoveIsComputer=false; startGame=false; return;
  }
  if (value[0][2].equals("O") && value[1][2].equals("") && 
    value[2][2].equals("O")) 
   {value[1][2]="O";button[5].setText("0");
   msg=" I won !"; label.setText(msg); 
   nextMoveIsComputer=false; startGame=false; return;
  }
  if (value[0][2].equals("O") && value[1][2].equals("O") && 
    value[2][2].equals("")) 
   {value[2][2]="O";button[8].setText("0");
   msg=" I won !"; label.setText(msg); 
   nextMoveIsComputer=false; startGame=false; return;
  }
  
  if (value[0][0].equals("") && value[1][1].equals("O") && 
    value[2][2].equals("O")) 
   {value[0][0]="O";button[0].setText("0");
   msg=" I won !"; label.setText(msg); 
   nextMoveIsComputer=false; startGame=false; return;
  }
  if (value[0][0].equals("O") && value[1][1].equals("") && 
    value[2][2].equals("O")) 
   {value[1][1]="O";button[4].setText("0");
   msg=" I won !"; label.setText(msg); 
   nextMoveIsComputer=false; startGame=false; return;
  }
  if (value[0][0].equals("O") && value[1][1].equals("O") && 
    value[2][2].equals("")) 
   {value[2][2]="O";button[8].setText("0");
   msg=" I won !"; label.setText(msg); 
   nextMoveIsComputer=false; startGame=false; return;
  }
  
  if (value[0][2].equals("") && value[1][1].equals("O") && 
    value[2][0].equals("O")) 
   {value[0][2]="O";button[2].setText("0");
   msg=" I won !"; label.setText(msg); 
   nextMoveIsComputer=false; startGame=false; return;
  }
  if (value[0][2].equals("O") && value[1][1].equals("") && 
    value[2][0].equals("O")) 
   {value[1][1]="O";button[4].setText("0");
   msg=" I won !"; label.setText(msg); 
   nextMoveIsComputer=false; startGame=false; return;
  }
  if (value[0][2].equals("O") && value[1][1].equals("O") && 
    value[2][0].equals("")) 
   {value[2][0]="O";button[6].setText("0");
   msg=" I won !"; label.setText(msg); 
   nextMoveIsComputer=false; startGame=false; return;
  }
  
  // Rule 2. Block: If the [opponent] has two in a row, 
  //   play the third to block them.
  if (value[0][0].equals("") && value[0][1].equals("X") && 
    value[0][2].equals("X")) 
   {value[0][0]="O";button[0].setText("0");
   msg=" Your turn"; label.setText(msg); 
   nextMoveIsComputer=false; return;
   }
  if (value[0][0].equals("X") && value[0][1].equals("") && 
    value[0][2].equals("X")) 
   {value[0][1]="O";button[1].setText("0");
   msg=" Your turn"; label.setText(msg); 
   nextMoveIsComputer=false; return;
  }
  if (value[0][0].equals("X") && value[0][1].equals("X") && 
    value[0][2].equals("")) 
   {value[0][2]="O";button[2].setText("0");
   msg=" Your turn"; label.setText(msg); 
   nextMoveIsComputer=false; return;
  }

  if (value[1][0].equals("") && value[1][1].equals("X") && 
    value[1][2].equals("X")) 
   {value[1][0]="O";button[3].setText("0");
   msg=" Your turn"; label.setText(msg); 
   nextMoveIsComputer=false; return;
  }
  if (value[1][0].equals("X") && value[1][1].equals("") && 
    value[1][2].equals("X")) 
   {value[1][1]="O";button[4].setText("0");
   msg=" Your turn"; label.setText(msg); 
   nextMoveIsComputer=false; return;
  }
  if (value[1][0].equals("X") && value[1][1].equals("X") && 
    value[1][2].equals("")) 
   {value[1][2]="O";button[5].setText("0");
   msg=" Your turn"; label.setText(msg); 
   nextMoveIsComputer=false; return;
  }
 
  if (value[2][0].equals("") && value[2][1].equals("X") && 
    value[2][2].equals("X")) 
   {value[2][0]="O";button[6].setText("0");
   msg=" Your turn"; label.setText(msg); 
   nextMoveIsComputer=false; return;
  }
  if (value[2][0].equals("X") && value[2][1].equals("") && 
    value[2][2].equals("X")) 
   {value[2][1]="O";button[7].setText("0");
   msg=" Your turn"; label.setText(msg); 
   nextMoveIsComputer=false; return;
  }
  if (value[2][0].equals("X") && value[2][1].equals("X") && 
    value[2][2].equals("")) 
   {value[2][2]="O";button[8].setText("0");
   msg=" Your turn"; label.setText(msg); 
   nextMoveIsComputer=false; return;
  }
 
  if (value[0][0].equals("") && value[1][0].equals("X") && 
    value[2][0].equals("X")) 
   {value[0][0]="O";button[0].setText("0");
   msg=" Your turn"; label.setText(msg); 
   nextMoveIsComputer=false; return;
  }
  if (value[0][0].equals("X") && value[1][0].equals("") && 
    value[2][0].equals("X")) 
   {value[1][0]="O";button[3].setText("0");
   msg=" Your turn"; label.setText(msg); 
   nextMoveIsComputer=false; return;
  }
  if (value[0][0].equals("X") && value[1][0].equals("X") && 
    value[2][0].equals("")) 
   {value[2][0]="O";button[6].setText("0");
   msg=" Your turn"; label.setText(msg); 
   nextMoveIsComputer=false; return;
  }

  if (value[0][1].equals("") && value[1][1].equals("X") && 
    value[2][1].equals("X")) 
   {value[0][1]="O";button[1].setText("0");
   msg=" Your turn"; label.setText(msg); 
   nextMoveIsComputer=false; return;
  }
  if (value[0][1].equals("X") && value[1][1].equals("") && 
    value[2][1].equals("X")) 
   {value[1][1]="O";button[4].setText("0");
   msg=" Your turn"; label.setText(msg); 
   nextMoveIsComputer=false; return;
  }
  if (value[0][1].equals("X") && value[1][1].equals("X") && 
    value[2][1].equals("")) 
   {value[2][1]="O";button[7].setText("0");
   msg=" Your turn"; label.setText(msg); 
   nextMoveIsComputer=false; return;
  }

  if (value[0][2].equals("") && value[1][2].equals("X") && 
    value[2][2].equals("X")) 
   {value[0][2]="O";button[2].setText("0");
   msg=" Your turn"; label.setText(msg); 
   nextMoveIsComputer=false; return;
  }
  if (value[0][2].equals("X") && value[1][2].equals("") && 
    value[2][2].equals("X")) 
   {value[1][2]="O";button[5].setText("0");
   msg=" Your turn"; label.setText(msg); 
   nextMoveIsComputer=false; return;
  }
  if (value[0][2].equals("X") && value[1][2].equals("X") && 
    value[2][2].equals("")) 
   {value[2][2]="O";button[8].setText("0");
   msg=" Your turn"; label.setText(msg); 
   nextMoveIsComputer=false; return;
  }
 
  if (value[0][0].equals("") && value[1][1].equals("X") && 
    value[2][2].equals("X")) 
   {value[0][0]="O";button[0].setText("0");
   msg=" Your turn"; label.setText(msg); 
   nextMoveIsComputer=false; return;
  }
  if (value[0][0].equals("X") && value[1][1].equals("") && 
    value[2][2].equals("X")) 
   {value[1][1]="O";button[4].setText("0");
   msg=" Your turn"; label.setText(msg); 
   nextMoveIsComputer=false; return;
  }
  if (value[0][0].equals("X") && value[1][1].equals("X") && 
    value[2][2].equals("")) 
   {value[2][2]="O";button[8].setText("0");
   msg=" Your turn"; label.setText(msg); 
   nextMoveIsComputer=false; return;
  }
 
  if (value[0][2].equals("") && value[1][1].equals("X") && 
    value[2][0].equals("X")) 
   {value[0][2]="O";button[2].setText("0");
   msg=" Your turn"; label.setText(msg); 
   nextMoveIsComputer=false; return;
  }
  if (value[0][2].equals("X") && value[1][1].equals("") && 
    value[2][0].equals("X")) 
   {value[1][1]="O";button[4].setText("0");
   msg=" Your turn"; label.setText(msg); 
   nextMoveIsComputer=false; return;
  }
  if (value[0][2].equals("X") && value[1][1].equals("X") && 
    value[2][0].equals("")) 
   {value[2][0]="O";button[6].setText("0");
   msg=" Your turn"; label.setText(msg); 
   nextMoveIsComputer=false; return;
  }
 
  // Rule 3. Fork: Create an opportunity where you can win in two ways.

  // Rule 4. Block opponent's Fork:
  //  Option 1: Create two in a row to force the opponent into 
  //  defending, as long as it doesn't result in them creating 
  //  a fork or winning. For example, if "X" has a corner, "O" 
  //  has the center, and "X" has the opposite corner as well, 
  //  "O" must not play a corner in order to win. (Playing a 
  //  corner in this scenario creates a fork for "X" to win.)
  //  Option 2: If there is a configuration where the opponent 
  //  can fork, block that fork.
  
  // Rule 5. Center: Play the center.
  if (value[1][1].equals("")) {
   value[1][1]="O";button[4].setText("0");msg=" Your turn"; 
   label.setText(msg); nextMoveIsComputer=false; return;
  }

  // Rule 6. Opposite corner: If the opponent is in the 
  //   corner, play the opposite corner.
  if (value[0][0].equals("") && value[2][2].equals("X")) {
   value[0][0]="O";button[0].setText("0");msg=" Your turn"; 
   label.setText(msg); nextMoveIsComputer=false; return;
  }
  if (value[0][1].equals("") && value[2][1].equals("X")) {
   value[0][1]="O";button[1].setText("0");msg=" Your turn"; 
   label.setText(msg); nextMoveIsComputer=false; return;
  }
  if (value[0][2].equals("") && value[2][0].equals("X")) {
   value[0][2]="O";button[2].setText("0");msg=" Your turn"; 
   label.setText(msg); nextMoveIsComputer=false; return;
  }
  if (value[1][0].equals("") && value[1][2].equals("X")) {
   value[1][0]="O";button[3].setText("0");msg=" Your turn"; 
   label.setText(msg); nextMoveIsComputer=false; return;
  }

  if (value[1][0].equals("X") && value[1][2].equals("")) {
   value[1][2]="O";button[5].setText("0");msg=" Your turn"; 
   label.setText(msg); nextMoveIsComputer=false; return;
  }
  if (value[0][2].equals("X") && value[2][0].equals("")) {
   value[2][0]="O";button[6].setText("0");msg=" Your turn"; 
   label.setText(msg); nextMoveIsComputer=false; return;
  }
  if (value[0][1].equals("X") && value[2][1].equals("")) {
   value[2][1]="O";button[7].setText("0");msg=" Your turn";
   label.setText(msg); nextMoveIsComputer=false; return;
  }
  if (value[0][0].equals("X") && value[2][2].equals("")) {
   value[2][2]="O";button[8].setText("0");msg=" Your turn"; 
   label.setText(msg); nextMoveIsComputer=false; return;
  }

  // Rule 7. Empty corner: Play in a corner square.
  if (value[0][0].equals("")) {
   value[0][0]="O";button[0].setText("0");msg=" Your turn"; 
   label.setText(msg); nextMoveIsComputer=false; return;
  }
  if (value[0][2].equals("")) {
   value[0][2]="O";button[2].setText("0");msg=" Your turn";
   label.setText(msg); nextMoveIsComputer=false; return;
  }
  if (value[2][0].equals("")) {
   value[2][0]="O";button[6].setText("0");msg=" Your turn"; 
   label.setText(msg); nextMoveIsComputer=false; return;
  }
  if (value[2][2].equals("")) {
   value[2][2]="O";button[8].setText("0");msg=" Your turn"; 
   label.setText(msg); nextMoveIsComputer=false; return;
  }
  
  // Rule 8. Empty side: Play in a middle square on any of 
  //  the 4 sides.
  if (value[0][1].equals("")) {
   value[0][1]="O";button[1].setText("0");msg=" Your turn"; 
   label.setText(msg); nextMoveIsComputer=false; return;
  }
  if (value[1][0].equals("")) {
   value[1][0]="O";button[3].setText("0");msg=" Your turn"; 
   label.setText(msg); nextMoveIsComputer=false; return;
  }
  if (value[1][2].equals("")) {
   value[1][2]="O";button[5].setText("0");msg=" Your turn"; 
   label.setText(msg); nextMoveIsComputer=false; return;
  }
  if (value[2][1].equals("")) {
   value[2][1]="O";button[7].setText("0");msg=" Your turn"; 
   label.setText(msg); nextMoveIsComputer=false; return;
  }
 }
 
 private boolean gameOver() {
  int blank = 0;
  for (int i = 0; i < 8; i++) {
   int cross = 0;
   int nough = 0;
   for (int j = 0; j < 3; j++) {
    if (value[winMatrixX[i][j]][winMatrixY[i][j]]=="X" ) {
     cross++;
    } else if (value[winMatrixX[i][j]][winMatrixY[i][j]]=="O" ) {
     nough++;
    } else 
    blank++;
   }
   if (cross == 3) { 
    msg=" You won !"; 
    label.setText(msg); 
    startGame=false; 
    return true;
   }
   if (nough == 3) { 
    msg=" I won !"; 
    label.setText(msg); 
    startGame=false; 
    return true;
   }
  }
  if (blank == 0) {
   msg=" Draw & Game Over!"; 
   label.setText(msg); 
   startGame=false; 
   return true;
  }
  return false;
 }
 
 @Override
 public void mouseClicked(MouseEvent e) {
  JButton aButton = (JButton) e.getSource();
  if (aButton.getName().equalsIgnoreCase(startButton.getName())) {
   initGame();
  } else {
   if (startGame) { // game starts
   for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
     if (aButton.getName().equalsIgnoreCase(button[i*3+j].getName())) {
      if (value[i][j].equals("") ) {
       value[i][j] = "X"; // computer:O, user: X 
       aButton.setText("X");
       nextMoveIsComputer = true;
      }
     }
    }
   }
   computerMoveNow();
   } // end of inGame
  } // of else
 }

 @Override
 public void mousePressed(MouseEvent e) {
 }
 @Override
 public void mouseReleased(MouseEvent e) {
 }
 @Override
 public void mouseEntered(MouseEvent e) {
 }
 @Override
 public void mouseExited(MouseEvent e) {
 }
}
Fig 2. Class Board

The code has not been fully optimized or re-factored sufficiently. It is a working example though.

The is the TicTacToe java program.

No comments:

Post a Comment