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.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)
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.
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.
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; |
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; } |
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
Post a Comment