Tic Tac Toe game in C++

There is also a newer article with a better implementation here, so after you read this don’t forget to check the other one to see how it differs.

After the posts related to devops work, with all the git and github and build systems stuff, it’s time for us to get a little bit into C++.

What a better way to do this than with a game (a simple one, but still, a game).

Before we start with the information on the game implementation itself, I just want to say that you can also find the video tutorial on my YouTube channel (/c/cppdev) right here.

Now that we got this out of the way, let’s get into it and check out how we can implement a Tic Tac Toe game in C++.

The software architecture

First of all, before creating a project, what we should do is think about how the project is going to look from implementation point of view.

What classes I need, what functions, what dependencies etc. Just a rough overview of what I want to create.

In my case, since this is a very simple project, we don’t need many things.

For this project, we will just have two classes and a main function to put them both together.

We are going to create a "Board" class and a "Game" class.

Board” class
– going to keep information related to the board
– the board is going to be a 3 by 3 matrix that will keep track of the current player turn’s mark and the input from the player (either X or 0 and at what positions)
– will have functions to initialize with no marks, draw to the screen (in console format), update with any new moves (e.g. X has been added) and also check if there is a winner (lines, columns or diagonals)
– we will also provide some getters for the Board for further usage

“Game” class
– going to use the “Board” as the main dependency
– will keep track of the number of moves and also start a loop (at least, until 9 moves are performed – since if 9 moves have passed and there is no winner, this is going to be a draw).
– the “Game” is going to use the “Board” more like an API, calling the functions provided by it in the actual loop just to check on the state of the game

Of course, the main.cpp will only create the “Board” and the “Game” with the previously created Board as an argument and will just “run” the “Game”.

Actual implementation

Now that we have the architecture and what we want to create all sorted out, all that is left to do for us, is to implement it.

First, for the “Board” class.

The actual “board” for our game (not the class itself) is going to be a bi-dimensional array of chars. We are also going to keep the “current” mark (basically, X or 0) as a data member.

Besides that, I want that the initializing of the board to be done with integers from 1 to 9. In this way, I can ask the player to input the number in which he wants to add it’s mark (from 1 to 9 – only the ones that are free at the moment).

Since we have the board as bi-dimensional char array, we can’t just add integers there, because when we try to print them to the screen, we will only get the ASCII equivalent of that integer. As a result of that, we will also create a char array (DIGITS) which will be fixed, that will contain the actual integers from 0 to 9 but as characters.

The Board.h will look like below

// include guards for header
#ifndef _BOARD_H_
#define _BOARD_H_
// constants that we need - the "DIGITS" that we mentioned earlier
constexpr int SIZE = 3;
constexpr char DIGITS[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
class Board
{
public:
    // default constructor
	Board() = default;
    // default destructor - virtual in case we decide to inherit from it
	virtual ~Board() = default;
    // init board
	virtual void init();
    // draw board on screen
	virtual void draw();
    // check win condition
	virtual bool check();
    // populate with mark
	virtual bool update(int position); 
    // getters for further use
	virtual char* getBoard()
	{
		return &board_[0][0];
	}
	virtual char getMark()
	{
		return mark_;
	}
private:
    // actual board representation
	char board_[SIZE][SIZE];
    // mark representation
	char mark_;
};
#endif

Now for the actual implementation – the Board.cpp

#include <iostream>
#include "Board.h"
/* Init function for the board
 * Starting mark is X, first digit on
 * the board is 1
 * Populate each position of the board
 * with digits from 1 to 9
 */
void Board::init()
{
	mark_ = 'X';
	int digit = 1;
	for (auto line = 0; line < SIZE; line++)
	{
		for (auto column = 0; column < SIZE; column++)
		{
			board_[line][column] = DIGITS[digit++];
		}
	}	
}
/* Just iterate through the board
 * and show it in a clean fashion
 * by outputting it to the screen
 */
void Board::draw()
{
	std::cout << "-   -   -   -\n";
	for (auto line = 0; line < SIZE; line++)
	{
		for (auto column = 0; column < SIZE; column++)
		{
			std::cout << "| " << board_[line][column] << " ";
		}
		std::cout << "| \n";
		std::cout << "-   -   -   -\n";
	}
}
/* Verify if there is a winner.
 * just some formula to check
 * the posibilities
 */
bool Board::check()
{
	int i = 0;
	int j = 0;
	// check lines
	for (auto i = 0; i < 3; i++)
	{
		if (board_[i][j] == board_[i][++j] && board_[i][j] == board_[i][++j])
			return true;
		j = 0;
	}
	// check columns
	for (auto j = 0; j < 3; j++)
	{
		if (board_[i][j] == board_[++i][j] && board_[i][j] == board_[++i][j])
			return true;
		i=0;
	}
	// check diags
	if (board_[i][j] == board_[++i][++j] && board_[i][j] == board_[++i][++j])
		return true;
	i = 0;
	j = SIZE - 1;
	return board_[i][j] == board_[++i][--j] && board_[i][j] == board_[++i][--j];
}
/* Update the board with the 
 * current mark, at the given position
 * Only update if there's no mark already
 */
bool Board::update(int position)
{
	bool updated = false;
	for (auto line = 0; line < SIZE; line++)
	{
		for (auto column = 0; column < SIZE; column++)
		{
			if(board_[line][column] == DIGITS[position])
			{
				board_[line][column] = mark_;
				updated = true;
			}
		}
	}
	// change mark only if updated
	if (updated)
	{
		if (mark_ == 'X')
			mark_ = 'O';
		else
	   		mark_ = 'X';
	}
	return updated;
}

Now, that’s it for the actual Board. We don’t need much, as you see. The class for the actual Game will be even simpler.

For the “Game” class

The Game class only needs to keep the Board as a data member and will only have a “single” functionality : “run” the game. That’s all.

The Game.h implementation

// include guards for the header
#ifndef _GAME_H_
#define _GAME_H_
#include "Board.h"
class Game
{
public:
    // constructor which has a board ptr as a parameter
	Game(Board* board);
    // default destructor
	~Game() = default;
    // will start the loop for the game
	void run();
private:
    // ptr to a board object (that will be provided on the constructor)
	Board* board_;
};
#endif

And for the Game.cpp implementation

#include <iostream>
#include "Game.h"
/* Initialize the board_ */
Game::Game(Board* board):
	board_(board)
{}
/* Run the game (start the loop)
 * Use the Board as an API whenever you need
 */
void Game::run()
{
    // initialize board
	board_->init();
    // keep track of the number of moves
	int moves = 0;
	while(moves < 9)
	{
        // show a nice title then draw the board
		std::cout << "\n TicTacToe ! \n";
		board_->draw();
        // ask the player for input and store it (position)
		std::cout << "\n Player " << (moves % 2 ? "2" : "1") << "\'s turn:\n";
		int position = 0;
		std::cin >> position;
        // if input is invalid position - ask again for input
		while (position > 9 || position < 1)
		{
			std::cout << "\nInvalid input. Please use numbers between 1 and 9!\n";
			std::cin >> position;
		};
        // while the position is already occupied - ask again for input
		while (!board_->update(position))
		{
			// probably there is already X or O at the given position
			std::cout << "\nInvalid Input. Try again with a valid position!\n";
			std::cin >> position;
		}
		// check if somebody won only if more than 3 moves done already
        // it's impossible to win and that will save us some CPU time
		if (moves > 3)
		{
            // check if there is a winner or if there is a draw
			if (board_->check())
			{
				board_->draw();
				std::cout << "\nPlayer " << (moves % 2 ? "2" : "1") << " won!\n";
				break;
			} else if(moves == 8)
			{
				std::cout << "\nIt's a draw!\n";
			}
		}
        // if there's no winner and it's not a draw
        // that means there are moves left
        // just increment and continue the loop
		moves++;
	};
}

The only thing that remains is to just create the main.cpp file in which we are going to just create the board instance, then the game instance which will use that board.

// include everything we need
#include <iostream>
#include "Board.h"
#include "Game.h"

int main()
{
    // create a pointer to a new board
	Board* board = new Board();
    // create the game and provide the board
	Game game(board);
    // just run the actual game instance
	game.run();

    // free up the resources for the board
	delete board;
	return 0;
}

End of the story

It is as simple as that. You know have a fully functional “Tic Tac Toe” game.

Now, I know that some of you are not going to be happy with the implementation but I just want to say that this is just a beginner’s tutorial and I know there are many things that can be improved.

I will let you all, improve this idea and come with a better and/or improved solution.

Until then, I hope you at least got a little bit of new information and that it will help you all pursue your programming aspirations.

All the best,
cppdev

6 thoughts on “Tic Tac Toe game in C++”

  1. Pingback: Test Cases using GTest (Unit Testing) – The CPPDEV

  2. Hello there, there is a bug in the Board class where you check the rows/columns/diagonals. Use explicit index positions i.e. board_[i][j] == board_[i+1][j-1] instead of board_[i][j] == board_[++i][–j].

    1. Had some time to check this out.
      It is not a bug, it works as expected.
      Let’s take an example: if (board_[i][j] == board_[i][++j] && board_[i][j] == board_[i][++j])
      This will roughly translate to: “if (board_[0][0] == board_[0][1] && board_[0][1] == board_[0][2])”, which means that all 3 values from row 0 should be equal.

  3. Pingback: Simple Tic Tac Toe game in C++ – The CPPDEV

  4. Pingback: Simple Tic Tac Toe game in C++ - cppdev

Leave a Reply

%d bloggers like this: