Wednesday, November 2, 2011

Genetic Algorithm and Java

I have written a Java program below to solve a Matrix-type problem using Genetic Algorithm. But let us first review some basic concepts.

There are many tutorials for Genetic Algorithm (GA) on the web. One of the comprehensive tutorials is
"Introduction to Genetic Algorithms, URL http://www.obitko.com/tutorials/genetic-algorithms/".

In many programming languages, "Hello World" programs is used to demonstrate how to code the first and the simplest program. There is a "Hello World" program for Genetic Algorithm too. You can find many "Hello World" examples of GA at  https://github.com/jsvazic/GAHelloWorld , written in various languages, including  the Java language.

However, after seeing Hello World program, interested users may want to see how GA can help to solve more challenging problems (for example, travelling salesman problem).

The will be a big gap between "Hello World" and the actual problems. How are we going to encode (that is, to represent) the actual problem in the chromosome strings? How to design the fitness function?  How does a chromosome string represent 2D problem? and tree structure? These are the questions we have in mind.

Two major challenging areas in writing GA program are: (A) How to encode the problem you have in hand, and (B) How to define a proper Fitness function.

(A) Encoding: There are four major types of encoding.

  • Binary Encoding : For example, "10100111" represents 10 and 7 decimal values.
  • Value Encoding : For example, "00011011" represents "left, right,back, forward", each with 2 bits codes. Or, a sequence of ASCII values can be used to represents the string "Hello, World!". (48hex for "H", 65hex for "e", and so on. The sequence would be "48656C6C6F..." in hexadecimal.)
  • Permutation Encoding : For example, "16248357" represent moving from position 1 to position 6 to position 2 and so on.
  • Tree Encoding : For example, "(+x(/5y))" represents a formula (x+(5/y)) in tree structure. Tree Encoding is more complicated and usually is done in LISP.

(B) Fitness Function: In general, design your fitness function so that value 0 represents the perfect score or best score. We need the program to halt when the Fitness function is equal to zero. Some examples:
  • If the target is to have 8 and 9, with current sequence "10100111" represents 10 and 7, one possible  Fitness function = abs(8-10)+abs(9-7) = +3
  • If the target is to have "Hello, World!", with current sequence "Hellq, Wovld!", one possible Fitness function = 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 4 + 0 + 0 +0 = +6
  • If the target is to have minimum distance when moving from position to positions, with a look-up table somewhere in the program, we can calculate the Fitness function as the sum of distances between 1 and 6, 6 and 2, 2 and 4,... for sequence "16248357".
  • If the target is to have a value of 10, with given x=3, y=1, "(+x(/5y))" represents a formula (x+(5/y)) in tree structure gives us value of 8, and the Fitness functions can be abs(10-8) = +2 .


For learning purpose, let's begin with simplest example and gradually go into the difficult ones. If we know how to encode the problem and how to define the Fitness function, we can easily code the program.

(1) The "Hello World" example:
  • Problem Description: This is the simplest one. With a target string "Hello, World!", GA program will give you ONE answer.
  • Encoding : This is Value Encoding with ASCII code. For target "Hello, World!", use a string (chromosome) of 8*13 bits. Limit the valid characters to the range of 32dec (the space) to 122dec (the 'z').
  • Fitness Function : One possible Fitness Function = Count how many characters mismatch the target string. For example "Hellq, Wovld!" would give you +2 because 2 characters mismatched. This functions can only give you 8 levels to differentiate the fitness all your chromosome. Another possible Fitness Function = Sum up the difference of each mismatched characters. "Hellq, Wovld!" would give you +6. The latter results in more than 8 levels of value and thus a better Fitness function.
  • Java example is available at https://github.com/jsvazic/GAHelloWorld .

(2) The "Mathematical Expression" example:
  • Problem Description: There is a good tutorial here: http://www.ai-junkie.com/ga/intro/gat1.html . The tutorial explains GA in layman term, and the example is: (quoted)
    "Given the digits 0 through 9 and the operators +, -, * and ', find a sequence that will represent a given target number. The operators will be applied sequentially from left to right as you read. So, given the target number 23, the sequence 6+5*4/2+1 would be one possible solution." 
  • Encoding : This is Value Encoding with ASCII code. For target "23", use a string (chromosome) of 72 bits (8*9, or 8*11, 8*13... bits). Limit the valid characters to "0123456789+-*/" and ignore all other characters.
  • Fitness Function : One possible Fitness Function = Evaluate the valid expression and ignore the invalid portion, then calculate the absolute different between the target (say) 23 and the calculated result.
  • With a target "23", this GA program will give you MANY answers. This example starts to show one powerful aspect of GA: You know what you are looking for (the target, 23), but you do not know the actual answer (the sequence). There can be many possible answers and each time you run the GA program, it will give you one possible answer.
  • Java example is available at http://www.ai-junkie.com/ga/intro/gat1.html .



(3) The "Matrix type of problem":
  • Problem Description: given a 3x3 matrix, and digits 1 to 9, find the arrangement that produces the sum of 15 on each row, each column and each diagonal. One of the answers we know is
    +---+---+---+
    | 2 | 9 | 4 |
    +---+---+---+
    | 7 | 5 | 3 |
    +---+---+---+
    | 6 | 1 | 8 |
    +---+---+---+
    

    We need to specify that each of the 1 to 9 has to appear only once. Otherwise, GA program will given undesirable answer like this:
    +---+---+---+
    | 3 | 9 | 3 |
    +---+---+---+
    | 5 | 5 | 5 |
    +---+---+---+
    | 7 | 1 | 7 |
    +---+---+---+
    

  • Encoding : This is Permutation Encoding because we want each character to appear only once. Limit the valid characters to "123456789" and this require some changes in selection, generateChromosome and Fitness methods. See below.
  • Fitness Function : One possible Fitness Function = There are 8 cases to calculate (3 rows, 3 columns, and 2 diagonal).  (i) If each character appears only once is true, we check further. For each cases, if its sum is not equal to 15, we assign 1, otherwise we assign 0. Thus the worse situation is fitness function has the value of 8. (ii) If each character appears only once is not true, assign fitness=9, because we want to indicate that it is worse than any of the cases in (i). 
  • Fitness Function= 0 + 1 + 1 + 1 + 1 + 0 + 1 + 1 = +6
  • +---+---+---+
    | 1 | 9 | 5 |
    +---+---+---+
    | 3 | 4 | 2 |
    +---+---+---+
    | 7 | 6 | 8 |
    +---+---+---+ 
  • Fitness Function= +9, because both 1 and 6 appear twice.
  • +---+---+---+
    | 1 | 1 | 4 |
    +---+---+---+
    | 3 | 9 | 6 |
    +---+---+---+
    | 7 | 2 | 6 |
    +---+---+---+
    
  • Java example:  I have a Java code here...




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.