Introduction
Tic-tac-toe is a classic game that has been played for centuries. In this blog post, we will walk you through the process of building a tic-tac-toe game using the C programming language. By following along with the code snippets provided, you will gain a better understanding of arrays, loops, functions, and conditional statements in C.
Understanding the Game
Tic-tac-toe is played on a 3x3 grid, where two players take turns marking X and O in empty cells. The goal is to form a line of three consecutive marks horizontally, vertically, or diagonally. The first player to achieve this wins the game. If all cells are filled without a winner, the game is declared a draw.
Setting Up the Board
Let's start by declaring a 2-dimensional array to represent the tic-tac-toe board. Each element of the array will hold either an 'X', an 'O', or a blank space (' ') to indicate the state of a cell. We will also initialize a few variables to keep track of the game state:
#include <stdio.h>
// Function to display the tic-tac-toe board
void displayBoard(char board[3][3]) {
printf("-------------\n");
for (int i = 0; i < 3; i++) {
printf("| %c | %c | %c |\n", board[i][0], board[i][1], board[i][2]);
printf("-------------\n");
}
}
int main() {
char board[3][3] = { { ' ', ' ', ' ' }, { ' ', ' ', ' ' }, { ' ', ' ', ' ' } };
int row, col;
char currentPlayer = 'X';
int movesLeft = 9;
int gameOver = 0;
// Game logic goes here
return 0;
}
In the code snippet above, we define the displayBoard()
function, which prints the current state of the board. The main()
function sets up the initial board, initializes the variables, and serves as the entry point for our program.
Game Loop
To allow players to take turns and interact with the game, we need to set up a game loop. The loop will continue until there are no moves left or a player wins. Inside the loop, we will display the board, prompt the current player for their move, validate the move, update the board, and check for a win condition.
while (movesLeft > 0 && !gameOver) {
// Display the board
displayBoard(board);
// Get the player's move
printf("Player %c's turn. Enter row (0-2): ", currentPlayer);
scanf("%d", &row);
printf("Enter column (0-2): ");
scanf("%d", &col);
// Check if the move is valid
if (row < 0 || row > 2 || col < 0 || col > 2 || board[row][col] != ' ') {
printf("Invalid move. Try again.\n");
continue;
}
// Make the move
board[row][col] = currentPlayer;
movesLeft--;
// Check if the current player wins
if (checkWin(board, currentPlayer)) {
printf("Player %c wins!\n", currentPlayer);
gameOver = 1;
}
// Switch to the other player
currentPlayer = (currentPlayer == 'X') ? 'O' : 'X';
}
In each iteration of the game loop, we display the current state of the board using the displayBoard()
function. We prompt the current player to enter their move by specifying the row and column numbers. The move is then validated to ensure it is within the bounds of the board and the selected cell is empty. If the move is invalid, an error message is displayed, and the loop continues to the next iteration.
If the move is valid, we update the board by assigning the current player's mark ('X' or 'O') to the selected cell. The movesLeft
variable is decremented to keep track of the remaining moves.
Next, we check if the current player has won the game by calling the checkWin()
function (which we will implement shortly). If a win is detected, we display a congratulatory message and set the gameOver
flag to end the game.
Finally, we switch the current player to the other player by toggling between 'X' and 'O'.
Checking for a Win
To determine if a player has won, we need to check the rows, columns, and diagonals of the board for a matching sequence of marks. We can define the checkWin()
function to handle this logic:
int checkWin(char board[3][3], char player) {
// Check rows
for (int i = 0; i < 3; i++) {
if (board[i][0] == player && board[i][1] == player && board[i][2] == player)
return 1;
}
// Check columns
for (int i = 0; i < 3; i++) {
if (board[0][i] == player && board[1][i] == player && board[2][i] == player)
return 1;
}
// Check diagonals
if (board[0][0] == player && board[1][1] == player && board[2][2] == player)
return 1;
if (board[0][2] == player && board[1][1] == player && board[2][0] == player)
return 1;
return 0;
}
The checkWin()
function takes the current board and the player's mark as parameters. It checks for a win by examining each row, column, and diagonal of the board. If it finds a matching sequence of marks for the given player, it returns 1 to indicate a win. Otherwise, it returns 0 to indicate no win.
Game Conclusion
Once the game loop ends, we can determine whether the game resulted in a win or a draw. If no win is detected, we display a message indicating a draw. Finally, we call the displayBoard()
function one last time to show the final state of the board.
// If no one wins, it's a draw
if (!gameOver)
printf("It's a draw!\n");
// Display the final board
displayBoard(board);
return 0;
Congratulations! You have successfully built a tic-tac-toe game in C. By combining the concepts of arrays, loops, functions, and conditional statements, you have created an interactive game that can be played by two players.
Feel free to further enhance the game by adding additional features, such as a replay option, input validation improvements, or even an AI opponent.
Summary
In this blog post, we covered the step-by-step process of building a tic-tac-toe game in C. By following the explanations and code snippets provided, you gained insight into the implementation of the game logic, the board representation using arrays, the game loop, and the win condition checking.
Programming games like tic-tac-toe not only strengthens your understanding of programming concepts but also provides a fun and engaging way to apply your knowledge. We encourage you to explore and expand upon this implementation, experiment with new features, and continue building upon your programming skills.
Happy coding!