C++

Creating a Tic-Tac-Toe Game in C++

Tic-tac-toe is an interesting, old, and classic game that has entertained the generations. In tic-tac-toe, two players compete on a 9-square grid that is marked with a hash pattern. Each player takes their turn and places the symbol (O or X) in one of the empty squares. In this article, we’ll explore how to create a tic-tac-toe game in the C++ programming language. The following example will guide you through building a simple yet engaging tic-tac-toe game, covering the essential concepts, code breakdowns, and considerations for creating an interactive gaming experience.

Create a Tic-Tac-Toe Game in C++

The following example provides the basics of making this interactive two-player tic-tac-toe game. It showcases a simple and easy approach to programming it with C++ and provides a well-documented source code to relive those childhood challenges with friends in a new, digital format. Let us see the following code.

Example: Basic Console-Based Tic-Tac-Toe without Using the 2D Array

In this example, we will use a 2D array, functions, and if-else conditions to make the tic-tac-toe game in C++. In this game, two players are allowed to take turns in inputting their moves, and it determines the game state by checking for a winner or a tie. See the following given code:

#include <iostream>

using namespace std;

void drawBoard(char board[3][3]);

bool isMoveValid(char board[3][3], int row, int col);

bool isBoardFull(char board[3][3]);

char checkWinner(char board[3][3]);

int main() {

  char board[3][3] = {{' ', ' ', ' '}, {' ', ' ', ' '}, {' ', ' ', ' '}};

  int row, col;

  char currentPlayer = 'X';

  while (true) {

  drawBoard(board);

  cout << "Player " << currentPlayer << "'s turn. Enter row (1-3) and column (1-3): ";

  cin >> row >> col;

  row--;

  col--;

  if (isMoveValid(board, row, col)) {

    board[row][col] = currentPlayer;

    char winner = checkWinner(board);

    if (winner != ' ') {

        drawBoard(board);

        cout << "Player " << winner << " is a winnner!\n";

        break;

    }

    if (isBoardFull(board)) {

        drawBoard(board);

        cout << "It's a tie!\n";

        break;

    }

    currentPlayer = (currentPlayer == 'X') ? 'O' : 'X';

    } else {

    cout << "Invalid move. Choose other cell.\n";

    } }

  return 0;

}

void drawBoard(char board[3][3]) {

cout << "b|\t1\t|\t2\t|\t3\t|\n";

cout << " ______________________\n";

for (int m = 0; m < 3; m++) {

  cout << m + 1 << "| ";

  for (int t = 0; t < 3; t++) {

     cout <<""<< board[m][t];

     if (t < 2) cout << " \t|\t";

  }

  cout << "\t|\n";

  if (m < 2) cout << " ______________________\n";

}

  cout << "\n"; }

  bool isMoveValid(char board[3][3], int row, int col) {

  return (row >= 0 && row < 3 && col >= 0 && col < 3 && board[row][col] == ' ');

}

bool isBoardFull(char board[3][3]) {

  for (int m = 0; m < 3; m++) {

    for (int t = 0; t < 3; t++) {

      if (board[m][t] == ' ') {

         return false;

      } } }

  return true; }

char checkWinner(char board[3][3]) {

  for (int m = 0; m < 3; m++) {

  if (board[m][0] == board[m][1] && board[m][1] == board[m][2] && board[m][0] != ' ') {

     return board[m][0];

  }

  if (board[0][m] == board[1][m] && board[1][m] == board[2][m] && board[0][m] != ' ') {

    return board[0][m];

  } }

  if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ') {

    return board[0][0];

  }

  if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ') {

    return board[0][2];

  }

  return ' ';

}

Here’s a breakdown of its functionality:

The “#include<iostream>” is a preprocessor directive that includes the I/O stream library for input/output operations. Using the “namespace std” allows the direct use of cout, cin, etc. functions in a C++ program, without requiring the “std:: prefix”.

There are four function prototypes in this program – they are drawBoard(), isMoveValid(), isBoardFull(), and checkWinner(). The function declaration is known as a function prototype. Although it comes after the main function in the program, it will be used. The main function contains the game loop and logic to manage the players’ turns and moves. Within the main function, the game board is initialized with spaces.

