A command-line unbeatable Tic-Tac-Toe written in C
$begingroup$
I'm trying to learn programming and this Tic-Tac-Toe is one of my first projects. The user gets to start first as 'x' or second as 'o'.
Please give me any criticism you find on the code and give suggestions on where I can improve the structure and style.
#include <stdio.h>
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
/*the print function will be called after every input by the user*/
void print(char (*GRID)[7])
{
/*length and breadth of the grid of a tic-tac-toe game is 3*3*/
int length=7, breadth=7,i,j;
printf("nTic-Tac-Toe by Udhay Sankarnn");
for(i=0;i<length;i++)
{
printf(" ");
for(j=0;j<breadth;j++)
{
printf("%c",GRID[i][j]);
}
printf("n");
}
}
/*function to check the validity of user input*/
int valid(char (*GRID)[7],int TEMP1)
{
if(((TEMP1)>0)&&((TEMP1)<10))
{
switch (TEMP1)
{
case 1:
if (GRID[1][1]=='x'||GRID[1][1]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 2:
if (GRID[1][3]=='x'||GRID[1][3]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 3:
if (GRID[1][5]=='x'||GRID[1][5]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 4:
if (GRID[3][1]=='x'||GRID[3][1]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 5:
if (GRID[3][3]=='x'||GRID[3][3]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 6:
if (GRID[3][5]=='x'||GRID[3][5]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 7:
if (GRID[5][1]=='x'||GRID[5][1]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 8:
if (GRID[5][3]=='x'||GRID[5][3]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 9:
if (GRID[5][5]=='x'||GRID[5][5]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
}
}
else
{
return 0;
}
}
/*function to get input from user*/
void get_input(char (*GRID)[7],int turn)
{
int TEMP2;
if(1==turn)
{
printf("nConsider the 3*3 grid with 9 positionsnnIf position is row 2 column 3, Enter 6 as inputnnEnter your position for 'x': ");
}
else
{
printf("nConsider the 3*3 grid with 9 positionsnnIf position is row 2 column 3, Enter 6 as inputnnEnter your position for 'o': ");
}
scanf("%d",&TEMP2);
while((valid(GRID,TEMP2))!=1)
{
//if position is already occupied
printf("nInvalid Input! Enter a valid positionn");
if(1==turn)
{
printf("nConsider the 3*3 grid with 9 positionsnnIf position is row 2 column 3, Enter 6 as inputnnEnter your position for 'x': ");
}
else
{
printf("nConsider the 3*3 grid with 9 positionsnnIf position is row 2 column 3, Enter 6 as inputnnEnter your position for 'o': ");
}
scanf("%d",&TEMP2);
}
if(1==turn)
{
switch (TEMP2)
{
case 1:GRID[1][1]='x';
break;
case 2:GRID[1][3]='x';
break;
case 3:GRID[1][5]='x';
break;
case 4:GRID[3][1]='x';
break;
case 5:GRID[3][3]='x';
break;
case 6:GRID[3][5]='x';
break;
case 7:GRID[5][1]='x';
break;
case 8:GRID[5][3]='x';
break;
case 9:GRID[5][5]='x';
break;
}
}
else
{
switch (TEMP2)
{
case 1:GRID[1][1]='o';
break;
case 2:GRID[1][3]='o';
break;
case 3:GRID[1][5]='o';
break;
case 4:GRID[3][1]='o';
break;
case 5:GRID[3][3]='o';
break;
case 6:GRID[3][5]='o';
break;
case 7:GRID[5][1]='o';
break;
case 8:GRID[5][3]='o';
break;
case 9:GRID[5][5]='o';
break;
}
}
}
//function to find the number of available available_spots
int available_spots(char (*GRID)[7])
{
int spots=0;
for(int i=1;i<6;i=i+2)
for(int j=1;j<6;j=j+2)
{
if (GRID[i][j]==' ')
spots++;
}
return spots;
}
//function to check for win condition after every move from user and computer
int terminal_state(char (*GRID)[7])
{
if (((GRID[1][1]=='o')&&(GRID[1][3]=='o'))&&((GRID[1][3]=='o')&&(GRID[1][5]=='o')))
{
return -10;
}
else if (((GRID[3][1]=='o')&&(GRID[3][3]=='o'))&&((GRID[3][3]=='o')&&(GRID[3][5]=='o')))
{
return -10;
}
else if (((GRID[5][1]=='o')&&(GRID[5][3]=='o'))&&((GRID[5][3]=='o')&&(GRID[5][5]=='o')))
{
return -10;
}
else if (((GRID[1][1]=='o')&&(GRID[3][1]=='o'))&&((GRID[3][1]=='o')&&(GRID[5][1]=='o')))
{
return -10;
}
else if (((GRID[1][3]=='o')&&(GRID[3][3]=='o'))&&((GRID[3][3]=='o')&&(GRID[5][3]=='o')))
{
return -10;
}
else if (((GRID[1][5]=='o')&&(GRID[3][5]=='o'))&&((GRID[3][5]=='o')&&(GRID[5][5]=='o')))
{
return -10;
}
else if (((GRID[1][1]=='o')&&(GRID[3][3]=='o'))&&((GRID[3][3]=='o')&&(GRID[5][5]=='o')))
{
return -10;
}
else if (((GRID[1][5]=='o')&&(GRID[3][3]=='o'))&&((GRID[3][3]=='o')&&(GRID[5][1]=='o')))
{
return -10;
}
if (((GRID[1][1]=='x')&&(GRID[1][3]=='x'))&&((GRID[1][3]=='x')&&(GRID[1][5]=='x')))
{
return 10;
}
else if (((GRID[3][1]=='x')&&(GRID[3][3]=='x'))&&((GRID[3][3]=='x')&&(GRID[3][5]=='x')))
{
return 10;
}
else if (((GRID[5][1]=='x')&&(GRID[5][3]=='x'))&&((GRID[5][3]=='x')&&(GRID[5][5]=='x')))
{
return 10;
}
else if (((GRID[1][1]=='x')&&(GRID[3][1]=='x'))&&((GRID[3][1]=='x')&&(GRID[5][1]=='x')))
{
return 10;
}
else if (((GRID[1][3]=='x')&&(GRID[3][3]=='x'))&&((GRID[3][3]=='x')&&(GRID[5][3]=='x')))
{
return 10;
}
else if (((GRID[1][5]=='x')&&(GRID[3][5]=='x'))&&((GRID[3][5]=='x')&&(GRID[5][5]=='x')))
{
return 10;
}
else if (((GRID[1][1]=='x')&&(GRID[3][3]=='x'))&&((GRID[3][3]=='x')&&(GRID[5][5]=='x')))
{
return 10;
}
else if (((GRID[1][5]=='x')&&(GRID[3][3]=='x'))&&((GRID[3][3]=='x')&&(GRID[5][1]=='x')))
{
return 10;
}
else if(available_spots(GRID)==0)
return 0;
}
/*function of minimax algorithm that is recursive*/
int minimax(char (*GRID)[7],int turn)
{
//
int best;
if(terminal_state(GRID)==10)
return 10;
if(terminal_state(GRID)==-10)
return -10;
if(terminal_state(GRID)==0)
return 0;
//
if(0==turn)
{
int i,j;
int temp;
best=1000;
for(int i=1;i<6;i=i+2)
{
for(int j=1;j<6;j=j+2)
{
if(GRID[i][j]==' ')
{
GRID[i][j]='o';
temp=minimax(GRID,1);
best=MIN(temp,best);
GRID[i][j]=' ';
}
}
}
return best;
}
else if(1==turn)
{
int i,j;
int temp;
best=-1000;
for(i=1;i<6;i=i+2)
{
for(j=1;j<6;j=j+2)
{
if(GRID[i][j]==' ')
{
GRID[i][j]='x';
temp=minimax(GRID,0);
best=MAX(temp,best);
GRID[i][j]=' ';
}
}
}
return best;
}
}
//the following function returns the best move
void computer_position(char (*GRID)[7],int turn)
{
if(0==turn)
{
int sample=1000;
int computer_move[3];
computer_move[0]=sample;
for(int i=1;i<6;i=i+2)
{
for(int j=1;j<6;j=j+2)
{
if(GRID[i][j]==' ')
{
GRID[i][j]='o';
sample=minimax(GRID,!turn);
if(sample<computer_move[0])
{
computer_move[0]=sample;
computer_move[1]=i;
computer_move[2]=j;
}
GRID[i][j]=' ';
}
}
}
GRID[computer_move[1]][computer_move[2]]='o';
}
else
{
int sample=-1000;
int computer_move[3];
computer_move[0]=sample;
for(int i=1;i<6;i=i+2)
{
for(int j=1;j<6;j=j+2)
{
if(GRID[i][j]==' ')
{
GRID[i][j]='x';
sample=minimax(GRID,!turn);
if(sample>computer_move[0])
{
computer_move[0]=sample;
computer_move[1]=i;
computer_move[2]=j;
}
GRID[i][j]=' ';
}
}
}
GRID[computer_move[1]][computer_move[2]]='x';
}
}
/*main function*/
int main()
{
//int USR_INPUT,RESULT;
char GRID[7][7]={
{'-','-','-','-','-','-','-'},
{'|',' ','|',' ','|',' ','|'},
{'-','-','-','-','-','-','-'},
{'|',' ','|',' ','|',' ','|'},
{'-','-','-','-','-','-','-'},
{'|',' ','|',' ','|',' ','|'},
{'-','-','-','-','-','-','-'}
};
int turn;
//get the turn from the user
printf("nDo you want to go first as 'x', or second as 'o'?n");
printf("nEnter 1 for 'x' or 0 for 'o':");
scanf("%d",&turn);
while((turn!=0)&&(turn!=1))
{
printf("nInvalid value for turn!n");
printf("nDo you want to go first as 'x', or second as 'o'?n");
printf("nEnter 1 for 'x' or 0 for 'o':");
scanf("%d",&turn);
}
//when no spots are available or a win condition is obtained
if(1==turn)
{
while(available_spots(GRID)!=0)
{
print(GRID);
get_input(GRID,turn);
if(terminal_state(GRID)==10)
{
print(GRID);
printf("nYou have wonnn");
return 0;
}else if (terminal_state(GRID)==-10) {
print(GRID);
printf("nComputer has wonnn");
return 0;
}else if (terminal_state(GRID)==0) {
print(GRID);
printf("nThe game is a drawnn");
return 0;
}
computer_position(GRID,!turn);
}
}
else
{
while(available_spots(GRID)!=0)
{
computer_position(GRID,!turn);
if(terminal_state(GRID)==-10)
{
print(GRID);
printf("nYou have wonnn");
return 0;
}else if (terminal_state(GRID)==10) {
print(GRID);
printf("nComputer has wonnn");
return 0;
}else if (terminal_state(GRID)==0) {
print(GRID);
printf("nThe game is a drawnn");
return 0;
}
print(GRID);
get_input(GRID,turn);
}
}
}
beginner c tic-tac-toe ai
New contributor
$endgroup$
add a comment |
$begingroup$
I'm trying to learn programming and this Tic-Tac-Toe is one of my first projects. The user gets to start first as 'x' or second as 'o'.
Please give me any criticism you find on the code and give suggestions on where I can improve the structure and style.
#include <stdio.h>
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
/*the print function will be called after every input by the user*/
void print(char (*GRID)[7])
{
/*length and breadth of the grid of a tic-tac-toe game is 3*3*/
int length=7, breadth=7,i,j;
printf("nTic-Tac-Toe by Udhay Sankarnn");
for(i=0;i<length;i++)
{
printf(" ");
for(j=0;j<breadth;j++)
{
printf("%c",GRID[i][j]);
}
printf("n");
}
}
/*function to check the validity of user input*/
int valid(char (*GRID)[7],int TEMP1)
{
if(((TEMP1)>0)&&((TEMP1)<10))
{
switch (TEMP1)
{
case 1:
if (GRID[1][1]=='x'||GRID[1][1]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 2:
if (GRID[1][3]=='x'||GRID[1][3]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 3:
if (GRID[1][5]=='x'||GRID[1][5]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 4:
if (GRID[3][1]=='x'||GRID[3][1]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 5:
if (GRID[3][3]=='x'||GRID[3][3]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 6:
if (GRID[3][5]=='x'||GRID[3][5]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 7:
if (GRID[5][1]=='x'||GRID[5][1]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 8:
if (GRID[5][3]=='x'||GRID[5][3]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 9:
if (GRID[5][5]=='x'||GRID[5][5]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
}
}
else
{
return 0;
}
}
/*function to get input from user*/
void get_input(char (*GRID)[7],int turn)
{
int TEMP2;
if(1==turn)
{
printf("nConsider the 3*3 grid with 9 positionsnnIf position is row 2 column 3, Enter 6 as inputnnEnter your position for 'x': ");
}
else
{
printf("nConsider the 3*3 grid with 9 positionsnnIf position is row 2 column 3, Enter 6 as inputnnEnter your position for 'o': ");
}
scanf("%d",&TEMP2);
while((valid(GRID,TEMP2))!=1)
{
//if position is already occupied
printf("nInvalid Input! Enter a valid positionn");
if(1==turn)
{
printf("nConsider the 3*3 grid with 9 positionsnnIf position is row 2 column 3, Enter 6 as inputnnEnter your position for 'x': ");
}
else
{
printf("nConsider the 3*3 grid with 9 positionsnnIf position is row 2 column 3, Enter 6 as inputnnEnter your position for 'o': ");
}
scanf("%d",&TEMP2);
}
if(1==turn)
{
switch (TEMP2)
{
case 1:GRID[1][1]='x';
break;
case 2:GRID[1][3]='x';
break;
case 3:GRID[1][5]='x';
break;
case 4:GRID[3][1]='x';
break;
case 5:GRID[3][3]='x';
break;
case 6:GRID[3][5]='x';
break;
case 7:GRID[5][1]='x';
break;
case 8:GRID[5][3]='x';
break;
case 9:GRID[5][5]='x';
break;
}
}
else
{
switch (TEMP2)
{
case 1:GRID[1][1]='o';
break;
case 2:GRID[1][3]='o';
break;
case 3:GRID[1][5]='o';
break;
case 4:GRID[3][1]='o';
break;
case 5:GRID[3][3]='o';
break;
case 6:GRID[3][5]='o';
break;
case 7:GRID[5][1]='o';
break;
case 8:GRID[5][3]='o';
break;
case 9:GRID[5][5]='o';
break;
}
}
}
//function to find the number of available available_spots
int available_spots(char (*GRID)[7])
{
int spots=0;
for(int i=1;i<6;i=i+2)
for(int j=1;j<6;j=j+2)
{
if (GRID[i][j]==' ')
spots++;
}
return spots;
}
//function to check for win condition after every move from user and computer
int terminal_state(char (*GRID)[7])
{
if (((GRID[1][1]=='o')&&(GRID[1][3]=='o'))&&((GRID[1][3]=='o')&&(GRID[1][5]=='o')))
{
return -10;
}
else if (((GRID[3][1]=='o')&&(GRID[3][3]=='o'))&&((GRID[3][3]=='o')&&(GRID[3][5]=='o')))
{
return -10;
}
else if (((GRID[5][1]=='o')&&(GRID[5][3]=='o'))&&((GRID[5][3]=='o')&&(GRID[5][5]=='o')))
{
return -10;
}
else if (((GRID[1][1]=='o')&&(GRID[3][1]=='o'))&&((GRID[3][1]=='o')&&(GRID[5][1]=='o')))
{
return -10;
}
else if (((GRID[1][3]=='o')&&(GRID[3][3]=='o'))&&((GRID[3][3]=='o')&&(GRID[5][3]=='o')))
{
return -10;
}
else if (((GRID[1][5]=='o')&&(GRID[3][5]=='o'))&&((GRID[3][5]=='o')&&(GRID[5][5]=='o')))
{
return -10;
}
else if (((GRID[1][1]=='o')&&(GRID[3][3]=='o'))&&((GRID[3][3]=='o')&&(GRID[5][5]=='o')))
{
return -10;
}
else if (((GRID[1][5]=='o')&&(GRID[3][3]=='o'))&&((GRID[3][3]=='o')&&(GRID[5][1]=='o')))
{
return -10;
}
if (((GRID[1][1]=='x')&&(GRID[1][3]=='x'))&&((GRID[1][3]=='x')&&(GRID[1][5]=='x')))
{
return 10;
}
else if (((GRID[3][1]=='x')&&(GRID[3][3]=='x'))&&((GRID[3][3]=='x')&&(GRID[3][5]=='x')))
{
return 10;
}
else if (((GRID[5][1]=='x')&&(GRID[5][3]=='x'))&&((GRID[5][3]=='x')&&(GRID[5][5]=='x')))
{
return 10;
}
else if (((GRID[1][1]=='x')&&(GRID[3][1]=='x'))&&((GRID[3][1]=='x')&&(GRID[5][1]=='x')))
{
return 10;
}
else if (((GRID[1][3]=='x')&&(GRID[3][3]=='x'))&&((GRID[3][3]=='x')&&(GRID[5][3]=='x')))
{
return 10;
}
else if (((GRID[1][5]=='x')&&(GRID[3][5]=='x'))&&((GRID[3][5]=='x')&&(GRID[5][5]=='x')))
{
return 10;
}
else if (((GRID[1][1]=='x')&&(GRID[3][3]=='x'))&&((GRID[3][3]=='x')&&(GRID[5][5]=='x')))
{
return 10;
}
else if (((GRID[1][5]=='x')&&(GRID[3][3]=='x'))&&((GRID[3][3]=='x')&&(GRID[5][1]=='x')))
{
return 10;
}
else if(available_spots(GRID)==0)
return 0;
}
/*function of minimax algorithm that is recursive*/
int minimax(char (*GRID)[7],int turn)
{
//
int best;
if(terminal_state(GRID)==10)
return 10;
if(terminal_state(GRID)==-10)
return -10;
if(terminal_state(GRID)==0)
return 0;
//
if(0==turn)
{
int i,j;
int temp;
best=1000;
for(int i=1;i<6;i=i+2)
{
for(int j=1;j<6;j=j+2)
{
if(GRID[i][j]==' ')
{
GRID[i][j]='o';
temp=minimax(GRID,1);
best=MIN(temp,best);
GRID[i][j]=' ';
}
}
}
return best;
}
else if(1==turn)
{
int i,j;
int temp;
best=-1000;
for(i=1;i<6;i=i+2)
{
for(j=1;j<6;j=j+2)
{
if(GRID[i][j]==' ')
{
GRID[i][j]='x';
temp=minimax(GRID,0);
best=MAX(temp,best);
GRID[i][j]=' ';
}
}
}
return best;
}
}
//the following function returns the best move
void computer_position(char (*GRID)[7],int turn)
{
if(0==turn)
{
int sample=1000;
int computer_move[3];
computer_move[0]=sample;
for(int i=1;i<6;i=i+2)
{
for(int j=1;j<6;j=j+2)
{
if(GRID[i][j]==' ')
{
GRID[i][j]='o';
sample=minimax(GRID,!turn);
if(sample<computer_move[0])
{
computer_move[0]=sample;
computer_move[1]=i;
computer_move[2]=j;
}
GRID[i][j]=' ';
}
}
}
GRID[computer_move[1]][computer_move[2]]='o';
}
else
{
int sample=-1000;
int computer_move[3];
computer_move[0]=sample;
for(int i=1;i<6;i=i+2)
{
for(int j=1;j<6;j=j+2)
{
if(GRID[i][j]==' ')
{
GRID[i][j]='x';
sample=minimax(GRID,!turn);
if(sample>computer_move[0])
{
computer_move[0]=sample;
computer_move[1]=i;
computer_move[2]=j;
}
GRID[i][j]=' ';
}
}
}
GRID[computer_move[1]][computer_move[2]]='x';
}
}
/*main function*/
int main()
{
//int USR_INPUT,RESULT;
char GRID[7][7]={
{'-','-','-','-','-','-','-'},
{'|',' ','|',' ','|',' ','|'},
{'-','-','-','-','-','-','-'},
{'|',' ','|',' ','|',' ','|'},
{'-','-','-','-','-','-','-'},
{'|',' ','|',' ','|',' ','|'},
{'-','-','-','-','-','-','-'}
};
int turn;
//get the turn from the user
printf("nDo you want to go first as 'x', or second as 'o'?n");
printf("nEnter 1 for 'x' or 0 for 'o':");
scanf("%d",&turn);
while((turn!=0)&&(turn!=1))
{
printf("nInvalid value for turn!n");
printf("nDo you want to go first as 'x', or second as 'o'?n");
printf("nEnter 1 for 'x' or 0 for 'o':");
scanf("%d",&turn);
}
//when no spots are available or a win condition is obtained
if(1==turn)
{
while(available_spots(GRID)!=0)
{
print(GRID);
get_input(GRID,turn);
if(terminal_state(GRID)==10)
{
print(GRID);
printf("nYou have wonnn");
return 0;
}else if (terminal_state(GRID)==-10) {
print(GRID);
printf("nComputer has wonnn");
return 0;
}else if (terminal_state(GRID)==0) {
print(GRID);
printf("nThe game is a drawnn");
return 0;
}
computer_position(GRID,!turn);
}
}
else
{
while(available_spots(GRID)!=0)
{
computer_position(GRID,!turn);
if(terminal_state(GRID)==-10)
{
print(GRID);
printf("nYou have wonnn");
return 0;
}else if (terminal_state(GRID)==10) {
print(GRID);
printf("nComputer has wonnn");
return 0;
}else if (terminal_state(GRID)==0) {
print(GRID);
printf("nThe game is a drawnn");
return 0;
}
print(GRID);
get_input(GRID,turn);
}
}
}
beginner c tic-tac-toe ai
New contributor
$endgroup$
add a comment |
$begingroup$
I'm trying to learn programming and this Tic-Tac-Toe is one of my first projects. The user gets to start first as 'x' or second as 'o'.
Please give me any criticism you find on the code and give suggestions on where I can improve the structure and style.
#include <stdio.h>
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
/*the print function will be called after every input by the user*/
void print(char (*GRID)[7])
{
/*length and breadth of the grid of a tic-tac-toe game is 3*3*/
int length=7, breadth=7,i,j;
printf("nTic-Tac-Toe by Udhay Sankarnn");
for(i=0;i<length;i++)
{
printf(" ");
for(j=0;j<breadth;j++)
{
printf("%c",GRID[i][j]);
}
printf("n");
}
}
/*function to check the validity of user input*/
int valid(char (*GRID)[7],int TEMP1)
{
if(((TEMP1)>0)&&((TEMP1)<10))
{
switch (TEMP1)
{
case 1:
if (GRID[1][1]=='x'||GRID[1][1]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 2:
if (GRID[1][3]=='x'||GRID[1][3]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 3:
if (GRID[1][5]=='x'||GRID[1][5]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 4:
if (GRID[3][1]=='x'||GRID[3][1]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 5:
if (GRID[3][3]=='x'||GRID[3][3]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 6:
if (GRID[3][5]=='x'||GRID[3][5]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 7:
if (GRID[5][1]=='x'||GRID[5][1]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 8:
if (GRID[5][3]=='x'||GRID[5][3]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 9:
if (GRID[5][5]=='x'||GRID[5][5]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
}
}
else
{
return 0;
}
}
/*function to get input from user*/
void get_input(char (*GRID)[7],int turn)
{
int TEMP2;
if(1==turn)
{
printf("nConsider the 3*3 grid with 9 positionsnnIf position is row 2 column 3, Enter 6 as inputnnEnter your position for 'x': ");
}
else
{
printf("nConsider the 3*3 grid with 9 positionsnnIf position is row 2 column 3, Enter 6 as inputnnEnter your position for 'o': ");
}
scanf("%d",&TEMP2);
while((valid(GRID,TEMP2))!=1)
{
//if position is already occupied
printf("nInvalid Input! Enter a valid positionn");
if(1==turn)
{
printf("nConsider the 3*3 grid with 9 positionsnnIf position is row 2 column 3, Enter 6 as inputnnEnter your position for 'x': ");
}
else
{
printf("nConsider the 3*3 grid with 9 positionsnnIf position is row 2 column 3, Enter 6 as inputnnEnter your position for 'o': ");
}
scanf("%d",&TEMP2);
}
if(1==turn)
{
switch (TEMP2)
{
case 1:GRID[1][1]='x';
break;
case 2:GRID[1][3]='x';
break;
case 3:GRID[1][5]='x';
break;
case 4:GRID[3][1]='x';
break;
case 5:GRID[3][3]='x';
break;
case 6:GRID[3][5]='x';
break;
case 7:GRID[5][1]='x';
break;
case 8:GRID[5][3]='x';
break;
case 9:GRID[5][5]='x';
break;
}
}
else
{
switch (TEMP2)
{
case 1:GRID[1][1]='o';
break;
case 2:GRID[1][3]='o';
break;
case 3:GRID[1][5]='o';
break;
case 4:GRID[3][1]='o';
break;
case 5:GRID[3][3]='o';
break;
case 6:GRID[3][5]='o';
break;
case 7:GRID[5][1]='o';
break;
case 8:GRID[5][3]='o';
break;
case 9:GRID[5][5]='o';
break;
}
}
}
//function to find the number of available available_spots
int available_spots(char (*GRID)[7])
{
int spots=0;
for(int i=1;i<6;i=i+2)
for(int j=1;j<6;j=j+2)
{
if (GRID[i][j]==' ')
spots++;
}
return spots;
}
//function to check for win condition after every move from user and computer
int terminal_state(char (*GRID)[7])
{
if (((GRID[1][1]=='o')&&(GRID[1][3]=='o'))&&((GRID[1][3]=='o')&&(GRID[1][5]=='o')))
{
return -10;
}
else if (((GRID[3][1]=='o')&&(GRID[3][3]=='o'))&&((GRID[3][3]=='o')&&(GRID[3][5]=='o')))
{
return -10;
}
else if (((GRID[5][1]=='o')&&(GRID[5][3]=='o'))&&((GRID[5][3]=='o')&&(GRID[5][5]=='o')))
{
return -10;
}
else if (((GRID[1][1]=='o')&&(GRID[3][1]=='o'))&&((GRID[3][1]=='o')&&(GRID[5][1]=='o')))
{
return -10;
}
else if (((GRID[1][3]=='o')&&(GRID[3][3]=='o'))&&((GRID[3][3]=='o')&&(GRID[5][3]=='o')))
{
return -10;
}
else if (((GRID[1][5]=='o')&&(GRID[3][5]=='o'))&&((GRID[3][5]=='o')&&(GRID[5][5]=='o')))
{
return -10;
}
else if (((GRID[1][1]=='o')&&(GRID[3][3]=='o'))&&((GRID[3][3]=='o')&&(GRID[5][5]=='o')))
{
return -10;
}
else if (((GRID[1][5]=='o')&&(GRID[3][3]=='o'))&&((GRID[3][3]=='o')&&(GRID[5][1]=='o')))
{
return -10;
}
if (((GRID[1][1]=='x')&&(GRID[1][3]=='x'))&&((GRID[1][3]=='x')&&(GRID[1][5]=='x')))
{
return 10;
}
else if (((GRID[3][1]=='x')&&(GRID[3][3]=='x'))&&((GRID[3][3]=='x')&&(GRID[3][5]=='x')))
{
return 10;
}
else if (((GRID[5][1]=='x')&&(GRID[5][3]=='x'))&&((GRID[5][3]=='x')&&(GRID[5][5]=='x')))
{
return 10;
}
else if (((GRID[1][1]=='x')&&(GRID[3][1]=='x'))&&((GRID[3][1]=='x')&&(GRID[5][1]=='x')))
{
return 10;
}
else if (((GRID[1][3]=='x')&&(GRID[3][3]=='x'))&&((GRID[3][3]=='x')&&(GRID[5][3]=='x')))
{
return 10;
}
else if (((GRID[1][5]=='x')&&(GRID[3][5]=='x'))&&((GRID[3][5]=='x')&&(GRID[5][5]=='x')))
{
return 10;
}
else if (((GRID[1][1]=='x')&&(GRID[3][3]=='x'))&&((GRID[3][3]=='x')&&(GRID[5][5]=='x')))
{
return 10;
}
else if (((GRID[1][5]=='x')&&(GRID[3][3]=='x'))&&((GRID[3][3]=='x')&&(GRID[5][1]=='x')))
{
return 10;
}
else if(available_spots(GRID)==0)
return 0;
}
/*function of minimax algorithm that is recursive*/
int minimax(char (*GRID)[7],int turn)
{
//
int best;
if(terminal_state(GRID)==10)
return 10;
if(terminal_state(GRID)==-10)
return -10;
if(terminal_state(GRID)==0)
return 0;
//
if(0==turn)
{
int i,j;
int temp;
best=1000;
for(int i=1;i<6;i=i+2)
{
for(int j=1;j<6;j=j+2)
{
if(GRID[i][j]==' ')
{
GRID[i][j]='o';
temp=minimax(GRID,1);
best=MIN(temp,best);
GRID[i][j]=' ';
}
}
}
return best;
}
else if(1==turn)
{
int i,j;
int temp;
best=-1000;
for(i=1;i<6;i=i+2)
{
for(j=1;j<6;j=j+2)
{
if(GRID[i][j]==' ')
{
GRID[i][j]='x';
temp=minimax(GRID,0);
best=MAX(temp,best);
GRID[i][j]=' ';
}
}
}
return best;
}
}
//the following function returns the best move
void computer_position(char (*GRID)[7],int turn)
{
if(0==turn)
{
int sample=1000;
int computer_move[3];
computer_move[0]=sample;
for(int i=1;i<6;i=i+2)
{
for(int j=1;j<6;j=j+2)
{
if(GRID[i][j]==' ')
{
GRID[i][j]='o';
sample=minimax(GRID,!turn);
if(sample<computer_move[0])
{
computer_move[0]=sample;
computer_move[1]=i;
computer_move[2]=j;
}
GRID[i][j]=' ';
}
}
}
GRID[computer_move[1]][computer_move[2]]='o';
}
else
{
int sample=-1000;
int computer_move[3];
computer_move[0]=sample;
for(int i=1;i<6;i=i+2)
{
for(int j=1;j<6;j=j+2)
{
if(GRID[i][j]==' ')
{
GRID[i][j]='x';
sample=minimax(GRID,!turn);
if(sample>computer_move[0])
{
computer_move[0]=sample;
computer_move[1]=i;
computer_move[2]=j;
}
GRID[i][j]=' ';
}
}
}
GRID[computer_move[1]][computer_move[2]]='x';
}
}
/*main function*/
int main()
{
//int USR_INPUT,RESULT;
char GRID[7][7]={
{'-','-','-','-','-','-','-'},
{'|',' ','|',' ','|',' ','|'},
{'-','-','-','-','-','-','-'},
{'|',' ','|',' ','|',' ','|'},
{'-','-','-','-','-','-','-'},
{'|',' ','|',' ','|',' ','|'},
{'-','-','-','-','-','-','-'}
};
int turn;
//get the turn from the user
printf("nDo you want to go first as 'x', or second as 'o'?n");
printf("nEnter 1 for 'x' or 0 for 'o':");
scanf("%d",&turn);
while((turn!=0)&&(turn!=1))
{
printf("nInvalid value for turn!n");
printf("nDo you want to go first as 'x', or second as 'o'?n");
printf("nEnter 1 for 'x' or 0 for 'o':");
scanf("%d",&turn);
}
//when no spots are available or a win condition is obtained
if(1==turn)
{
while(available_spots(GRID)!=0)
{
print(GRID);
get_input(GRID,turn);
if(terminal_state(GRID)==10)
{
print(GRID);
printf("nYou have wonnn");
return 0;
}else if (terminal_state(GRID)==-10) {
print(GRID);
printf("nComputer has wonnn");
return 0;
}else if (terminal_state(GRID)==0) {
print(GRID);
printf("nThe game is a drawnn");
return 0;
}
computer_position(GRID,!turn);
}
}
else
{
while(available_spots(GRID)!=0)
{
computer_position(GRID,!turn);
if(terminal_state(GRID)==-10)
{
print(GRID);
printf("nYou have wonnn");
return 0;
}else if (terminal_state(GRID)==10) {
print(GRID);
printf("nComputer has wonnn");
return 0;
}else if (terminal_state(GRID)==0) {
print(GRID);
printf("nThe game is a drawnn");
return 0;
}
print(GRID);
get_input(GRID,turn);
}
}
}
beginner c tic-tac-toe ai
New contributor
$endgroup$
I'm trying to learn programming and this Tic-Tac-Toe is one of my first projects. The user gets to start first as 'x' or second as 'o'.
Please give me any criticism you find on the code and give suggestions on where I can improve the structure and style.
#include <stdio.h>
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
/*the print function will be called after every input by the user*/
void print(char (*GRID)[7])
{
/*length and breadth of the grid of a tic-tac-toe game is 3*3*/
int length=7, breadth=7,i,j;
printf("nTic-Tac-Toe by Udhay Sankarnn");
for(i=0;i<length;i++)
{
printf(" ");
for(j=0;j<breadth;j++)
{
printf("%c",GRID[i][j]);
}
printf("n");
}
}
/*function to check the validity of user input*/
int valid(char (*GRID)[7],int TEMP1)
{
if(((TEMP1)>0)&&((TEMP1)<10))
{
switch (TEMP1)
{
case 1:
if (GRID[1][1]=='x'||GRID[1][1]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 2:
if (GRID[1][3]=='x'||GRID[1][3]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 3:
if (GRID[1][5]=='x'||GRID[1][5]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 4:
if (GRID[3][1]=='x'||GRID[3][1]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 5:
if (GRID[3][3]=='x'||GRID[3][3]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 6:
if (GRID[3][5]=='x'||GRID[3][5]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 7:
if (GRID[5][1]=='x'||GRID[5][1]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 8:
if (GRID[5][3]=='x'||GRID[5][3]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 9:
if (GRID[5][5]=='x'||GRID[5][5]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
}
}
else
{
return 0;
}
}
/*function to get input from user*/
void get_input(char (*GRID)[7],int turn)
{
int TEMP2;
if(1==turn)
{
printf("nConsider the 3*3 grid with 9 positionsnnIf position is row 2 column 3, Enter 6 as inputnnEnter your position for 'x': ");
}
else
{
printf("nConsider the 3*3 grid with 9 positionsnnIf position is row 2 column 3, Enter 6 as inputnnEnter your position for 'o': ");
}
scanf("%d",&TEMP2);
while((valid(GRID,TEMP2))!=1)
{
//if position is already occupied
printf("nInvalid Input! Enter a valid positionn");
if(1==turn)
{
printf("nConsider the 3*3 grid with 9 positionsnnIf position is row 2 column 3, Enter 6 as inputnnEnter your position for 'x': ");
}
else
{
printf("nConsider the 3*3 grid with 9 positionsnnIf position is row 2 column 3, Enter 6 as inputnnEnter your position for 'o': ");
}
scanf("%d",&TEMP2);
}
if(1==turn)
{
switch (TEMP2)
{
case 1:GRID[1][1]='x';
break;
case 2:GRID[1][3]='x';
break;
case 3:GRID[1][5]='x';
break;
case 4:GRID[3][1]='x';
break;
case 5:GRID[3][3]='x';
break;
case 6:GRID[3][5]='x';
break;
case 7:GRID[5][1]='x';
break;
case 8:GRID[5][3]='x';
break;
case 9:GRID[5][5]='x';
break;
}
}
else
{
switch (TEMP2)
{
case 1:GRID[1][1]='o';
break;
case 2:GRID[1][3]='o';
break;
case 3:GRID[1][5]='o';
break;
case 4:GRID[3][1]='o';
break;
case 5:GRID[3][3]='o';
break;
case 6:GRID[3][5]='o';
break;
case 7:GRID[5][1]='o';
break;
case 8:GRID[5][3]='o';
break;
case 9:GRID[5][5]='o';
break;
}
}
}
//function to find the number of available available_spots
int available_spots(char (*GRID)[7])
{
int spots=0;
for(int i=1;i<6;i=i+2)
for(int j=1;j<6;j=j+2)
{
if (GRID[i][j]==' ')
spots++;
}
return spots;
}
//function to check for win condition after every move from user and computer
int terminal_state(char (*GRID)[7])
{
if (((GRID[1][1]=='o')&&(GRID[1][3]=='o'))&&((GRID[1][3]=='o')&&(GRID[1][5]=='o')))
{
return -10;
}
else if (((GRID[3][1]=='o')&&(GRID[3][3]=='o'))&&((GRID[3][3]=='o')&&(GRID[3][5]=='o')))
{
return -10;
}
else if (((GRID[5][1]=='o')&&(GRID[5][3]=='o'))&&((GRID[5][3]=='o')&&(GRID[5][5]=='o')))
{
return -10;
}
else if (((GRID[1][1]=='o')&&(GRID[3][1]=='o'))&&((GRID[3][1]=='o')&&(GRID[5][1]=='o')))
{
return -10;
}
else if (((GRID[1][3]=='o')&&(GRID[3][3]=='o'))&&((GRID[3][3]=='o')&&(GRID[5][3]=='o')))
{
return -10;
}
else if (((GRID[1][5]=='o')&&(GRID[3][5]=='o'))&&((GRID[3][5]=='o')&&(GRID[5][5]=='o')))
{
return -10;
}
else if (((GRID[1][1]=='o')&&(GRID[3][3]=='o'))&&((GRID[3][3]=='o')&&(GRID[5][5]=='o')))
{
return -10;
}
else if (((GRID[1][5]=='o')&&(GRID[3][3]=='o'))&&((GRID[3][3]=='o')&&(GRID[5][1]=='o')))
{
return -10;
}
if (((GRID[1][1]=='x')&&(GRID[1][3]=='x'))&&((GRID[1][3]=='x')&&(GRID[1][5]=='x')))
{
return 10;
}
else if (((GRID[3][1]=='x')&&(GRID[3][3]=='x'))&&((GRID[3][3]=='x')&&(GRID[3][5]=='x')))
{
return 10;
}
else if (((GRID[5][1]=='x')&&(GRID[5][3]=='x'))&&((GRID[5][3]=='x')&&(GRID[5][5]=='x')))
{
return 10;
}
else if (((GRID[1][1]=='x')&&(GRID[3][1]=='x'))&&((GRID[3][1]=='x')&&(GRID[5][1]=='x')))
{
return 10;
}
else if (((GRID[1][3]=='x')&&(GRID[3][3]=='x'))&&((GRID[3][3]=='x')&&(GRID[5][3]=='x')))
{
return 10;
}
else if (((GRID[1][5]=='x')&&(GRID[3][5]=='x'))&&((GRID[3][5]=='x')&&(GRID[5][5]=='x')))
{
return 10;
}
else if (((GRID[1][1]=='x')&&(GRID[3][3]=='x'))&&((GRID[3][3]=='x')&&(GRID[5][5]=='x')))
{
return 10;
}
else if (((GRID[1][5]=='x')&&(GRID[3][3]=='x'))&&((GRID[3][3]=='x')&&(GRID[5][1]=='x')))
{
return 10;
}
else if(available_spots(GRID)==0)
return 0;
}
/*function of minimax algorithm that is recursive*/
int minimax(char (*GRID)[7],int turn)
{
//
int best;
if(terminal_state(GRID)==10)
return 10;
if(terminal_state(GRID)==-10)
return -10;
if(terminal_state(GRID)==0)
return 0;
//
if(0==turn)
{
int i,j;
int temp;
best=1000;
for(int i=1;i<6;i=i+2)
{
for(int j=1;j<6;j=j+2)
{
if(GRID[i][j]==' ')
{
GRID[i][j]='o';
temp=minimax(GRID,1);
best=MIN(temp,best);
GRID[i][j]=' ';
}
}
}
return best;
}
else if(1==turn)
{
int i,j;
int temp;
best=-1000;
for(i=1;i<6;i=i+2)
{
for(j=1;j<6;j=j+2)
{
if(GRID[i][j]==' ')
{
GRID[i][j]='x';
temp=minimax(GRID,0);
best=MAX(temp,best);
GRID[i][j]=' ';
}
}
}
return best;
}
}
//the following function returns the best move
void computer_position(char (*GRID)[7],int turn)
{
if(0==turn)
{
int sample=1000;
int computer_move[3];
computer_move[0]=sample;
for(int i=1;i<6;i=i+2)
{
for(int j=1;j<6;j=j+2)
{
if(GRID[i][j]==' ')
{
GRID[i][j]='o';
sample=minimax(GRID,!turn);
if(sample<computer_move[0])
{
computer_move[0]=sample;
computer_move[1]=i;
computer_move[2]=j;
}
GRID[i][j]=' ';
}
}
}
GRID[computer_move[1]][computer_move[2]]='o';
}
else
{
int sample=-1000;
int computer_move[3];
computer_move[0]=sample;
for(int i=1;i<6;i=i+2)
{
for(int j=1;j<6;j=j+2)
{
if(GRID[i][j]==' ')
{
GRID[i][j]='x';
sample=minimax(GRID,!turn);
if(sample>computer_move[0])
{
computer_move[0]=sample;
computer_move[1]=i;
computer_move[2]=j;
}
GRID[i][j]=' ';
}
}
}
GRID[computer_move[1]][computer_move[2]]='x';
}
}
/*main function*/
int main()
{
//int USR_INPUT,RESULT;
char GRID[7][7]={
{'-','-','-','-','-','-','-'},
{'|',' ','|',' ','|',' ','|'},
{'-','-','-','-','-','-','-'},
{'|',' ','|',' ','|',' ','|'},
{'-','-','-','-','-','-','-'},
{'|',' ','|',' ','|',' ','|'},
{'-','-','-','-','-','-','-'}
};
int turn;
//get the turn from the user
printf("nDo you want to go first as 'x', or second as 'o'?n");
printf("nEnter 1 for 'x' or 0 for 'o':");
scanf("%d",&turn);
while((turn!=0)&&(turn!=1))
{
printf("nInvalid value for turn!n");
printf("nDo you want to go first as 'x', or second as 'o'?n");
printf("nEnter 1 for 'x' or 0 for 'o':");
scanf("%d",&turn);
}
//when no spots are available or a win condition is obtained
if(1==turn)
{
while(available_spots(GRID)!=0)
{
print(GRID);
get_input(GRID,turn);
if(terminal_state(GRID)==10)
{
print(GRID);
printf("nYou have wonnn");
return 0;
}else if (terminal_state(GRID)==-10) {
print(GRID);
printf("nComputer has wonnn");
return 0;
}else if (terminal_state(GRID)==0) {
print(GRID);
printf("nThe game is a drawnn");
return 0;
}
computer_position(GRID,!turn);
}
}
else
{
while(available_spots(GRID)!=0)
{
computer_position(GRID,!turn);
if(terminal_state(GRID)==-10)
{
print(GRID);
printf("nYou have wonnn");
return 0;
}else if (terminal_state(GRID)==10) {
print(GRID);
printf("nComputer has wonnn");
return 0;
}else if (terminal_state(GRID)==0) {
print(GRID);
printf("nThe game is a drawnn");
return 0;
}
print(GRID);
get_input(GRID,turn);
}
}
}
beginner c tic-tac-toe ai
beginner c tic-tac-toe ai
New contributor
New contributor
edited 13 mins ago
200_success
130k16153417
130k16153417
New contributor
asked 11 hours ago
Udhay SankarUdhay Sankar
161
161
New contributor
New contributor
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
$begingroup$
Please add some space to your code - it can be hard to read when it's all crammed together.
Use ALL_CAPS
names for preprocessor macros, but not for ordinary variables or functions. It's important to be able to tell them apart (because macros don't obey the rules of scope, for instance).
The game grid is 7✕7 = 49 elements, but only 3✕3 = 9 of those elements are actually storing game state - that's only ⅕. The rest are filled with presentation constants that never need to be changed, and can be produced when printing (they don't need to be stored).
Look at this repetition:
case 1:
if (GRID[1][1]=='x'||GRID[1][1]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 2:
if (GRID[1][3]=='x'||GRID[1][3]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
Here, we're doing two things: mapping the input number to a position, and checking whether it's occupied. If we separate those computations, we'll find we don't need to repeat the tests.
Something like this:
if (input < 1 || input > 9) {
/* out of range */
return 0;
}
--input; /* now 0-8 */
int x = input % 3;
int y = input / 3;
char occupier = grid[2*y+1][2*x+1];
if (occupier != ' ') {
printf("nPosition already occupied!!!n");
return 0;
} else {
return 1;
}
Similar techniques can reduce duplication elsewhere in the program.
Enable more warning messages in your compiler. It will help you spot errors such as these:
gcc -std=c17 -fPIC -g -Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds -Wconversion 214336.c -o 214336
214336.c: In function ‘minimax’:
214336.c:287:11: warning: unused variable ‘j’ [-Wunused-variable]
int i,j;
^
214336.c:287:9: warning: unused variable ‘i’ [-Wunused-variable]
int i,j;
^
214336.c: In function ‘valid’:
214336.c:114:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
214336.c: In function ‘terminal_state’:
214336.c:272:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
214336.c: In function ‘minimax’:
214336.c:325:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
$endgroup$
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Udhay Sankar is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f214336%2fa-command-line-unbeatable-tic-tac-toe-written-in-c%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
Please add some space to your code - it can be hard to read when it's all crammed together.
Use ALL_CAPS
names for preprocessor macros, but not for ordinary variables or functions. It's important to be able to tell them apart (because macros don't obey the rules of scope, for instance).
The game grid is 7✕7 = 49 elements, but only 3✕3 = 9 of those elements are actually storing game state - that's only ⅕. The rest are filled with presentation constants that never need to be changed, and can be produced when printing (they don't need to be stored).
Look at this repetition:
case 1:
if (GRID[1][1]=='x'||GRID[1][1]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 2:
if (GRID[1][3]=='x'||GRID[1][3]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
Here, we're doing two things: mapping the input number to a position, and checking whether it's occupied. If we separate those computations, we'll find we don't need to repeat the tests.
Something like this:
if (input < 1 || input > 9) {
/* out of range */
return 0;
}
--input; /* now 0-8 */
int x = input % 3;
int y = input / 3;
char occupier = grid[2*y+1][2*x+1];
if (occupier != ' ') {
printf("nPosition already occupied!!!n");
return 0;
} else {
return 1;
}
Similar techniques can reduce duplication elsewhere in the program.
Enable more warning messages in your compiler. It will help you spot errors such as these:
gcc -std=c17 -fPIC -g -Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds -Wconversion 214336.c -o 214336
214336.c: In function ‘minimax’:
214336.c:287:11: warning: unused variable ‘j’ [-Wunused-variable]
int i,j;
^
214336.c:287:9: warning: unused variable ‘i’ [-Wunused-variable]
int i,j;
^
214336.c: In function ‘valid’:
214336.c:114:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
214336.c: In function ‘terminal_state’:
214336.c:272:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
214336.c: In function ‘minimax’:
214336.c:325:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
$endgroup$
add a comment |
$begingroup$
Please add some space to your code - it can be hard to read when it's all crammed together.
Use ALL_CAPS
names for preprocessor macros, but not for ordinary variables or functions. It's important to be able to tell them apart (because macros don't obey the rules of scope, for instance).
The game grid is 7✕7 = 49 elements, but only 3✕3 = 9 of those elements are actually storing game state - that's only ⅕. The rest are filled with presentation constants that never need to be changed, and can be produced when printing (they don't need to be stored).
Look at this repetition:
case 1:
if (GRID[1][1]=='x'||GRID[1][1]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 2:
if (GRID[1][3]=='x'||GRID[1][3]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
Here, we're doing two things: mapping the input number to a position, and checking whether it's occupied. If we separate those computations, we'll find we don't need to repeat the tests.
Something like this:
if (input < 1 || input > 9) {
/* out of range */
return 0;
}
--input; /* now 0-8 */
int x = input % 3;
int y = input / 3;
char occupier = grid[2*y+1][2*x+1];
if (occupier != ' ') {
printf("nPosition already occupied!!!n");
return 0;
} else {
return 1;
}
Similar techniques can reduce duplication elsewhere in the program.
Enable more warning messages in your compiler. It will help you spot errors such as these:
gcc -std=c17 -fPIC -g -Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds -Wconversion 214336.c -o 214336
214336.c: In function ‘minimax’:
214336.c:287:11: warning: unused variable ‘j’ [-Wunused-variable]
int i,j;
^
214336.c:287:9: warning: unused variable ‘i’ [-Wunused-variable]
int i,j;
^
214336.c: In function ‘valid’:
214336.c:114:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
214336.c: In function ‘terminal_state’:
214336.c:272:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
214336.c: In function ‘minimax’:
214336.c:325:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
$endgroup$
add a comment |
$begingroup$
Please add some space to your code - it can be hard to read when it's all crammed together.
Use ALL_CAPS
names for preprocessor macros, but not for ordinary variables or functions. It's important to be able to tell them apart (because macros don't obey the rules of scope, for instance).
The game grid is 7✕7 = 49 elements, but only 3✕3 = 9 of those elements are actually storing game state - that's only ⅕. The rest are filled with presentation constants that never need to be changed, and can be produced when printing (they don't need to be stored).
Look at this repetition:
case 1:
if (GRID[1][1]=='x'||GRID[1][1]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 2:
if (GRID[1][3]=='x'||GRID[1][3]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
Here, we're doing two things: mapping the input number to a position, and checking whether it's occupied. If we separate those computations, we'll find we don't need to repeat the tests.
Something like this:
if (input < 1 || input > 9) {
/* out of range */
return 0;
}
--input; /* now 0-8 */
int x = input % 3;
int y = input / 3;
char occupier = grid[2*y+1][2*x+1];
if (occupier != ' ') {
printf("nPosition already occupied!!!n");
return 0;
} else {
return 1;
}
Similar techniques can reduce duplication elsewhere in the program.
Enable more warning messages in your compiler. It will help you spot errors such as these:
gcc -std=c17 -fPIC -g -Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds -Wconversion 214336.c -o 214336
214336.c: In function ‘minimax’:
214336.c:287:11: warning: unused variable ‘j’ [-Wunused-variable]
int i,j;
^
214336.c:287:9: warning: unused variable ‘i’ [-Wunused-variable]
int i,j;
^
214336.c: In function ‘valid’:
214336.c:114:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
214336.c: In function ‘terminal_state’:
214336.c:272:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
214336.c: In function ‘minimax’:
214336.c:325:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
$endgroup$
Please add some space to your code - it can be hard to read when it's all crammed together.
Use ALL_CAPS
names for preprocessor macros, but not for ordinary variables or functions. It's important to be able to tell them apart (because macros don't obey the rules of scope, for instance).
The game grid is 7✕7 = 49 elements, but only 3✕3 = 9 of those elements are actually storing game state - that's only ⅕. The rest are filled with presentation constants that never need to be changed, and can be produced when printing (they don't need to be stored).
Look at this repetition:
case 1:
if (GRID[1][1]=='x'||GRID[1][1]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
case 2:
if (GRID[1][3]=='x'||GRID[1][3]=='o')
{
printf("nPosition already occupied!!!n");
return 0;
}
else
return 1;
break;
Here, we're doing two things: mapping the input number to a position, and checking whether it's occupied. If we separate those computations, we'll find we don't need to repeat the tests.
Something like this:
if (input < 1 || input > 9) {
/* out of range */
return 0;
}
--input; /* now 0-8 */
int x = input % 3;
int y = input / 3;
char occupier = grid[2*y+1][2*x+1];
if (occupier != ' ') {
printf("nPosition already occupied!!!n");
return 0;
} else {
return 1;
}
Similar techniques can reduce duplication elsewhere in the program.
Enable more warning messages in your compiler. It will help you spot errors such as these:
gcc -std=c17 -fPIC -g -Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds -Wconversion 214336.c -o 214336
214336.c: In function ‘minimax’:
214336.c:287:11: warning: unused variable ‘j’ [-Wunused-variable]
int i,j;
^
214336.c:287:9: warning: unused variable ‘i’ [-Wunused-variable]
int i,j;
^
214336.c: In function ‘valid’:
214336.c:114:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
214336.c: In function ‘terminal_state’:
214336.c:272:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
214336.c: In function ‘minimax’:
214336.c:325:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
answered 11 hours ago
Toby SpeightToby Speight
24.9k740115
24.9k740115
add a comment |
add a comment |
Udhay Sankar is a new contributor. Be nice, and check out our Code of Conduct.
Udhay Sankar is a new contributor. Be nice, and check out our Code of Conduct.
Udhay Sankar is a new contributor. Be nice, and check out our Code of Conduct.
Udhay Sankar is a new contributor. Be nice, and check out our Code of Conduct.
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f214336%2fa-command-line-unbeatable-tic-tac-toe-written-in-c%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown