Building a Tic-Tac-Toe Game in C

One of my favorite solo projects in C was a Tic-Tac-Toe game that allows a player to compete against the computer. This project helped me understand core concepts like multi-dimensional arrays, conditional logic, and functions in C. Here’s a breakdown of how I designed and implemented this game.


The Goal

The objective was to create a terminal-based Tic-Tac-Toe game where:

  • The user plays as ‘X’ and the computer plays as ‘O’.
  • The board updates dynamically based on the player’s and computer’s moves.
  • The game ends when there’s a winner or no free spaces remain.

Game Flow

  1. Game Initialization
    At the start of the game, the board is reset to a 3×3 grid of empty spaces, and the game runs until a winner is found or the grid is full.
  2. Player vs. Computer Logic
    • The player inputs row and column numbers to make a move.
    • The computer generates random moves while ensuring the chosen space is free.
  3. Win Conditions
    The game checks for a winner after every move by examining rows, columns, and diagonals.
  4. Replay Option
    After each game, the player is prompted to replay or exit.

Breaking Down the Code

1. Resetting the Board

The resetBoard function initializes the game board to an empty state using nested loops:

c
void resetBoard()
{
for (int i = 0; i < 3; i++)
     {
for (int j = 0; j < 3; j++)
        {
board[i][j] = ' ';
}
     }
}
  • This ensures the board is clean before each game.

2. Printing the Board

The printBoard function displays the game board with a grid format for better readability:

c
void printBoard()
{
printf(" %c | %c | %c\n", board[0][0], board[0][1], board[0][2]);
printf("---|---|---\n");
printf(" %c | %c | %c\n", board[1][0], board[1][1], board[1][2]);
printf("---|---|---\n");
printf(" %c | %c | %c\n", board[2][0], board[2][1], board[2][2]);
}
  • The grid visually separates rows and columns, making it easy for players to follow the game.

3. Player Move

The playerMove function allows the user to pick a row and column to place their symbol (X):

c
void playerMove()
{
int x, y;
do {
printf("Enter row #(1-3): ");
scanf("%d", &x);
x--; // Convert to 0-based index
printf("Enter column #(1-3): ");
scanf("%d", &y);
y--; // Convert to 0-based index
if (board[x][y] != ' ')
{
printf("Invalid move\n");
}
else {
board[x][y] = PLAYER;
break;
}
} while (board[x][y] != ' ');
}
  • Input validation ensures the user selects an empty space.

4. Computer Move

The computer makes a random move using rand() while checking for an available space:

c
void computerMove()
{
srand(time(0));
int x, y;
if (checkFreeSpaces() > 0)
{
do {
x = rand() % 3;
y = rand() % 3;
} while (board[x][y] != ' ');
board[x][y] = COMPUTER;
}
}
  • This ensures the game progresses without conflicts from overlapping moves.

5. Checking for a Winner

The checkWinner function evaluates the board to determine if the player or computer has won:

c
char checkWinner()
{
// Check rows and columns
for (int i = 0; i < 3; i++)
{
if (board[i][0] == board[i][1] && board[i][0] == board[i][2] && board[i][0] != ' ')
{
return board[i][0];
}
if (board[0][i] == board[1][i] && board[0][i] == board[2][i] && board[0][i] != ' ')
{
return board[0][i];
}
}
// Check diagonals
if (board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] != ' ')
{
return board[0][0];
}
if (board[0][2] == board[1][1] && board[0][2] == board[2][0] && board[0][2] != ' ')
{
return board[0][2];
}
return ‘ ‘;
}

  • This function identifies a winner by checking all possible win conditions.

6. Announcing the Winner

Finally, the printWinner function declares the result:

c
void printWinner(char winner)
{
if (winner == PLAYER)
{
printf("YOU WIN!\n");
}
else if (winner == COMPUTER)
{
printf("YOU LOSE!\n");
} else
{
printf("IT'S A TIE\n");
}
}

What I Learned

This project enhanced my understanding of:

  1. Multi-dimensional arrays to represent the game board.
  2. Random number generation for the computer’s moves.
  3. Input validation to prevent invalid moves.
  4. Game logic for determining winners and handling ties.

Potential Improvements

  1. Smarter AI: Implementing a minimax algorithm for the computer to make optimal moves.
  2. Graphical Interface: Adding a GUI to make the game more interactive.
  3. Scoring System: Keeping track of wins, losses, and ties across multiple games.

This project was an excellent way to solidify my grasp of C programming fundamentals while also tackling problem-solving in a fun, engaging manner. Let me know if you’d like to dive deeper into specific parts of the code!


Discover more from Ajala Mark

Subscribe to get the latest posts sent to your email.

Leave a Reply

Scroll to Top