Open In App

Tic Tac Toe Game in C

Last Updated : 04 Oct, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Tic Tac Toe is a game that was popularly played on paper or pen using the board. This is a fun game played by people of all ages. But now the digital version is becoming popular to have fun on the same game with friends. In this article, we will learn to write a program that allows a person to play tic tac toe against the computer.

Tic-Tac-Toe-Game-in-C

Components of Tic Tac Toe Game

The working of tic tac toe game is same as traditional tic tac toe having following components:

  • Objective: To be the first to make a straight line with either ‘X’ or ‘O’.
  • Game Board: The board consists of a 3×3 matrix-like structure, having 9 small boxes.
  • The computer: Since it is a two-player game each player gets one chance alternatively. i.e.; first player1 than player2.
  • Moves: The computer starts the game with O. After that player makes moves alternatively.
  • Winning: You win by making your symbol in a row or diagonal or column. Also, as a part of strategy you need to block your opponent from forming a straight line while making of your own.

Note: The program uses the algorithm discussed here to find the best possible move for the computer to make the game competitive.

Implementation of Tic-Tac-Toe Game

C




#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define COMPUTER 1
#define HUMAN 2
#define SIDE 3
#define COMPUTERMOVE 'O'
#define HUMANMOVE 'X'
  
// ---------------- Intelligent Moves start
  
struct Move {
    int row, col;
};
  
char player = 'x', opponent = 'o';
  
// This function returns true if there are moves
// remaining on the board. It returns false if
// there are no moves left to play.
bool isMovesLeft(char board[3][3])
{
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
            if (board[i][j] == '_')
                return true;
    return false;
}
  
// This is the evaluation function
int evaluate(char b[3][3])
{
    // Checking for Rows for X or O victory.
    for (int row = 0; row < 3; row++) {
        if (b[row][0] == b[row][1]
            && b[row][1] == b[row][2]) {
            if (b[row][0] == player)
                return +10;
            else if (b[row][0] == opponent)
                return -10;
        }
    }
  
    // Checking for Columns for X or O victory.
    for (int col = 0; col < 3; col++) {
        if (b[0][col] == b[1][col]
            && b[1][col] == b[2][col]) {
            if (b[0][col] == player)
                return +10;
  
            else if (b[0][col] == opponent)
                return -10;
        }
    }
  
    // Checking for Diagonals for X or O victory.
    if (b[0][0] == b[1][1] && b[1][1] == b[2][2]) {
        if (b[0][0] == player)
            return +10;
        else if (b[0][0] == opponent)
            return -10;
    }
  
    if (b[0][2] == b[1][1] && b[1][1] == b[2][0]) {
        if (b[0][2] == player)
            return +10;
        else if (b[0][2] == opponent)
            return -10;
    }
  
    // Else if none of them have won then return 0
    return 0;
}
  
// This is the minimax function. It considers all
// the possible ways the game can go and returns
// the value of the board
int minimax(char board[3][3], int depth, bool isMax)
{
    int score = evaluate(board);
  
    // If Maximizer has won the game return his/her
    // evaluated score
    if (score == 10)
        return score;
  
    // If Minimizer has won the game return his/her
    // evaluated score
    if (score == -10)
        return score;
  
    // If there are no more moves and no winner then
    // it is a tie
    if (isMovesLeft(board) == false)
        return 0;
  
    // If this maximizer's move
    if (isMax) {
        int best = -1000;
  
        // Traverse all cells
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                // Check if cell is empty
                if (board[i][j] == '_') {
                    // Make the move
                    board[i][j] = player;
                    int val
                        = minimax(board, depth + 1, !isMax);
                    if (val > best) {
                        best = val;
                    }
  
                    // Undo the move
                    board[i][j] = '_';
                }
            }
        }
        return best;
    }
  
    // If this minimizer's move
    else {
        int best = 1000;
  
        // Traverse all cells
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                // Check if cell is empty
                if (board[i][j] == '_') {
                    // Make the move
                    board[i][j] = opponent;
  
                    // Call minimax recursively and choose
                    int val
                        = minimax(board, depth + 1, !isMax);
                    if (val < best) {
                        best = val;
                    }
                    // Undo the move
                    board[i][j] = '_';
                }
            }
        }
        return best;
    }
}
  
// This will return the best possible move for the player
struct Move findBestMove(char board[3][3])
{
    int bestVal = -1000;
    struct Move bestMove;
    bestMove.row = -1;
    bestMove.col = -1;
  
