Hello everyone, I find myself in need of creating an Unbeatable, or almost unbeatable AI for a school project. I've done the whole project so far without arrays, I have the player vs player done, but now I need the AI, which I'm unsure how to start with. All I need to do to finish this project is create a menu to change between player vs player and player vs machine and then the AI. Here's my coding so far, I can do the menu no problem, just the AI I need some help with. I'd appreciate it if you didn't just give me the coding to do it, but rather helped me understand it so I can learn from it. Thanks in advance.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.applet.*;
public class TICTACTOE extends Applet implements MouseListener, ActionListener{
Timer timer1;
int width=800, height=800; // screen size
Image backbuffer;
Image x;
Image x2;
Image x3;
Image x4;
Image x5;
Image x6;
Image x7;
Image x8;
Image x9;
Image o;
Image o2;
Image o3;
Image o4;
Image o5;
Image o6;
Image o7;
Image o8;
Image o9;
Image reset;
Graphics backg;
int ypos;
int xpos;
int mouse = 0;
int seconds=0;
int g1 = 0;
int g2 = 0;
int g3 = 0;
int g4 = 0;
int g5 = 0;
int g6 = 0;
int g7 = 0;
int g8 = 0;
int g9 = 0;
int res = 1;
String turn="mouse: "+mouse;
String dc = "Double Click";
String fin;
String game ="Games Played: ";
Image background;
public void init() {
setSize(800,800);
addMouseListener(this);
backbuffer = createImage( width, height );
backg = backbuffer.getGraphics();
background = getImage(getDocumentBase(), "background.png");
x = getImage(getDocumentBase(), "X.png");
x2 = getImage(getDocumentBase(), "X.png");
x3 = getImage(getDocumentBase(), "X.png");
x4 = getImage(getDocumentBase(), "X.png");
x5 = getImage(getDocumentBase(), "X.png");
x6 = getImage(getDocumentBase(), "X.png");
x7 = getImage(getDocumentBase(), "X.png");
x8 = getImage(getDocumentBase(), "X.png");
x9 = getImage(getDocumentBase(), "X.png");
o = getImage(getDocumentBase(), "O.png");
o2 = getImage(getDocumentBase(), "O.png");
o3 = getImage(getDocumentBase(), "O.png");
o4 = getImage(getDocumentBase(), "O.png");
o5 = getImage(getDocumentBase(), "O.png");
o6 = getImage(getDocumentBase(), "O.png");
o7 = getImage(getDocumentBase(), "O.png");
o8 = getImage(getDocumentBase(), "O.png");
o9 = getImage(getDocumentBase(), "O.png");
reset = getImage(getDocumentBase(), "reset.png");
timer1 = new Timer(5, this);
}
public void start(){
timer1.start();
}
public void stop(){
timer1.stop();
}
public void destroy(){
//System.exit(0);
}
public void mouseClicked (MouseEvent e) {
}
public void mouseEntered (MouseEvent e) {
}
public void mousePressed (MouseEvent e) {
xpos = e.getX();
ypos = e.getY();
// Player 1
if ((g1==0) && (mouse==0) && (xpos >= 0) && (xpos <= 266) && (ypos >= 0) && (ypos <= 266) )
{
g1 = 1;
System.out.println(" Grid Pressed");
mouse = 1;
}
if ((g2==0) && (mouse==0) && (xpos >= 266) && (xpos <= 535) && (ypos >= 0) && (ypos <= 266) )
{
g2 = 1;
System.out.println(" Grid Pressed");
mouse = 1;
}
if ((g3==0) && (mouse==0) && (xpos >= 535) && (xpos <= 801) && (ypos >= 0) && (ypos <= 266) )
{
g3 = 1;
System.out.println(" Grid Pressed");
mouse = 1;
}
if ((g4==0) && (mouse==0) && (xpos >= 0) && (xpos <= 266) && (ypos >= 266) && (ypos <= 535) )
{
g4 = 1;
System.out.println(" Grid Pressed");
mouse = 1;
}
if ((g5==0) && (mouse==0) && (xpos >= 266) && (xpos <= 535) && (ypos >= 366) && (ypos <= 535) )
{
g5 = 1;
System.out.println(" Grid Pressed");
mouse = 1;
}
if ((g6==0) && (mouse==0) && (xpos >= 535) && (xpos <= 800) && (ypos >= 266) && (ypos <= 535) )
{
g6 = 1;
System.out.println(" Grid Pressed");
mouse = 1;
}
if ((g7==0) && (mouse==0) && (xpos >= 0) && (xpos <= 266) && (ypos >= 535) && (ypos <= 800) )
{
g7 = 1;
System.out.println(" Grid Pressed");
mouse = 1;
}
if ((g8==0) && (mouse==0) && (xpos >= 266) && (xpos <= 535) && (ypos >= 535) && (ypos <= 800) )
{
g8 = 1;
System.out.println(" Grid Pressed");
mouse = 1;
}
if ((g9==0) && (mouse==0) && (xpos >= 535) && (xpos <= 800) && (ypos >= 535) && (ypos <= 800) )
{
g9 = 1;
System.out.println(" Grid Pressed");
mouse = 1;
}
// Player 2
if ((g1==0) && (mouse==1) && (xpos >= 0) && (xpos <= 266) && (ypos >= 0) && (ypos <= 266) )
{
g1 = 2;
System.out.println(" Grid Pressed");
mouse = 0;
}
if ((g2==0) && (mouse==1) && (xpos >= 266) && (xpos <= 535) && (ypos >= 0) && (ypos <= 266) )
{
g2 = 2;
System.out.println(" Grid Pressed");
mouse = 0;
}
if ((g3==0) && (mouse==1) && (xpos >= 535) && (xpos <= 801) && (ypos >= 0) && (ypos <= 266) )
{
g3 = 2;
System.out.println(" Grid Pressed");
mouse = 0;
}
if ((g4==0) && (mouse==1) && (xpos >= 0) && (xpos <= 266) && (ypos >= 266) && (ypos <= 535) )
{
g4 = 2;
System.out.println(" Grid Pressed");
mouse = 0;
}
if ((g5==0) && (mouse==1) && (xpos >= 266) && (xpos <= 535) && (ypos >= 366) && (ypos <= 535) )
{
g5 = 2;
System.out.println(" Grid Pressed");
mouse = 0;
}
if ((g6==0) && (mouse==1) && (xpos >= 535) && (xpos <= 800) && (ypos >= 266) && (ypos <= 535) )
{
g6 = 2;
System.out.println(" Grid Pressed");
mouse = 0;
}
if ((g7==0) && (mouse==1) && (xpos >= 0) && (xpos <= 266) && (ypos >= 535) && (ypos <= 800) )
{
g7 = 2;
System.out.println(" Grid Pressed");
mouse = 0;
}
if ((g8==0) && (mouse==1) && (xpos >= 266) && (xpos <= 535) && (ypos >= 535) && (ypos <= 800) )
{
g8 = 2;
System.out.println(" Grid Pressed");
mouse = 0;
}
if ((g9==0) && (mouse==1) && (xpos >= 535) && (xpos <= 800) && (ypos >= 535) && (ypos <= 800) )
{
g9 = 2;
System.out.println(" Grid Pressed");
mouse = 0;
}
if (xpos >=600 && xpos <=770 && ypos >= -30 && ypos <= 50 )
{
g1=0;
g2=0;
g3=0;
g4=0;
g5=0;
g6=0;
g7=0;
g8=0;
g9=0;
res= res +1;
mouse = 0;
}
}
public void mouseReleased (MouseEvent me) {
}
public void mouseExited (MouseEvent me) {
}
public void update( Graphics g ) {
g.drawImage( backbuffer, 0, 0, this );
}
public void paint( Graphics g ) {
update( g );
}
public void actionPerformed(ActionEvent e){
if(e.getSource() == timer1){
seconds++;
backg.drawImage(background,0,0,800,800,this);
backg.setColor( Color.white );
backg.drawLine (266, 0 ,266,800);
backg.drawLine (535, 0 ,535,800);
backg.drawLine (800, 266 ,0,266);
backg.drawLine (800, 535 ,0,535);
System.out.println(turn);
// Player 1
if (g1 == 1)
{
backg.drawImage(x,0,0,266,266,this);
}
if (g2 == 1)
{
backg.drawImage(x2,266,0,266,266,this);
}
if (g3 == 1)
{
backg.drawImage(x3,535,0,266,266,this);
}
if (g4 == 1)
{
backg.drawImage(x4,0,266,266,266,this);
}
if (g5 == 1)
{
backg.drawImage(x5,266,266,266,266,this);
}
if (g6 == 1)
{
backg.drawImage(x6,535,266,266,266,this);
}
if (g7 == 1)
{
backg.drawImage(x7,0,535,266,266,this);
}
if (g8 == 1)
{
backg.drawImage(x8,266,535,266,266,this);
}
if (g9 == 1)
{
backg.drawImage(x9,535,535,266,266,this);
}
// Player 2
if (g1 == 2)
{
backg.drawImage(o,0,0,266,266,this);
}
if (g2 == 2)
{
backg.drawImage(o2,266,0,266,266,this);
}
if (g3 == 2)
{
backg.drawImage(o3,535,0,266,266,this);
}
if (g4 == 2)
{
backg.drawImage(o4,0,266,266,266,this);
}
if (g5 == 2)
{
backg.drawImage(o5,266,266,266,266,this);
}
if (g6 == 2)
{
backg.drawImage(o6,535,266,266,266,this);
}
if (g7 == 2)
{
backg.drawImage(o7,0,535,266,266,this);
}
if (g8 == 2)
{
backg.drawImage(o8,266,535,266,266,this);
}
if (g9 == 2)
{
backg.drawImage(o9,535,535,266,266,this);
}
if ((g1==1 && g2==1 && g3==1) || (g1==1 && g4 == 1 && g7 == 1) || (g4 == 1 && g5==1 && g6==1) || (g7==1 && g8==1 && g9==1)
|| (g2==1 && g5==1 && g8==1) || (g3==1 && g6==1 && g9==1) || (g1==1 && g5==1 && g9==1) || (g3==1 && g5==1 && g7==1))
{
fin = "Player 1 Wins :D";
backg.setColor( Color.black );
backg.setFont(new Font("Areil", Font.PLAIN,35) );
backg.drawString(fin,320,450);
}
if ((g1==2 && g2==2 && g3==2) || (g1==2 && g4 == 2 && g7 == 2) || (g4 == 2 && g5==2 && g6==2) || (g7==2 && g8==2 && g9==2)
|| (g2==2 && g5==2 && g8==2) || (g3==2 && g6==2 && g9==2) || (g1==2 && g5==2 && g9==2) || (g3==2 && g5==2 && g7==2))
{
fin = "Player 2 Wins :D";
backg.setColor( Color.black );
backg.setFont(new Font("Areil", Font.PLAIN,35) );
backg.drawString(fin,320,450);
}
backg.drawImage(reset,600,-50,200,200,this);
backg.setColor( Color.red );
backg.setFont(new Font("Areil", Font.PLAIN,16) );
backg.drawString("Games Played: "+res,50,50);;
repaint();
}
}
}
P.S. I don`t know how to attach images, so you'll have to make your own images for x, o, and background.
Tic Tac Toe Ai
Started by
timo0060
, May 31 2011 08:55 PM
5 replies to this topic
#1
Posted 31 May 2011 - 08:55 PM
#2
Posted 01 June 2011 - 01:30 PM
Fun. I remember doing this myself.
One thing I'm wondering. Why do you copy the X and O images so many times? You should be able to repeat the same ones as many times as you want.
Way back when I did it I made an unbeatable program from a mess of if/else statements so it always followed exactly the same pattern so I've tried to think of a better way.
So here's my idea:
Each square should be given a weight.
Then give a score to each of the 8 lines it is possible to make a row of 3 on.
Add 1 point if the AI has that square, subtract 1 if the opponent does.
This would ignore preventing the opponent winning so if a line has a score of 2 increase it to 3 and if one has a score of -2 make it 2.
I would recommend storing the value of each grid square in an array rather than seperate values or at least copy them into one.
Once each line has a score. Loop through the scores and find the highest.
Then for each line that was equal to the highest score set the weight score for the individual squares
This step is not needed but will cause the AI to choose randomly among the available squares with an equal weighting which will hopefully make it appear more interesting.
Alternatively just keep the first found index of the high score.
Finally the AI has chosen a move to make so set the weight to 0 so it will not try to make the same move again. Weights must also be set to 0 when a player takes a square or it may try to overwrite their move.
I hope this is of some help to you. If you have any questions feel free to ask
One thing I'm wondering. Why do you copy the X and O images so many times? You should be able to repeat the same ones as many times as you want.
Way back when I did it I made an unbeatable program from a mess of if/else statements so it always followed exactly the same pattern so I've tried to think of a better way.
So here's my idea:
Each square should be given a weight.
int[] weights = {3,1,3,1,2,1,3,1,3};
This will always make it choose the corners first, followed by the middle.Then give a score to each of the 8 lines it is possible to make a row of 3 on.
Add 1 point if the AI has that square, subtract 1 if the opponent does.
This would ignore preventing the opponent winning so if a line has a score of 2 increase it to 3 and if one has a score of -2 make it 2.
I would recommend storing the value of each grid square in an array rather than seperate values or at least copy them into one.
int[] grid = {g1,g2,g3,g4,g5,g6,g7,g8,g9};
Also storing the grid squares that make up each line will allow the rest to be done with less repetition of code.
int[][] lines = new int[8][3];
lines[0] = {0,1,2};
lines[1] = {3,4,5};
lines[2] = {6,7,8};
lines[3] = {0,3,6};
lines[4] = {1,4,7};
lines[5] = {2,5,8};
lines[6] = {0,4,8};
lines[7] = {2,4,6};
int[] linescore = new int[8];
int ai;//if the AI is player 1 set this to 1. If it is player 2 set it to 2
for (int a = 0; a < 8; a++){
linescore[a] = 0;
for (int b = 0; b < 3; b++){
if (grid[lines[a][b]]==ai){linescore[a]++;} else if (grid[lines[a][b]]!=0){linescore[a]--;}
}
}
Once each line has a score. Loop through the scores and find the highest.
int high = 0;
for (int i = 0; i < 8; i++){
if (linescore[i]>high){high = linescore[i];}
}
Then for each line that was equal to the highest score set the weight score for the individual squares
int[] gridscore = new int[9];
for (int a = 0; a < 8; a++){
if (linescore[a]==high){
for (int b = 0; b < 3; b++){
gridscore[lines[a][b]] = weights[lines[a][b]];
}
}
This step is not needed but will cause the AI to choose randomly among the available squares with an equal weighting which will hopefully make it appear more interesting.
//Find the highest score
high = 0;//reusing the int high from earlier
for (int i = 0; i < 9; i++){
if (gridscore[i]>high){high = gridscore[i];}
}
//Count the number of squares with that score
int count = 0;
for (int i = 0; i < 9; i++){
if (gridscore[i]==high){count++;}
}
Random random = new Random();//requires importing java.util.Random
int x = random.nextInt(count);//returns an integer number between 0 and count (will always be less than count)
//Loop through the squares again and find the Xth occurance of the highest score
int move = -1; count = 0;
for (int i = 0; i<9&&move==-1; i++){
if (gridscore[i]==high){
if (count==x){move=i;} else{count++;}
}
Alternatively just keep the first found index of the high score.
high = 0;//reusing the int high from earlier
int index = -1;
for (int i = 0; i < 9; i++){
if (gridscore[i]>high){high = gridscore[i]; index=i;}
}
int move = index;
Finally the AI has chosen a move to make so set the weight to 0 so it will not try to make the same move again. Weights must also be set to 0 when a player takes a square or it may try to overwrite their move.
weights[move] = 0; grid[move] = ai;//Set the appropriate g value to the AIs player number
I hope this is of some help to you. If you have any questions feel free to ask
#3
Posted 01 June 2011 - 07:44 PM
That would help a lot, but unfortunately, I'm not using arrays. I haven't learned how to do arrays yet, but hopefully I'll e learning them for my final project. If you have a way to do it without arrays, and as little if/else if statements as possible, please inform me. I really don't like doing if statements, so I wanna learn arrays, but I'm gonna learn those for my next projects. Thanks for your help.
#4
Posted 01 June 2011 - 11:30 PM
How odd. You're using images and mouse listeners and yet you haven't learnt arrays yet? My old program was so basic that it displayed using System.out.println.
The best way I can think of is going with a fixed pattern through if/else statements. Something like this:
Also this method relies on another check to find and make/block winning moves. All I can think of right now is checking every possible winning combination.
Far, far simpler this time
The best way I can think of is going with a fixed pattern through if/else statements. Something like this:
int ai;//If the AI is player 1 set to 1. If it is player 2 set to 2
if (g1==0){g1=ai;}
else if (g5==0){g5==ai;}
else if (g3==0){g3==ai;}
else if (g7==0){g7==ai;}
else if (g9==0){g9==ai;}
else if (g2==0){g2==ai;}
else if (g4==0){g4==ai;}
else if (g6==0){g6==ai;}
else if (g8==0){g8==ai;}
I found the sequence 1,5,3,7,9,2,4,6,8 in my old code. It doesn't seem to be the best but I guess it might take into account preventing the opponent winning too. If that's no good you'll just have to find one that works.Also this method relies on another check to find and make/block winning moves. All I can think of right now is checking every possible winning combination.
if ((g1==ai)&&(g2==ai)&&(g3==0)){g3==ai;}
else if ((g1==ai)&&(g2==0)&&(g3==ai)){g2==ai;}
else if ((g1==0)&&(g2==ai)&&(g3==ai)){g1==ai;}
//Etcetera
It may be a good idea to put this check in a method and have it return -1 or something if there is no winning move. Then it can be used to find a win for the ai and block the opponent winning.Far, far simpler this time
#5
Posted 02 June 2011 - 07:21 PM
Thank you very much, this will surely help me a great deal. I also know it's a bit weird that we haven't learned arrays yet. Some people in our class have sacrificed their lunch to learn, but I like my lunch so I didn't, but now I wish I had.... Anyways, thank you once again.
#6
Posted 02 June 2011 - 08:41 PM
You're welcome.
Except for my tic-tac-toe program I never put in any extra effort until later when I started making games.
For future reference arrays are very simple. The basic way to create one is as follows:
The array elements can be accessed using the names myarray[0] and myarray[1].
The length of the array can be obtained with myarray.length.
E.g:
Except for my tic-tac-toe program I never put in any extra effort until later when I started making games.
For future reference arrays are very simple. The basic way to create one is as follows:
int[] myarray = new int[2];This creates an integer array 2 elements long called myarray. Array elements are numbered from 0.
The array elements can be accessed using the names myarray[0] and myarray[1].
The length of the array can be obtained with myarray.length.
E.g:
System.out.println(myarray.length);