char board[3][3] = {{' ', ' ', ' '}, {' ', ' ', ' '}, {' ', ' ', ' '}};

After this, two row and col variables are defined to store the player’s move input. The “char currentPlayer = ‘X’;” defines that the “X” player goes first.

Now, the while (true) game loop starts, and it runs until there’s a winner or a tie. This “while” loop calls the “drawBoard();” to display the board. After displaying the board on the console, the user is asked to choose a cell to mark in the following code statement:

cout << "Player " << currentPlayer << "'s turn. Enter row and column (1-3): ";

The player inputs their move in “cin >> row >> col;”.

Upon selecting a cell for marking, the program will first verify the validity of the input, ensuring that the cell is not already filled by calling the isMoveValid() function.

board[row][col] = currentPlayer;

This statement places the player’s mark on the board.

char winner = checkWinner(board);

if (winner != ' ') {

drawBoard(board);

cout << "Player " << winner << " wins!\n";

These statements check for a winner every time a player marks an entry on the board. The winner’s name will be announced if there’s a winner, and the program will exit the game loop.

if (isBoardFull(board)) {

This statement checks for a tie. The tie condition occurs in a case when the board is full and there is no winner. In this case, “It’s a tie!” is printed on the screen.

currentPlayer = (currentPlayer == 'X') ? 'O' : 'X';

This statement switches the players to give every player a chance to play their turn.

cout << "Invalid move. Choose other cell.\n";

If the move isn’t valid, the user is prompted to input again and choose any other cell.

After the “main” function, the function definitions for the function prototypes that are previously declared will start. The first function that is defined here is drawBoard() which is used to draw the tic-tac-toe board to the console. The drawBoard() function prints out the current state of the board, including grid lines.

The next function that is defined here is isMoveValid(). This function is used to determine whether a move is allowed both inside the board and on an empty cell. The isBoardFull() function is used to check whether the board is yet full. This is a condition for a tie situation when there is no winner. The isBoardFull() checks if all positions on the board are filled which indicates a tie if there’s no winner. If there is a winner, it can be ascertained using the checkWinner() function. The checkWinner() checks all potential winning lines for the same player’s mark (“X” or “O”) and returns the winning player’s mark if found or a space character “ “ if there’s no winner yet. The following is the program’s output. It shows every turn from each player.

First, the board is clear; player “X” is prompted to choose the cell to be marked. Here, player “X” enters 2 and 2. The cells of row 2 and column 2 are marked. Refer to the marked board in the following:

Now, it is the player O’s turn. The player is prompted to choose a cell to be marked. Player “O” chooses 1 for the row and 1 for the column. The chosen cell is marked for player “O” as shown in the following output snippet:

All turns for each player will follow the same pattern. It’s the player X’s turn, and the player chooses 1 for the row and 2 for the column. Refer to the following given output snapshots:

Now, the turn is for player “O”. The player chooses 1 for the row and 3 for the column.

The next turn is again on player “X”. The player chooses 3 for the row and 1 for the column.

Player “O” chooses 3 for the row and 2 for the column.

Player “X” selects the second row and the third column.

Player “O” now selects the second row and the first column.

Player “X” chooses the third row and the third column this time.

No player could make any line horizontally, vertically, or diagonally, so it is a tie. There is no winner for the chosen array of inputs.

Overall, the code comprises a main game loop that is responsible for handling the game state and user input, along with several utility functions that are used to draw the board, validate the moves, check for a full board, and determine if there’s a winner.

Conclusion

Developing a tic-tac-toe game using C++ is an excellent practical exercise to reinforce your programming skills. The article accurately explains how to create tic-tac-toe in C++. The step-by-step guidance provided in this article encompassed a 2D array, functions, and if-else conditions for the readers to understand the game mechanics, user interactions, and efficient code structuring. The detailed walkthrough of the code and the explanation of functions that are crucial to the core gameplay equip the readers with invaluable insights into both the C++ programming practices and the intricacies of a simple game development.

About the author

Kalsoom Bibi

Hello, I am a freelance writer and usually write for Linux and other technology related content