    // Traverse all cells, evaluate minimax function for
    // all empty cells. And return the cell with optimal
    // value.
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            // Check if cell is empty
            if (board[i][j] == '_') {
                // Make the move
                board[i][j] = player;
  
                // compute evaluation function for this
                // move.
                int moveVal = minimax(board, 0, false);
  
                // Undo the move
                board[i][j] = '_';
  
                // If the value of the current move is
                // more than the best value, then update
                // best/
                if (moveVal > bestVal) {
                    bestMove.row = i;
                    bestMove.col = j;
                    bestVal = moveVal;
                }
            }
        }
    }
  
    // printf("The value of the best Move is : %d\n\n",
    //       bestVal);
  
    return bestMove;
}
  
// -----------------------------------Intelligent Moves end
  
// Function to display the game board
void showBoard(char board[][SIDE])
{
    printf("\n\n");
    printf("\t\t\t %c | %c | %c \n", board[0][0],
           board[0][1], board[0][2]);
    printf("\t\t\t--------------\n");
    printf("\t\t\t %c | %c | %c \n", board[1][0],
           board[1][1], board[1][2]);
    printf("\t\t\t--------------\n");
    printf("\t\t\t %c | %c | %c \n\n", board[2][0],
           board[2][1], board[2][2]);
}
  
// Function to show the instructions
void showInstructions()
{
    printf("\t\t\t Tic-Tac-Toe\n\n");
    printf("Choose a cell numbered from 1 to 9 as below "
           "and play\n\n");
  
    printf("\t\t\t 1 | 2 | 3 \n");
    printf("\t\t\t--------------\n");
    printf("\t\t\t 4 | 5 | 6 \n");
    printf("\t\t\t--------------\n");
    printf("\t\t\t 7 | 8 | 9 \n\n");
  
    printf("-\t-\t-\t-\t-\t-\t-\t-\t-\t-\n\n");
}
  
// Function to initialise the game
void initialise(char board[][SIDE], int moves[])
{
    srand(time(NULL));
  
    // Initially, the board is empty
    for (int i = 0; i < SIDE; i++) {
        for (int j = 0; j < SIDE; j++)
            board[i][j] = ' ';
    }
  
    // Fill the moves with numbers
    for (int i = 0; i < SIDE * SIDE; i++)
        moves[i] = i;
  
    // Randomize the moves
    for (int i = 0; i < SIDE * SIDE; i++) {
        int randIndex = rand() % (SIDE * SIDE);
        int temp = moves[i];
        moves[i] = moves[randIndex];
        moves[randIndex] = temp;
    }
}
  
// Function to declare the winner of the game
void declareWinner(int whoseTurn)
{
    if (whoseTurn == COMPUTER)
        printf("COMPUTER has won\n");
    else
        printf("HUMAN has won\n");
}
  
// Function to check if any row is crossed with the same
// player's move
int rowCrossed(char board[][SIDE])
{
    for (int i = 0; i < SIDE; i++) {
        if (board[i][0] == board[i][1]
            && board[i][1] == board[i][2]
            && board[i][0] != ' ')
            return 1;
    }
    return 0;
}
  
// Function to check if any column is crossed with the same
// player's move
int columnCrossed(char board[][SIDE])
{
    for (int i = 0; i < SIDE; i++) {
        if (board[0][i] == board[1][i]
            && board[1][i] == board[2][i]
            && board[0][i] != ' ')
            return 1;
    }
    return 0;
}
  
// Function to check if any diagonal is crossed with the
// same player's move
int diagonalCrossed(char board[][SIDE])
{
    if ((board[0][0] == board[1][1]
         && board[1][1] == board[2][2]
         && board[0][0] != ' ')
        || (board[0][2] == board[1][1]
            && board[1][1] == board[2][0]
            && board[0][2] != ' '))
        return 1;
  
    return 0;
}
  
// Function to check if the game is over
int gameOver(char board[][SIDE])
{
    return (rowCrossed(board) || columnCrossed(board)
            || diagonalCrossed(board));
}
  
