Feb 23, 2014 at 9:56am UTC
Hello folks !
This is my first post here and I'm sort of a beginner in C++. Learnt the basics in my junior year and am on my way to senior ! Here's a tic-tac-toe program I made with an AI and I believe it is impossible to defeat the AI though it is possible for the AI to win or draw the match. This is the first half of my Tic-tac-toe project which lets you do the first move. (The second part has the AI do the first move and is more "attacking in nature")
I would appreciate tips regarding shortening the program and the like. I have also added comments where necessary and would like to help out regarding any block of code.
#include <iostream>
using namespace std;
void player_move(char A[3][3])
{
int x;
cout << '\n' << "Enter the square";
cin >> x;
if(x == 1 && A[0][0] == '.')
A[0][0] = 'X';
else if(x == 2 && A[0][1] == '.')
A[0][1] = 'X';
else if(x == 3 && A[0][2] == '.')
A[0][2] = 'X';
else if(x == 4 && A[1][0] == '.')
A[1][0] = 'X';
else if(x == 5 && A[1][1] == '.')
A[1][1] = 'X';
else if(x == 6 && A[1][2] == '.')
A[1][2] = 'X';
else if(x == 7 && A[2][0] == '.')
A[2][0] = 'X';
else if(x == 8 && A[2][1] == '.')
A[2][1] = 'X';
else if(x == 9 && A[2][2] == '.')
A[2][2] = 'X';
}
int checkpw(char A[3][3])
{ int p = 2;
if(A[0][0] == 'X' && A[0][1] == 'X' && A[0][2] == 'X')
p=0;
else if(A[1][0] == 'X' && A[1][1] == 'X' && A[1][2] == 'X')
p=0;
else if(A[2][0] == 'X' && A[2][1] == 'X' && A[2][2] == 'X')
p=0;
else if(A[0][0] == 'X' && A[1][0] == 'X' && A[2][0] == 'X')
p=0;
else if(A[0][1] == 'X' && A[1][1] == 'X' && A[2][1] == 'X')
p=0;
else if(A[0][2] == 'X' && A[1][2] == 'X' && A[2][2] == 'X')
p=0;
else if(A[0][0] == 'X' && A[1][1] == 'X' && A[2][2] == 'X')
p=0;
else if(A[0][2] == 'X' && A[1][1] == 'X' && A[2][0] == 'X')
p=0;
return p;
}
int checkcw(char A[3][3])
{ int p=0;
// Horizontal 1
if(A[0][0] == 'O' && A[0][1] == 'O' && A[0][2] == '.')
{A[0][2] = 'O';p=1;}
else if(A[0][0] == 'O' && A[0][2] == 'O' && A[0][1] == '.')
{A[0][1] = 'O';p=1;}
else if(A[0][1] == 'O' && A[0][2] == 'O' && A[0][0] == '.')
{A[0][0] = 'O';p=1;}
// Horizontal 2
else if(A[1][0] == 'O' && A[1][1] == 'O' && A[1][2] == '.')
{A[1][2] = 'O';p=1;}
else if(A[1][0] == 'O' && A[1][2] == 'O' && A[1][1] == '.')
{A[1][1] = 'O';p=1;}
else if(A[1][1] == 'O' && A[1][2] == 'O' && A[1][0] == '.')
{A[1][0] = 'O';p=1;}
// Horizontal 3
else if(A[2][0] == 'O' && A[2][1] == 'O' && A[2][2] == '.')
{A[2][2] = 'O';p=1;}
else if(A[2][0] == 'O' && A[2][2] == 'O' && A[2][1] == '.')
{A[2][1] = 'O';p=1;}
else if(A[2][1] == 'O' && A[2][2] == 'O' && A[2][0] == '.')
{A[2][0] = 'O';p=1;}
// Vertical 1
else if(A[0][0] == 'O' && A[1][0] == 'O' && A[2][0] == '.')
{A[2][0] = 'O';p=1;}
else if(A[0][0] == 'O' && A[2][0] == 'O' && A[1][0] == '.')
{A[1][0] = 'O';p=1;}
else if(A[1][0] == 'O' && A[2][0] == 'O' && A[0][0] == '.')
{A[0][0] = 'O';p=1;}
// Vertical 2
else if(A[0][1] == 'O' && A[1][1] == 'O' && A[2][1] == '.')
{A[2][1] = 'O';p=1;}
else if(A[0][1] == 'O' && A[2][1] == 'O' && A[1][1] == '.')
{A[1][1] = 'O';p=1;}
else if(A[1][1] == 'O' && A[2][1] == 'O' && A[0][1] == '.')
{A[0][1] = 'O';p=1;}
// Vertical 3
else if(A[0][2] == 'O' && A[1][2] == 'O' && A[2][2] == '.')
{A[2][2] = 'O';p=1;}
else if(A[0][2] == 'O' && A[2][2] == 'O' && A[1][2] == '.')
{A[1][2] = 'O';p=1;}
else if(A[1][2] == 'O' && A[2][2] == 'O' && A[0][2] == '.')
{A[0][2] = 'O';p=1;}
// Diagonal Left-Right
else if(A[0][0] == 'O' && A[1][1] == 'O' && A[2][2] == '.')
{A[2][2] = 'O';p=1;}
else if(A[0][0] == 'O' && A[2][2] == 'O' && A[1][1] == '.')
{A[1][1] = 'O';p=1;}
else if(A[1][1] == 'O' && A[2][2] == 'O' && A[0][0] == '.')
{A[0][0] = 'O';p=1;}
// Diagonal Right-Left
else if(A[0][2] == 'O' && A[1][1] == 'O' && A[2][0] == '.')
{A[2][0] = 'O';p=1;}
else if(A[0][2] == 'O' && A[2][0] == 'O' && A[1][1] == '.')
{A[1][1] = 'O';p=1;}
else if(A[1][1] == 'O' && A[2][0] == 'O' && A[0][2] == '.')
{A[0][2] = 'O';p=1;}
return p;
}
int checkifpw(char A[3][3])
{ int p=0;
// Horizontal 1
if(A[0][0] == 'X' && A[0][1] == 'X' && A[0][2] == '.')
{A[0][2] = 'O';p=1;}
else if(A[0][0] == 'X' && A[0][2] == 'X' && A[0][1] == '.')
{A[0][1] = 'O';p=1;}
else if(A[0][1] == 'X' && A[0][2] == 'X' && A[0][0] == '.')
{A[0][0] = 'O';p=1;}
// Horizontal 2
else if(A[1][0] == 'X' && A[1][1] == 'X' && A[1][2] == '.')
{A[1][2] = 'O';p=1;}
else if(A[1][0] == 'X' && A[1][2] == 'X' && A[1][1] == '.')
{A[1][1] = 'O';p=1;}
else if(A[1][1] == 'X' && A[1][2] == 'X' && A[1][0] == '.')
{A[1][0] = 'O';p=1;}
// Horizontal 3
else if(A[2][0] == 'X' && A[2][1] == 'X' && A[2][2] == '.')
{A[2][2] = 'O';p=1;}
else if(A[2][0] == 'X' && A[2][2] == 'X' && A[2][1] == '.')
{A[2][1] = 'O';p=1;}
else if(A[2][1] == 'X' && A[2][2] == 'X' && A[2][0] == '.')
{A[2][0] = 'O';p=1;}
// Vertical 1
else if(A[0][0] == 'X' && A[1][0] == 'X' && A[2][0] == '.')
{A[2][0] = 'O';p=1;}
else if(A[0][0] == 'X' && A[2][0] == 'X' && A[1][0] == '.')
{A[1][0] = 'O';p=1;}
else if(A[1][0] == 'X' && A[2][0] == 'X' && A[0][0] == '.')
{A[0][0] = 'O';p=1;}
// Vertical 2
else if(A[0][1] == 'X' && A[1][1] == 'X' && A[2][1] == '.')
{A[2][1] = 'O';p=1;}
else if(A[0][1] == 'X' && A[2][1] == 'X' && A[1][1] == '.')
{A[1][1] = 'O';p=1;}
else if(A[1][1] == 'X' && A[2][1] == 'X' && A[0][1] == '.')
{A[0][1] = 'O';p=1;}
// Vertical 3
else if(A[0][2] == 'X' && A[1][2] == 'X' && A[2][2] == '.')
{A[2][2] = 'O';p=1;}
else if(A[0][2] == 'X' && A[2][2] == 'X' && A[1][2] == '.')
{A[1][2] = 'O';p=1;}
else if(A[1][2] == 'X' && A[2][2] == 'X' && A[0][2] == '.')
{A[0][2] = 'O';p=1;}
// Diagonal Left-Right
else if(A[0][0] == 'X' && A[1][1] == 'X' && A[2][2] == '.')
{A[2][2] = 'O';p=1;}
else if(A[0][0] == 'X' && A[2][2] == 'X' && A[1][1] == '.')
{A[1][1] = 'O';p=1;}
else if(A[1][1] == 'X' && A[2][2] == 'X' && A[0][0] == '.')
{A[0][0] = 'O';p=1;}
// Diagonal Right-Left
else if(A[0][2] == 'X' && A[1][1] == 'X' && A[2][0] == '.')
{A[2][0] = 'O';p=1;}
else if(A[0][2] == 'X' && A[2][0] == 'X' && A[1][1] == '.')
{A[1][1] = 'O';p=1;}
else if(A[1][1] == 'X' && A[2][0] == 'X' && A[0][2] == '.')
{A[0][2] = 'O';p=1;}
return p;
}
int trapcheck(char A[3][3])
{ int p = 0;
// Diagonal-check
if(A[0][0] == 'X' && A[1][1] == 'O' && A[2][2] == 'X' && A[2][1] == '.')
{A[2][1] = 'O';p=1;}
else if(A[0][0] == 'X' && A[1][1] == 'O' && A[2][2] == 'X' && A[0][1] == '.')
{A[0][1] = 'O';p=1;}
else if(A[0][2] == 'X' && A[1][1] == 'O' && A[2][0] == 'X' && A[2][1] == '.')
{A[2][1] = 'O';p=1;}
else if(A[0][0] == 'X' && A[1][1] == 'O' && A[2][2] == 'X' && A[0][1] == '.')
{A[0][1] = 'O';p=1;}
// L-check
else if(A[0][2] == 'X' && A[2][1] == 'X' && A[2][2] == '.')
{A[2][2] = 'O';p=1;}
else if(A[0][0] == 'X' && A[2][1] == 'X' && A[2][0] == '.')
{A[2][0] = 'O';p=1;}
else if(A[2][0] == 'X' && A[0][1] == 'X' && A[0][0] == '.')
{A[0][0] = 'O';p=1;}
else if(A[2][2] == 'X' && A[0][1] == 'X' && A[0][2] == '.')
{A[0][2] = 'O';p=1;}
else if(A[0][2] == 'X' && A[1][0] == 'X' && A[0][0] == '.')
{A[0][0] = 'O';p=1;}
else if(A[2][2] == 'X' && A[1][0] == 'X' && A[2][0] == '.')
{A[2][0] = 'O';p=1;}
else if(A[0][0] == 'X' && A[1][2] == 'X' && A[0][2] == '.')
{A[0][2] = 'O';p=1;}
else if(A[2][0] == 'X' && A[1][2] == 'X' && A[2][2] == '.')
{A[2][2] = 'O';p=1;}
return p;
}
void show_game(char A[3][3])
{
int i,j=0;
for(i=0;i<2;i++)
{
cout << A[i][j] << " | " << A[i][j+1] << " | " << A[i][j+2] << '\n';
cout << "--+---+--" << '\n';
}
cout << A[i][j] << " | " << A[i][j+1] << " | " << A[i][j+2] << '\n';
}
void main()
{
while(true)
{
int p,q,r;
char A[3][3] = {'.','.','.','.','.','.','.','.','.'};
show_game(A);
cout << endl << endl;
for(int i=0;i<5;i++)
{
player_move(A);
p=checkpw(A);
if(p==0)
break;
q=checkcw(A);
if(q==0)
r=checkifpw(A);
else
{
show_game(A);
cout << endl << endl;
break;
}
if(q==0 && r==0)
{
if(A[1][1]=='.')
A[1][1]='O';
else if(trapcheck(A) == 0)
{
if(A[0][0] == '.')
A[0][0] = 'O';
else if(A[0][2] == '.')
A[0][2] = 'O';
else if(A[2][0] == '.')
A[2][0] = 'O';
else if(A[2][2] == '.')
A[2][2] = 'O';
else if(A[0][1] == '.')
A[0][1] = 'O';
else if(A[1][0] == '.')
A[1][0] = 'O';
else if(A[1][2] == '.')
A[1][2] = 'O';
else if(A[2][1] == '.')
A[2][1] = 'O';
}
}
cout << endl << endl;
show_game(A);
}
if(q==1)
cout << " HAHAHA YOU LOSE ! \n \n";
else if (p==0)
cout << " OMG YOU MUST BE A GENIUS ! YOU WIN ! \n \n";
else
cout << "DRAW ! \n \n";
system("pause");
system("CLS");
}
}
Feb 23, 2014 at 6:05pm UTC
Thanks :-) I'm not really familiar with Boolean functions, but will look into it now as it REALLY saves a lot of space :-) Thank you :)
A small problem with that is even after the computer gets a 3 in a row against me, it does not show that I lost. It takes another run so that the 3 in a row is proved.
In my method, it checks if it can win, puts an O in there and immediately changes the value of p to 1 (which is q in void main). The 'else' proves it false and it breaks out of the loop.
In your method, it will check if there's a 3 in a row first instead of checking the possibility and hence won't ALWAYS win. (Try entering squares in the order 1,2,9 and see what happens)
Besides that, I think it's an excellent way of doing this. So, thanks again.
Last edited on Feb 23, 2014 at 6:56pm UTC
Feb 25, 2014 at 7:59am UTC
I shortened the code using another logic but has the for loop similar to yours. It uses a position algorithm to determine the win and I will post that here. I've also added a return function in every statement so that it saves execution time. Doesn't have to run through the entire thing once it finds a match.
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
int checkpw(char A[3][3])
{ int p=2,i;
for (i=0;i<3;i++)
if (A[i][0] == 'X' && A[i][1] == 'X' && A[i][2] == 'X' )
{p=0;return p;}
for (i=0;i<3;i++)
if (A[0][i] == 'X' && A[1][i] == 'X' && A[2][i] == 'X' )
{p=0;return p;}
if (A[0][0] == 'X' && A[1][1] == 'X' && A[2][2] == 'X' )
{p=0;return p;}
if (A[0][2] == 'X' && A[1][1] == 'X' && A[2][0] == 'X' )
{p=0;return p;}
return p;
}
int checkcw(char A[3][3])
{ int p=0,i,j;
// Horizontals
for (i=0;i<3;i++)
for (j=0;j<3;j++)
if (A[i][j] == 'O' && A[i][(j+2)%3] == 'O' && A[i][3-(j+((j+2)%3))] == '.' )
{A[i][3-(j+((j+2)%3))] = 'O' ;p=1;return p;}
// Verticals
for (j=0;j<3;j++)
for (i=0;i<3;i++)
if (A[i][j] == 'O' && A[(i+2)%3][j] == 'O' && A[3-(i+((i+2)%3))][j] == '.' )
{A[3-(i+((i+2)%3))][j] = 'O' ;p=1;return p;}
// Diagonal Left-Right
for (i=0,j=0;i<3&&j<3;i++,j++)
if (A[i][j] == 'O' && A[(i+2)%3][(j+2)%3] == 'O' && A[3-(i+((i+2)%3))][3-(j+((j+2)%3))] == '.' )
{A[3-(i+((i+2)%3))][3-(j+((j+2)%3))] = 'O' ;p=1;return p;}
// Diagonal Right-Left
for (i=0,j=2;i<3&&j>=0;i++,j--)
if (A[i][j] == 'O' && A[(i+2)%3][(j+1)%3] == 'O' && A[3-(i+((i+2)%3))][3-(j+((j+1)%3))] == '.' )
{A[3-(i+((i+2)%3))][3-(j+((j+1)%3))] = 'O' ;p=1;return p;}
return p;
}
However with that additional function you provided, the program looks neat. Thanks !
Last edited on Feb 25, 2014 at 10:06am UTC