Hello, so im writing a tic tac toe game with AI. There is no possible human win . Everything works fine ( it should work fine) , but i want to ask you what could i improve in this game? Maybe make code shorter or somehow improve it. Tell me what you think
Code:
#include <iostream>#include <cstdlib>
#include <ctime>
using namespace std;
void initBoard();
void printBoard(bool firstTime);
bool placeChar(int place, char playerChar);
int computerMove();
int checkWin(char playerChar);
char board[3][3];
int main()
{
int tie = 0; // every time a 'X' or 'O' is placed , tie increases so if it is 9 and there is no win
// it says that game is draw.
int turn;
char playerChar;
char playAgain;
int whosMove=1;
bool endGame = false;
int humanWins=0;
int computerWins=0;
initBoard();
printBoard(true);
while( endGame == false )
{
if(whosMove == 1)
{
playerChar = 'X';
cout << "Enter your move: " << endl;
cin >> turn;
whosMove = 0;
if( placeChar(turn, playerChar) == false ) // if it failed to put a 'X' to board, human's move still
//remains the same
whosMove = 1;
else
tie++;
// checks for win
if( checkWin(playerChar) == 1 )
{
cout << "You won by horizontal" << endl;
endGame = true;
humanWins++;
}
else if( checkWin(playerChar) == 2 )
{
cout << "You won by vertical" << endl;
endGame = true;
humanWins++;
}
else if( checkWin(playerChar) == 3 )
{
cout << "You won by diagonal from left to right" << endl;
endGame = true;
humanWins++;
}
else if( checkWin(playerChar) == 4 )
{
cout << "You won by diagonal from right to left" << endl;
endGame = true;
humanWins++;
}
}
else
{
int cTurn;
cTurn = computerMove();
playerChar = 'O';
whosMove = 1;
if( placeChar(cTurn, playerChar) == false )
whosMove = 0;
else
tie++;
// checks for win
if( checkWin(playerChar) == 1 )
{
cout << "Computer won by horizontal" << endl;
endGame = true;
computerWins++;
}
else if( checkWin(playerChar) == 2 )
{
cout << "Computer won by vertical" << endl;
endGame = true;
computerWins++;
}
else if( checkWin(playerChar) == 3 )
{
cout << "Computer won by diagonal from left to right" << endl;
endGame = true;
computerWins++;
}
else if( checkWin(playerChar) == 4 )
{
cout << "Computer won by diagonal from right to left" << endl;
endGame = true;
computerWins++;
}
}
if( endGame == false)
system("cls");
printBoard(false);
cout << endl;
if( tie == 9 )
{
cout << "Draw game." << endl;
}
if( endGame == true || tie == 9 ) // asks if you want to play again
{
cout << "Do you want to play again? y/n: " ;
cin >> playAgain;
if( playAgain == 'y' )
{
endGame = false;
tie = 0;
initBoard();
printBoard(false);
}
else
{
endGame = true;
system("cls");
cout << "Computer wins: " << computerWins << endl;
cout << "Your wins: " << humanWins << endl;
}
}
}
}
void initBoard() // function to initialize board
{
for(int i=0; i<3; i++)
{
for(int j=0; j<3; j++)
{
board[i][j] = ' ';
}
}
}
void printBoard(bool firstTime) // prints the board
{
if( firstTime == true ) // Just for visual to get know what numbers represent
{
board[0][0] = '1';
board[0][1] = '2';
board[0][2] = '3';
board[1][0] = '4';
board[1][1] = '5';
board[1][2] = '6';
board[2][0] = '7';
board[2][1] = '8';
board[2][2] = '9';
for(int i=0; i<3; i++)
{
for(int j=0; j<3; j++)
cout << board[i][j] << " | ";
cout << endl;
cout << "- - - - - -" << endl;
}
initBoard();
}
else
{
for(int i=0; i<3; i++)
{
for(int j=0; j<3; j++)
cout << board[i][j] << " | ";
cout << endl;
cout << "- - - - - -" << endl;
}
}
}
bool placeChar(int place, char playerChar) // function to place char to board
{
// it is boolean because if there is already taken place in board it returs false, so in main function
// you can determine whose move it is: computer or human.
if( place < 4 )
{
for(int i=0; i<4; i++)
{
if( i == place )
{
if( board[0][i-1] == ' ' )
{
board[0][i-1] = playerChar;
return true;
}
else
return false;
}
}
}
else if( place < 7 && place > 3 )
{
for(int i=4; i<8; i++)
{
if( i == place)
{
if( board[1][i-4] == ' ')
{
board[1][i-4] = playerChar;
return true;
}
else
return false;
}
}
}
else if( place < 10 && place > 6)
{
for(int i=7; i<11; i++)
{
if( i == place)
{
if( board[2][i-7] == ' ')
{
board[2][i-7] = playerChar;
return true;
}
else
return false;
}
}
}
}
int computerMove() // function to get computer move
{
//how can i improve this one to reduce number of integers?
int horizontal=0;
int horizontal1=0;
int vertical=0;
int vertical1=0;
int diagonal=0;
int diagonal1=0;
int diagonal2=0;
int diagonal3=0;
int horizontalA=0;
int horizontal1A=0;
int verticalA=0;
int vertical1A=0;
int diagonalA=0;
int diagonal1A=0;
int diagonal2A=0;
int diagonal3A=0;
bool attack = false; // if attack is possible, then attack becomes true so defence move wont work
// because if it does sometimes computer will lose game
int j=2;
int compMove=0;
srand(time(NULL));
if( board[1][1] == ' ' )
{
compMove = 5;
}
// every for loop checks if there is horizontal, vertical or diagonal possible human win and if it is,
// these algorithms blocks it. If there is possible win move, it takes priority by changing boolean
// value "attack" to true.
// checks for horizontal from left to right
for(int i=0; i<3; i++)
{
for(int j=0; j<2; j++)
{
if( board[i][j] == 'O' && board[i][2] == ' ' )
{
horizontalA++;
if( horizontalA == 2 )
{
if( i == 0 )
compMove = 3;
else if( i == 1 )
compMove = 6;
else if( i == 2 )
compMove = 9;
cout << "COMPUTER ATTACK HORIZONTAL FROM LEFT TO RIGHT, SQUARE: " << compMove << endl;
attack = true;
break;
}
}
else if( board[i][j] == 'X' && board[i][2] == ' ' && attack == false )
{
horizontal++;
if( horizontal == 2 )
{
if( i == 0 )
compMove = 3;
else if( i == 1 )
compMove = 6;
else if( i == 2 )
compMove = 9;
cout << "COMPUTER DEF HORIZONTAL FROM LEFT TO RIGHT, SQUARE: " << compMove << endl;
break;
}
}
}
horizontal = 0;
horizontalA = 0;
if( compMove != 0 )
break;
}
// checks for horizontal from right to left
for(int i=0; i<3; i++)
{
for(int j=2; j>0; j--)
{
if( board[i][j] == 'O' && board[i][0] == ' ' )
{
horizontal1A++;
if( horizontal1A == 2 )
{
if( i == 0 )
compMove = 1;
else if( i == 1 )
compMove = 4;
else if( i == 2 )
compMove = 7;
cout << "COMPUTER ATTACK HORIZONTAL FROM RIGHT TO LEFT, SQUARE: " << compMove << endl;
attack = true;
break;
}
}
else if( board[i][j] == 'X' && board[i][0] == ' ' && attack == false )
{
horizontal1++;
if( horizontal1 == 2 )
{
if( i == 0 )
compMove = 1;
else if( i == 1 )
compMove = 4;
else if( i == 2 )
compMove = 7;
cout << "COMPUTER DEF HORIZONTAL FROM RIGHT TO LEFT, SQUARE: " << compMove << endl;
//break;
}
}
}
horizontal1 = 0;
horizontal1A = 0;
if( compMove != 0)
break;
}
// checks for vertical from top to bottom
for(int i=0; i<3; i++)
{
for(int j=0; j<2; j++)
{
if( board[j][i] == 'O' && board[2][i] == ' ' )
{
verticalA++;
if( verticalA == 2 )
{
if( i == 0 )
compMove = 7;
else if( i == 1 )
compMove = 8;
else if( i == 2 )
compMove = 9;
cout << "COMPUTER ATTACK VERTICAL FROM TOP TO BOTTOM, SQUARE: " << compMove << endl;
attack = true;
break;
}
}
else if( board[j][i] == 'X' && board[2][i] == ' ' && attack == false )
{
vertical++;
if( vertical == 2 )
{
if( i == 0 )
compMove = 7;
else if( i == 1 )
compMove = 8;
else if( i == 2 )
compMove = 9;
cout << "COMPUTER DEF VERTICAL FROM TOP TO BOTTOM, SQUARE: " << compMove << endl;
break;
}
}
}
vertical = 0;
verticalA = 0;
if( compMove != 0 )
break;
}
// checks for vertical from bottom to top
for(int i=0; i<3; i++)
{
for(int j=2; j>0; j--)
{
if( board[j][i] == 'O' && board[0][i] == ' ' )
{
vertical1A++;
if( vertical1A == 2 )
{
if( i == 0 )
compMove = 1;
else if( i == 1 )
compMove = 2;
else if( i == 2 )
compMove = 3;
cout << "COMPUTER ATTACK VERTICAL1 FROM BOTTOM TO TOP, SQUARE: " << compMove << endl;
attack = true;
break;
}
}
else if( board[j][i] == 'X' && board[0][i] == ' ' && attack == false )
{
vertical1++;
if( vertical1 == 2 )
{
if( i == 0 )
compMove = 1;
else if( i == 1 )
compMove = 2;
else if( i == 2 )
compMove = 3;
cout << "COMPUTER DEF VERTICAL FROM BOTTOM TO TOP, SQUARE: " << compMove << endl;
break;
}
}
}
vertical1 = 0;
vertical1A = 0;
if( compMove != 0 )
break;
}
// checks for diagonal from top-left to bottom-right
for(int i=0; i<2; i++)
{
if( board[i][i] == 'O' && board[2][2] == ' ' )
{
diagonalA++;
if( diagonalA == 2 )
{
compMove = 9;
cout << "COMPUTER DIAGONAL ATTACK FROM TOP-LEFT TO BOTTOM-RIGHT, SQUARE: " << compMove << endl;
attack = true;
}
}
else if( board[i][i] == 'X' && board[2][2] == ' ' && attack == false )
{
diagonal++;
if( diagonal == 2 )
{
compMove = 9;
cout << "COMPUTER DIAGONAL DEF FROM TOP-LEFT TO BOTTOM-RIGHT, SQUARE: " << compMove << endl;
}
}
}
// checks for diagonal from bottom-right to top-left
for(int i=2; i>0; i--)
{
if( board[i][i] == 'O' && board[0][0] == ' ' )
{
diagonal1A++;
if( diagonal1A == 2 )
{
compMove = 1;
cout << "COMPUTER ATTACK DIAGONAL FROM BOTTOM-RIGHT TO TOP-LEFT, SQUARE: " << compMove << endl;
attack = true;
}
}
else if( board[i][i] == 'X' && board[0][0] == ' ' && attack == false )
{
diagonal1++;
if( diagonal1 == 2 )
{
compMove = 1;
cout << "COMPUTER DEF DIAGONAL FROM BOTTOM-RIGHT TO TOP-LEFT, SQUARE: " << compMove << endl;
}
}
}
// checks for diagonal from top-right to bottom-left
for(int i=0; i<2; i++)
{
if( board[i][j] == 'O' && board[2][0] == ' ' )
{
diagonal2A++;
if( diagonal2A == 2 )
{
compMove = 7;
cout << "COMPUTER ATTACK DIAGONAL FROM TOP-RIGHT TO BOTTOM-LEFT, SQUARE: " << compMove << endl;
attack = true;
}
}
else if( board[i][j] == 'X' && board[2][0] == ' ' && attack == false )
{
diagonal2++;
if( diagonal2 == 2 )
{
compMove = 7;
cout << "COMPUTER DEF DIAGONAL FROM TOP-RIGHT TO BOTTOM-LEFT, SQUARE: " << compMove << endl;
}
}
j--;
}
j = 0; // resets j value so it can be used again
// checks for diagonal from bottom-left to top-right
for(int i=2; i>0; i--)
{
if( board[i][j] == 'O' && board[0][2] == ' ' )
{
diagonal3A++;
if( diagonal3A == 2 )
{
compMove = 3;
cout << "COMPUTER ATTACK DIAGONAL FROM BOTTOM-LEFT TO TOP-RIGHT, SQUARE: " << compMove << endl;
attack = true;
}
}
else if( board[i][j] == 'X' && board[0][2] == ' ' && attack == false )
{
diagonal3++;
if( diagonal3 == 2 )
{
compMove = 3;
cout << "COMPUTER DEF DIAGONAL FROM BOTTOM-LEFT TO TOP-RIGHT, SQUARE: " << compMove << endl;
}
}
j++;
}
// checks if horizontal middle square should be placed by computer
for(int i=0; i<3; i++)
{
if( board[i][0] != ' ' && board[i][2] != ' ' )
{
if( board[i][0] == 'O' && board[i][2] == 'O' && board[i][1] == ' ' )
{
if( i == 0 )
compMove = 2;
else if( i == 1 )
compMove = 5;
else if( i == 2 )
compMove = 8;
cout << "COMPUTER HORIZONTAL MIDDLE ATTACK CHECK, SQUARE: " << compMove << endl;
attack = true;
}
else if( board[i][0] == 'X' && board[i][2] == 'X' && board[i][1] == ' ' && attack == false )
{
if( i == 0 )
compMove = 2;
else if( i == 1 )
compMove = 5;
else if( i == 2 )
compMove = 8;
cout << "COMPUTER HORIZONTAL MIDDLE DEF CHECK, SQUARE: " << compMove << endl;
}
}
}
// checks if vertical middle square should be placed by computer
for(int i=0; i<3; i++)
{
if( board[0][i] != ' ' && board[2][i] != ' ' )
{
if( board[0][i] == 'O' && board[2][i] == 'O' && board[1][i] == ' ' )
{
if( i == 0 )
compMove = 4;
else if( i == 1 )
compMove = 5;
else if( i == 2 )
compMove = 6;
cout << "COMPUTER MIDDLE ATTACK CHECK, SQUARE: " << compMove << endl;
attack = true;
}
else if( board[0][i] == 'X' && board[2][i] == 'X' && board[1][i] == ' ' && attack == false )
{
if( i == 0 )
compMove = 4;
else if( i == 1 )
compMove = 5;
else if( i == 2 )
compMove = 6;
cout << "COMPUTER MIDDLE DEF CHECK, SQUARE: " << compMove << endl;
}
}
}
// Places O's in corners if its empty and human has no possible win or there is no possible computer win
// No possible win for human and computer determines int "compMove". If it is 0, it means that none of above
// algorithms was used.
if( board[1][1] == 'X' || board[1][1] == 'O' )
{
if( board[0][0] == ' ' && compMove == 0 )
{
compMove = 1;
cout << "Top left is free." << endl;
}
else if( board[0][2] == ' ' && compMove == 0 )
{
compMove = 3;
cout << "Top right is free." << endl;
}
}
if( compMove != 0 )
return compMove;
else // this should be improved, because sometimes it takes so long to generate proper number, for example
// when there is only 1 emply place left and there is no possible human and computer wins
return rand() % (10 - 1) + 1;
}
int checkWin(char playerChar) // function to check for a win
{
int horizontal=0;
int vertical=0;
int diagonal1=0;
int diagonal2=0;
int j=2;
for(int i=0; i<3; i++)
{
for(int j=0; j<3; j++)
{
if( board[i][j] == playerChar )
{
horizontal++;
if( horizontal == 3 )
{
return 1;
}
}
}
horizontal = 0;
}
for(int i=0; i<3; i++)
{
for(int j=0; j<3; j++)
{
if( board[j][i] == playerChar )
{
vertical++;
if( vertical == 3 )
{
return 2;
}
}
}
vertical = 0;
}
for(int i=0; i<3; i++)
{
if( board[i][i] == playerChar )
{
diagonal1++;
if( diagonal1 == 3 )
{
return 3;
}
}
}
for(int i=0; i<3; i++)
{
if( board[i][j] == playerChar )
{
diagonal2++;
if( diagonal2 == 3 )
{
return 4;
}
}
j--;
}
}