# Coding Exercise: Writing a CPU Random TicTacToe Game

## TicTacToe - Coding Exercise for Beginners

Who doesn't love a litle tictactoe on the back of their notebooks during class/lectures. Using this inspiration, Last year I tried to write my own tictactoe console version when I was preparing for my interviews. In this, It'll be You versus the CPU, catch is, CPU is only random, not any AI (It's a beginners tutorial, AI one will come later)

## Steps to write a simple TicTacToe Game

We'll be using C++ but a Java version is also Available at the end of the post.

• Make a Game Board
• Write a Function to place a piece
• Make it a reusable function by adding pos and user name
• Add a gameOver=false and winner flag
• add winning conditions of rows, columns, diagonals
• add all winning conditions to a single list
• Loop through that list and check for winners using containAll()
• keep a list of empty blocks as availPos
• write a function for cpu to use only availPos so as no overwriting happens
• Put all the functions together

## Let's Start

``````#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

bool gameOver = false;
string WinnerName = "";
vector<vector<string>> gameBoard;

vector<int> playerPos;
vector<int> cpuPos;
vector<int> availPos;
``````

### Total Functions needed

``````void printGameBoard();
void placePeice(int, string);
void init();
int indexOf(vector<int>&, int);
void wrongTurn();
void playerTurn();
void cpuTurn();
void checkWinner(vector<int>&, string);
``````

### Make a Game Board

Everyone likes to play TicTacToe on a gameboard, consisting of a grid with 9 playable places.

Let's make that

``````/*
Shoud Look Like this when print
| |
-+-+-
| |
-+-+-
| |
*/
void init()
{
for(auto i = 1; i<10; i++)
{
availPos.push_back(i);
}
vector<string> row = {" ", "|", " ", "|", " "};
vector<string> sep = {"-", "+", "-", "+", "-"};
gameBoard.push_back(row);
gameBoard.push_back(sep);
gameBoard.push_back(row);
gameBoard.push_back(sep);
gameBoard.push_back(row);
}
void printGameBoard()
{
for(auto i=0; i<5; i++)
{
for(auto j=0; j<5; j++)
{
cout<<gameBoard[i][j];
}
cout<<endl;
}
}
``````

### Write a Function to place a piece

Place a piece on the board : Put X or O in the grid

``````void _place(int i, int j, char symbol)
{
if(gameBoard[i][j] != "X" && gameBoard[i][j] != "O")
{
gameBoard[i][j] = symbol;
return;
}
wrongTurn();
}
``````

### Make it a reusable function by adding pos and user name

Map the 1-9 range input to appropriate i and j values in the grid so no irregularities are there.

``````void placePeice(int pos, string user)
{
char symbol = ' ';
if(user == "Player" && pos>=1 && pos<=9)
{
cout<<"Player: "<<pos<<endl;
playerPos.push_back(pos);
symbol = 'X';
} else if(user == "CPU" && pos>=1 && pos<=9)
{
cout<<"CPU: "<<pos<<endl;
cpuPos.push_back(pos);
symbol = 'O';
}
int index = indexOf(availPos, pos);
if(index != -1)
{
availPos.erase(availPos.begin() + index);
}

switch(pos)
{
case 1:
_place(0, 0, symbol);
break;
case 2:
_place(0, 2, symbol);
break;
case 3:
_place(0, 4, symbol);
break;
case 4:
_place(2, 0, symbol);
break;
case 5:
_place(2, 2, symbol);
break;
case 6:
_place(2, 4, symbol);
break;
case 7:
_place(4, 0, symbol);
break;
case 8:
_place(4, 2, symbol);
break;
case 9:
_place(4, 4, symbol);
break;
default:
break;
}
}
``````

### Handling Wrong Turns

In case someone enters a no. outside the range or enters a grid block which is already taken.

``````void wrongTurn()
{
playerTurn();
}
``````

### Trigger User/Player Turns

``````void playerTurn()
{
cout<<"Please Enter a Position [1-9]: ";
int pos;
cin>>pos;
placePeice(pos, "Player");
}
``````

### Trigger CPU Turns - Random but from available/Valid places

``````void cpuTurn()
{
int r = 1 + (rand() % availPos.size());
int pos = availPos[r];
placePeice(pos, "CPU");
}
``````

### Check for Winner and Halt the Game

We're checking the rows, columns and diagonals on each turn. Using hardcoded place values.

``````void checkWinner(vector<int>& v, string user)
{
if(gameOver)
return;
vector<int> topRow = {1,2,3};
vector<int> midRow = {4,5,6};
vector<int> botRow = {7,8,9};

vector<int> leftCol = {1,4,7};
vector<int> midCol =  {2,5,8};
vector<int> rightCol= {3,6,9};

vector<int> cross1 = {1,5,9};
vector<int> cross2 = {3,5,7};

vector<vector<int>> winning;
winning.push_back(topRow);
winning.push_back(midRow);
winning.push_back(botRow);
winning.push_back(leftCol);
winning.push_back(midCol);
winning.push_back(rightCol);
winning.push_back(cross1);
winning.push_back(cross2);

for(auto i = 0; i < winning.size(); i++)
{
int c = 0;
vector<int> con = winning[i];
for(auto j = 0; j < con.size(); j++)
{
if(std::count(v.begin(), v.end(), con[j]))
{
c = 1;
} else {
c = 0;
break;
}
}
if(c==1)
{
gameOver = true;
WinnerName = user;
return;
}
}
if(playerPos.size() + cpuPos.size() == 9)
{
gameOver = true;
WinnerName = "Draw";
return;
}
}
``````

### Finally, the main() method to drive everything and indexOf() helper function to get index from Iterator value(STL)

``````int main() {
init();
cout<<"Welcome to TicTacToe in C++"<<endl;
printGameBoard();

while(!gameOver)
{
playerTurn();
checkWinner(playerPos, "Player");
cpuTurn();
checkWinner(cpuPos, "CPU");
printGameBoard();
}
cout<<"Game Over!"<<endl;
cout<<"Winner: "<<WinnerName<<endl;
}
int indexOf(vector<int>& pos, int el)
{
auto it = find(pos.begin(), pos.end(), el);
if(it!=pos.end())
{
int index = distance(pos.begin(), it);
return index;
}
return -1;
}
``````

## Main.cpp

``````#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

bool gameOver = false;
string WinnerName = "";
vector<vector<string>> gameBoard;

vector<int> playerPos;
vector<int> cpuPos;
vector<int> availPos;

void printGameBoard();
void placePeice(int, string);
void init();
int indexOf(vector<int>&, int);
void wrongTurn();
void playerTurn();
void cpuTurn();
void checkWinner(vector<int>&, string);

int main() {
init();
cout<<"Welcome to TicTacToe in C++"<<endl;
printGameBoard();

while(!gameOver)
{
playerTurn();
checkWinner(playerPos, "Player");
cpuTurn();
checkWinner(cpuPos, "CPU");
printGameBoard();
}
cout<<"Game Over!"<<endl;
cout<<"Winner: "<<WinnerName<<endl;
}
void init()
{
for(auto i = 1; i<10; i++)
{
availPos.push_back(i);
}
vector<string> row = {" ", "|", " ", "|", " "};
vector<string> sep = {"-", "+", "-", "+", "-"};
gameBoard.push_back(row);
gameBoard.push_back(sep);
gameBoard.push_back(row);
gameBoard.push_back(sep);
gameBoard.push_back(row);
}
int indexOf(vector<int>& pos, int el)
{
auto it = find(pos.begin(), pos.end(), el);
if(it!=pos.end())
{
int index = distance(pos.begin(), it);
return index;
}
return -1;
}
void printGameBoard()
{
for(auto i=0; i<5; i++)
{
for(auto j=0; j<5; j++)
{
cout<<gameBoard[i][j];
}
cout<<endl;
}
}

void _place(int i, int j, char symbol)
{
if(gameBoard[i][j] != "X" && gameBoard[i][j] != "O")
{
gameBoard[i][j] = symbol;
return;
}
wrongTurn();
}

void placePeice(int pos, string user)
{
char symbol = ' ';
if(user == "Player" && pos>=1 && pos<=9)
{
cout<<"Player: "<<pos<<endl;
playerPos.push_back(pos);
symbol = 'X';
} else if(user == "CPU" && pos>=1 && pos<=9)
{
cout<<"CPU: "<<pos<<endl;
cpuPos.push_back(pos);
symbol = 'O';
}
int index = indexOf(availPos, pos);
if(index != -1)
{
availPos.erase(availPos.begin() + index);
}

switch(pos)
{
case 1:
_place(0, 0, symbol);
break;
case 2:
_place(0, 2, symbol);
break;
case 3:
_place(0, 4, symbol);
break;
case 4:
_place(2, 0, symbol);
break;
case 5:
_place(2, 2, symbol);
break;
case 6:
_place(2, 4, symbol);
break;
case 7:
_place(4, 0, symbol);
break;
case 8:
_place(4, 2, symbol);
break;
case 9:
_place(4, 4, symbol);
break;
default:
break;
}
}

void wrongTurn()
{
playerTurn();
}

void playerTurn()
{
cout<<"Please Enter a Position [1-9]: ";
int pos;
cin>>pos;
placePeice(pos, "Player");
}

void cpuTurn()
{
int r = 1 + (rand() % availPos.size());
int pos = availPos[r];
placePeice(pos, "CPU");
}

void checkWinner(vector<int>& v, string user)
{
if(gameOver)
return;
vector<int> topRow = {1,2,3};
vector<int> midRow = {4,5,6};
vector<int> botRow = {7,8,9};

vector<int> leftCol = {1,4,7};
vector<int> midCol =  {2,5,8};
vector<int> rightCol= {3,6,9};

vector<int> cross1 = {1,5,9};
vector<int> cross2 = {3,5,7};

vector<vector<int>> winning;
winning.push_back(topRow);
winning.push_back(midRow);
winning.push_back(botRow);
winning.push_back(leftCol);
winning.push_back(midCol);
winning.push_back(rightCol);
winning.push_back(cross1);
winning.push_back(cross2);

for(auto i = 0; i < winning.size(); i++)
{
int c = 0;
vector<int> con = winning[i];
for(auto j = 0; j < con.size(); j++)
{
if(std::count(v.begin(), v.end(), con[j]))
{
c = 1;
} else {
c = 0;
break;
}
}
if(c==1)
{
gameOver = true;
WinnerName = user;
return;
}
}
if(playerPos.size() + cpuPos.size() == 9)
{
gameOver = true;
WinnerName = "Draw";
return;
}
}
``````

## How to Compile?

Use any STL Compatiable C++ compiler. I prefer gcc/g++ 10+

``````g++ main.cpp -o TicTacToe
``````

## Run

This is for Unix environments(Linux, AWS, MacOS), just run the exe for windows in CMD/Powershell.

``````./TicTacToe
``````

## References:  