// Function to play Tic-Tac-Toe
void playTicTacToe(int whoseTurn)
{
    // A 3*3 Tic-Tac-Toe board for playing
    char board[SIDE][SIDE];
    int moves[SIDE * SIDE];
  
    // Initialise the game
    initialise(board, moves);
  
    // Show the instructions before playing
    showInstructions();
  
    int moveIndex = 0, x, y;
  
    // Keep playing until the game is over or it is a draw
    while (!gameOver(board) && moveIndex != SIDE * SIDE) {
        if (whoseTurn == COMPUTER) {
  
            char tempBoard[3][3];
            for (int i = 0; i < 3; i++) {
                for (int j = 0; j < 3; j++) {
                    if (board[i][j] == 'X') {
                        tempBoard[i][j] = 'x';
                    }
                    else if (board[i][j] == 'O') {
                        tempBoard[i][j] = 'o';
                    }
                    else {
                        tempBoard[i][j] = '_';
                    }
                }
            }
            struct Move thisMove = findBestMove(tempBoard);
            x = thisMove.row;
            y = thisMove.col;
  
            board[x][y] = COMPUTERMOVE;
            printf("COMPUTER has put a %c in cell %d %d\n",
                   COMPUTERMOVE, x, y);
            showBoard(board);
            moveIndex++;
            whoseTurn = HUMAN;
        }
        else if (whoseTurn == HUMAN) {
            int move;
            printf("Enter your move (1-9): ");
            scanf("%d", &move);
            if (move < 1 || move > 9) {
                printf("Invalid input! Please enter a "
                       "number between 1 and 9.\n");
                continue;
            }
            x = (move - 1) / SIDE;
            y = (move - 1) % SIDE;
            if (board[x][y] == ' ') {
                board[x][y] = HUMANMOVE;
                showBoard(board);
                moveIndex++;
                if (gameOver(board)) {
                    declareWinner(HUMAN);
                    return;
                }
                whoseTurn = COMPUTER;
            }
            else {
                printf("Cell %d is already occupied. Try "
                       "again.\n",
                       move);
            }
        }
    }
  
    // If the game has drawn
    if (!gameOver(board) && moveIndex == SIDE * SIDE)
        printf("It's a draw\n");
    else {
        // Toggling the user to declare the actual winner
        if (whoseTurn == COMPUTER)
            whoseTurn = HUMAN;
        else if (whoseTurn == HUMAN)
            whoseTurn = COMPUTER;
  
        // Declare the winner
        declareWinner(whoseTurn);
    }
}
  
// Driver program
int main()
{
    // Let us play the game with COMPUTER starting first
    playTicTacToe(COMPUTER);
  
    return 0;
}


Output

                         Tic-Tac-Toe
Choose a cell numbered from 1 to 9 as below and play
                         1 | 2 | 3 
                        --------------
                         4 | 5 | 6 
                        --------------
                         7 | 8 | 9 
-       -       -       -       -       -       -       -       -       -
COMPUTER has put a O in cell 0 0
                         O |   |   
                        --------------
                           |   |   
                        --------------
                           |   |   
Enter your move (1-9): 9
                         O |   |   
                        --------------
                           |   |   
                        --------------
                           |   | X 
COMPUTER has put a O in cell 0 2
                         O |   | O 
                        --------------
                           |   |   
                        --------------
                           |   | X 
Enter your move (1-9): 2
                         O | X | O 
                        --------------
                           |   |   
                        --------------
                           |   | X 
COMPUTER has put a O in cell 2 1
                         O | X | O 
                        --------------
                           |   |   
                        --------------
                           | O | X 
Enter your move (1-9): 5
                         O | X | O 
                        --------------
                           | X |   
                        --------------
                           | O | X 
COMPUTER has put a O in cell 1 0
                         O | X | O 
                        --------------
                         O | X |   
                        --------------
                           | O | X 
Enter your move (1-9): 6
                         O | X | O 
                        --------------
                         O | X | X 
                        --------------
                           | O | X 
COMPUTER has put a O in cell 2 0
                         O | X | O 
                        --------------
                         O | X | X 
                        --------------
                         O | O | X 
COMPUTER has won

Functions that are used in above code:

  • showboard(): this function is responsible for displaying the current state of the board.
  • showInstructions(): This displays the guide to playing the game.
  • initialise(): This function is used to display the dynamic moves of the game and set the moves with a corresponding empty cell.
  • declareWinner(): This declares who wins the game Computer or Human.
  • rowcrossed(), columncrossed(), diagonalcrossed(): These are used to check who wins the game ie.; which player crosses the row, column, or diagonal.
  • gameover(): this check. If any of the players win or the game draws.
  • makemove(): This updates the game board by the player move.
  • playtictactoe(): This is the main core of the game it checks everything like alternating between computer and human or checking to win or draw, etc.

Overall, this program implements a simple single-player Tic tac Toe game with input validation, user interface, winning logic and the game continues until there is a winner or draw.

If you want to implement Tic-Tac-Toe using Java, and Javascript, refer to the articles:



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads