NetBeans Java project- TIC TAC TOE (AI) - logic explained

Greetings!
This article covers the basic concept of how you can implement basic AI in you game, i.e allow the computer to compete with you, giving it equal chances of winning. It's worth a thought what makes the computer invincible in a human vs computer chess game?

A common notion is that programmers code for every single possibility in the game considering all permutations and combinations etc. However this is far from reality. We can instead make the computer go by the 'Human thought process ' for every move. Lets consider a simpler approach to the popular TIC-TAC-TOE game.



Try out TIC TAC TOE here. (500 Kb executable .jar file)



Coming to the TIC-TAC-TOE GAME. This project is a great exercise for beginners to get a hang of basic logic used in games and other applications.
The logic behind the computer's moves is simpler than you think. To begin with, lets see the logical flow of code before getting into the 'code'.
Here's how the code works-

After every move you play it's the computers chance to play- 

1) For the very first move -the computer plays a random corner (after ensuring not to overwrite a corner marked by the user).
2) Second move onward the computer checks for two things- 
  a) Check if the computer can win in a single move. If yes, mark that box.
   b) Check if the human can win in a single move. If yes, mark the winning         move.
3) Else, play a random move, with preference given to corners.
4) Apart from these steps you may write codes for more specific cases that you wish the computer to understand, such as simple winning strategies like blocking a corner when the user marks the centre. 


Leave some strategies for the user to win :)

Once you're done writing the basic code as mentioned above you can go about writing codes for tackling situations wherever the computer lost against you, moving one step closer to a completely 'invincible' version of tic tac toe !

Moving on to the programming syntax and logic.
This project is made on NetBeans Java 8.1 and requires the understanding of basic programming concepts.
It's always better to write codes for such projects yourself than copying things off the internet as such programs appear to be 'complex' to the reader but are very easily understood by the one who wrote it.
However you may use the following hints if you're clueless about any particular idea mentioned above.

------------------------------THE CODE BEGINS HERE------------------------------

So, those boxes in the frame are simply 'jLabels' in NetBeans (yep, 9 of em).
And we are performing a function whenever the MouseClicked action listener is
activated!
and this is what happens every time the mouse clicks on a label-

1
2
3
4
5
6
7
8
9
private void l1MouseClicked(java.awt.event.MouseEvent evt) {                                
if(a1==0){
    l1.setText("X");
    a1++;
    computerplay();
}
checkandend();
      
    }     

First things first, whats a1? 
I've created nine integer variables-


1
int a1=0,a2=0,a3=0,a4=0,a5=0,a6=0,a7=0,a8=0,a9=0;
and a few variables used later-


1

2

3

4

5

6
int a1=0,a2=0,a3=0,a4=0,a5=0,a6=0,a7=0,a8=0,a9=0;

int arr[]={a1,a2,a3,a4,a5,a6,a7,a8,a9};

int check[]={1,3,7,9,2,4,5,6,8};

int edge[]={2,4,6,8};

int corner[]={1,3,7,9};

int computerwins=0;




Each variable holds data corresponding to one label letting us know whether its marked 'X', 'O' or is simply empty!
When a box is marked X by the user, we set the value of the corresponding variable to 1, or set it to 2 if the computer marks that label.
Suppose the user clicks label1 (named as l1 in  the code above), the value of a1 is set to 1.
After each time the user plays a move, the computerplay() function is called, where the computer plays its move. Here where the logic comes in picture.

WARNING: Nerdy stuff ahead-


1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
void computerplay(){
int cornerplayed=0;
if (a1==1 && a9==1){
 cornerplayed=1;
}
else if(a3==1 && a7==1)
     cornerplayed=1;
//the corner played variable tells if any two diagonally opposite corners are marked by the user.
//lolwa is a variable that keeps track of who starts first i.e you or comp
//When lolwa is divisible by two the computer starts else we start
//After every game lolwa increases by one.
//played integer tells if the computer has played its move for the given chance
    int played=0;
  
 if (lolwa%2==1 && played==0 && chance==1){
     if(a2==1 || a4==1 || a6 ==1 || a8==1){
      mark(5);
      played=1;
      chance++;
     }
     
 }
 if (lolwa%2==0 && played==0 && chance==0){
     if(a2==1 || a4==1 || a6 ==1 || a8==1){
      mark(5);
      played=1;
      chance++;
     }
     
 }
if (chance==0 && played==0){ //for the first  move mark the center if the user marks a corner
  if(a1==1 || a3==1 || a7 ==1 || a9==1){
      mark(5);
      played=1;
      chance++;
  }

  else{ 
    Random x= new Random();
    for (int p=0;p<=1000;p++){
int need=x.nextInt(5);
if (mark(corner[need])==true){
   chance++;
   played=1;
    break;
}
}}//forloop ends here
  }
if(played==0 && chance==1 && cornerplayed==1 && lolwa%2==1 ){
       for (int p=0;p<=4;p++){

if (mark(edge[p])==true){
   chance++;
   played=1;
    break;
}
}
  }
if(played==0 && chance==1 && cornerplayed==1 && lolwa%2==0 ){
       for (int p=0;p<=4;p++){

if (mark(edge[p])==true){
   chance++;
   played=1;
    break;
}
}
  }
if(played==0 && chance==1 && cornerplayed==0 && lolwa%2==1 ){
    if(a4==1){
        if (mark(1)) {
            chance++;
   played=1; 
        }
            else{
            mark(7);
        chance++;
   played=1;
    }
    }
         if(a6==1){
          if (mark(3)) {
            chance++;
   played=1; 
        }
            else{
            mark(9);
        chance++;
   played=1;
    }
    }
   if(a2==1){
          if (mark(1)) {
            chance++;
   played=1; 
        }
            else{
            mark(3);
        chance++;
   played=1;
    }
    }
         if(a8==1){
          if (mark(7)) {
            chance++;
   played=1; 
        }
            else{
            mark(9);
        chance++;
   played=1;
    }
    }
     
}
else if(chance>0 && played==0){// check for computer victory
    for (int p=0;p<=8;p++){
    boolean checker=computerMark(check[p]);  
      
    if (computervictory()==true){
        computerUnmark(check[p]);
        mark(check[p]);
        System.out.println("GOT It its"+ check[p]);
      played=7;
        break;
    }else if(checker){
 computerUnmark(check[p]);
    }
  }   
    
}
 if (chance>0 && played==0){
  for (int p=0;p<=8;p++){
    boolean damn=humanmark(check[p]);  
      //block human' move
    if (humanvictory()==true){
        humanUnmark(check[p]);
        mark(check[p]);
        System.out.println("GOT It its"+ check[p]);
      played=1;
        break;
    }else if(damn){
 humanUnmark(check[p]);
    }
  }  
}
 if (played==0){
       //play a random move if nothing else works
    for (int p=0;p<=8;p++){

if (mark(check[p])==true){
   chance++;
   played=1;
    break;
}
}
}

}

That might seem to be an overdose if you're not java friendly yet, but yeah, this code is definitely not optimised and is really hap hazard. The main purpose of sharing it- is to help you understand the core idea and not how to go about it.

Here's the code for the mark() function-



1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
boolean mark(int a){
    boolean isdone=false;
     if(a==1 && a1==0){
         l1.setText("O");
         isdone=true;
         a1=2;
     }
     else if(a==2 && a2==0){
         l2.setText("O");
         isdone=true;
         a2=2;
     }
       else if(a==3 && a3==0){
         l3.setText("O");
         isdone=true;
         a3=2;
     }
       else if(a==4 && a4==0){
         l4.setText("O");
         isdone=true;
         a4=2;
     }
       else if(a==5 && a5==0){
         l5.setText("O");
         isdone=true;
         a5=2;
     }
       else if(a==6 && a6==0){
         l6.setText("O");
         isdone=true;
         a6=2;
     }
       else if(a==7 && a7==0){
         l7.setText("O");
         isdone=true;
         a7=2;
     }
       else if(a==8 && a8==0){
         l8.setText("O");
         isdone=true;
         a8=2;
     }
       else if(a==9 && a9==0){
         l9.setText("O");
         isdone=true;
         a9=2;
     }
     return isdone;
 }
The unmark function is similar to the mark function but does the exact opposite.

And finally here's how the computer checks for 'humanvictory' before blocking the user's winning move-



1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
boolean humanvictory(){
     boolean what=false;
    if (a1==1 && a2==1 && a3==1)
       what= true;
    else if(a4==1 && a5==1 && a6==1)
       what= true;
     else if(a7==1 && a8==1 && a9==1)
         what= true;
      else if(a1==1 && a5==1 && a9==1)
         what= true;
       else if(a3==1 && a5==1 && a7==1)
         what= true;
        else if(a1==1 && a4==1 && a7==1)
        what= true;
         else if(a2==1 && a5==1 && a8==1)
         what= true;
          else if(a3==1 && a6==1 && a9==1)
         what= true;
  return what;
}

And that's a good dose of code for today :)
I plan to reorganise this code and make it simpler sometime, once I'm done with my high school leaving examinations.

Till then -Cheers­čŹĚ
                                                                
                                                                                           -Siddharth 







Comments

Popular Posts