AI FIle 12e
AI FIle 12e
ARTIFICIAL INTELLIGENCE
THEORY:
Tic-tac-toe (also known as noughts and crosses or Xs and Os) is a paper-and-pencil game for
two players, X and O, who take turns marking the spaces in a 3×3 grid. The player who succeeds
in placing three of their marks in a horizontal, vertical, or diagonal row wins the game.
Because of the simplicity of tic-tac-toe, it is often used as a pedagogical tool for teaching the
concepts of good sportsmanship and the branch of artificial intelligence that deals with the
searching of game trees. It is straightforward to write a computer program to play tic-tac-toe
perfectly or to enumerate the 765 essentially different positions (the state space complexity) or
the 26,830 possible games up to rotations and reflections (the game tree complexity) on this
space
ALGORITHM:
In this Algorithm, instead of using a Bool variable for O and X, we use 2 for blank, 3 for X and 5
for O. There are three main sub procedures:
Function Make2:
The function is used to select an empty square for the Computer to move. The function first
checks for the center square and then for the non-corner squares.
Function PosWin:
The function is used to check whether the current player will win in the next move or not. It will
return 0 if win is not possible or index i indicating the next winning move. The function checks
every row, column and diagonal for a possible product of 18(2*3*3) or 50(2*5*5).
Function Go:
The function is used to place either an X or an O on the board.
CODE:
#include<bits/stdc++.h>
#include<windows.h>
using namespace std;
int board[3][3];
bool player = true;
bool draw = true;
//2 - Blank
//3 - X
//5 - O
//0 - X, 1 - O
void print_board()
{
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
if(board[i][j] == 2) {
cout<<" "<<"|";
}
else if(board[i][j] == 3) {
cout<<" X"<<"|";
}
else {
cout<<" O"<<"|";
}
}
cout<<endl;
}
cout<<endl;
}
pair<int, int> poss_win(bool p) {
int x;
if(p)
x=50;
else
x=18;
for(int i=0;i<3;i++)
{
if(board[i][0]*board[i][1]*board[i][2]==x)
{
if(board[i][0] == 2) return make_pair(i,0);
else if(board[i][1] == 2) return make_pair(i,1);
else return make_pair(i,2);
}
if(board[0][i]*board[1][i]*board[2][i]==x)
{
if(board[0][i] == 2) return make_pair(0,i);
else if(board[1][i] == 2) return make_pair(1,i);
else return make_pair(2,i);
}
}
if(board[0][0] * board[1][1] * board[2][2] == x)
{
if(board[0][0] == 2) return make_pair(0,0);
else if(board[1][1] == 2) return make_pair(1,1);
else return make_pair(2,2);
}
if(board[0][2] * board[1][1] * board[2][0] == x)
{
if(board[0][2] == 2) return make_pair(0,2);
else if(board[1][1] == 2) return make_pair(1,1);
else return make_pair(2,0);
}
return make_pair(-1,-1);
}
void go(pair<int, int> move)
{
int x = (player)?(5):(3);
board[move.first][move.second] = x;
print_board();
player = !player;
}
pair<int, int> make2() {
cout<<"\nAI is thinking...\n";
Sleep(2000);
if(board[1][1] == 2) return make_pair(1,1);
vector<pair<int, int> > cd;
if(board[0][1]== 2) cd.push_back(make_pair(0,1));
if(board[1][0]== 2) cd.push_back(make_pair(1,0));
if(board[1][2]== 2) cd.push_back(make_pair(1,2));
if(board[2][1]== 2) cd.push_back(make_pair(2,1));
if(cd.size() == 0) {
if(board[0][0] == 2) cd.push_back(make_pair(0,0));
if(board[0][2] == 2) cd.push_back(make_pair(0,2));
if(board[2][0] == 2) cd.push_back(make_pair(2,0));
if(board[2][2] == 2) cd.push_back(make_pair(2,2));
}
srand(time(NULL));
int pos = rand() % cd.size();
return cd[pos];
}
pair<int, int> user() {
int i,j;
cout<<"Input- ";
cin>>i;
--i;
return make_pair(i/3,i%3);
}
bool hasPlayerWon()
{
int x=125;
for(int i=0;i<3;i++)
{
if(board[i][0]*board[i][1]*board[i][2]==x)
{
if(board[i][0] == 2) return true;
else if(board[i][1] == 2) return true;
else return true;
}
if(board[0][i]*board[1][i]*board[2][i]==x)
{
if(board[0][i] == 2) return true;
else if(board[1][i] == 2) return true;
else return true;
}
}
if(board[0][0] * board[1][1] * board[2][2] == x)
{
if(board[0][0] == 2) return true;
else if(board[1][1] == 2) return true;
else return true;
}
if(board[0][2] * board[1][1] * board[2][0] == x)
{
if(board[0][2] == 2) return true;
else if(board[1][1] == 2) return true;
else return true;
}
return false;
}
int main()
{
system("color f0");
int moves = 9;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
board[i][j]=2;
while(moves--) {
if(player) {
go(user());
if(hasPlayerWon())
{
cout<<"Player Won\n";
draw=false;
break;
}
} else {
if(poss_win(player) == make_pair(-1,-1)) {
if(poss_win(!player) != make_pair(-1,-1)) {
go(poss_win(!player));
} else {
go(make2());
}
} else {
go(poss_win(player));
draw = false;
cout<<"AI Wins. \n";
break;
}
}
}
if(draw) cout<<"It's a draw. \n";
return 0;
}
OUTPUT:
DISCUSSION:
Advantages:
1. This implementation is space efficient. The previous method stored a copy of every
possible board orientation. The number of orientations possible are 3^9. Hence a vector
was declared of this size.
Disadvantages:
1. The program is not time efficient. The function posWin() takes more time to compute.
There are better alternatives available.
2. The program is not smart enough. The computer is easy to beat. The computer cannot force a
draw in every game.