用C语言创建一个简单的井字棋游戏

CCBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

在这个项目中,你将学习如何用C语言创建一个简单的井字棋游戏。游戏将由两名玩家轮流在一个3x3的网格中标记空格。第一个在一行、一列或一条对角线上有三个标记的玩家就是赢家。如果所有空格都被填满,且没有玩家在一行中有三个标记,则游戏平局。

👀 预览

井字棋游戏预览

🎯 任务

在这个项目中,你将学习:

  • 如何创建一个游戏棋盘并用空格初始化它。
  • 如何实现清除屏幕、显示游戏棋盘以及检查游戏是否结束的函数。
  • 如何确定游戏的赢家。
  • 如何实现主游戏循环,让玩家轮流与游戏进行交互。

🏆 成果

完成这个项目后,你将能够:

  • 在C语言中创建和操作数组。
  • 使用循环和条件语句来实现游戏逻辑。
  • 通过命令行界面与用户进行交互。
  • 将代码组织成函数,以提高模块化和可读性。

创建项目文件

首先,创建一个名为tictactoe.c的新文件,并在你喜欢的代码编辑器中打开它。

cd ~/project
touch tictactoe.c
✨ 查看解决方案并练习

定义常量

现在,我们需要编写C代码。第一步是包含头文件:

#include <stdio.h>
#include <stdbool.h>

声明棋盘大小:

char board[3][3];
✨ 查看解决方案并练习

初始化游戏棋盘

用空格初始化游戏棋盘。

void initializeBoard() {
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            board[i][j] = ' ';
        }
    }
}

第一个for循环是外层循环,它使用变量i0迭代到2,表示游戏棋盘上的行数。第二个for循环是内层循环,它使用变量j0迭代到2,依次表示游戏棋盘上的列数。

board[i][j] = ' '在内层循环中,将游戏棋盘第i行第j列的方格内容设置为空格字符(' ')。这意味着整个游戏棋盘被初始化为空状态,棋盘上没有玩家落子。

✨ 查看解决方案并练习

每回合后清空屏幕

实现一个在每回合后清空屏幕的函数。

void clearScreen() {
    printf("\033[H\033[J");
}

clearScreen函数主要用于清除终端或控制台屏幕的内容,以清除上一回合的游戏状态和输出。这是通过向标准输出流(通常是终端窗口)打印一个特殊的转义序列来完成的,该序列会清除屏幕上的文本内容。

printf("\033[H\033[J")使用了ANSI转义序列:

  • \033ASCII转义字符的八进制表示,代表序列的开始。
  • [H表示将光标移动到屏幕的左上角,相当于将光标定位到屏幕的第一行第一列。
  • [J表示清除屏幕。它会清除光标位置之后的所有文本内容,包括之前的游戏状态和输出。

这意味着每次调用clearScreen函数时,它都会清除当前终端或控制台屏幕的内容,以便在下一回合游戏之前显示新的游戏状态,从而得到一个更简洁的界面。

✨ 查看解决方案并练习

显示游戏棋盘

创建printBoard函数,以便在屏幕上直观地显示当前游戏棋盘的状态,让玩家了解棋盘上棋子的位置。这是井字棋游戏中用于展示游戏状态的一部分。

void printBoard() {
    printf("\n");
    printf("  1   2   3\n");
    printf("1 %c | %c | %c\n", board[0][0], board[0][1], board[0][2]);
    printf("  ---------\n");
    printf("2 %c | %c | %c\n", board[1][0], board[1][1], board[1][2]);
    printf("  ---------\n");
    printf("3 %c | %c | %c\n", board[2][0], board[2][1], board[2][2]);
}
✨ 查看解决方案并练习

检查游戏是否结束

实现一个名为isGameOver的函数,用于判断井字棋游戏是否结束,并返回一个布尔值(truefalse)。

bool isGameOver() {
    // 检查行
    for (int i = 0; i < 3; i++) {
        if (board[i][0]!= ' ' && board[i][0] == board[i][1] && board[i][0] == board[i][2]) {
            return true;
        }
    }

    // 检查列
    for (int j = 0; j < 3; j++) {
        if (board[0][j]!= ' ' && board[0][j] == board[1][j] && board[0][j] == board[2][j]) {
            return true;
        }
    }

    // 检查对角线
    if (board[0][0]!= ' ' && board[0][0] == board[1][1] && board[0][0] == board[2][2]) {
        return true;
    }
    if (board[0][2]!= ' ' && board[0][2] == board[1][1] && board[0][2] == board[2][0]) {
        return true;
    }

    // 检查是否平局
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            if (board[i][j] == ' ') {
                return false;
            }
        }
    }

    return true;
}

检查某一行是否有获胜者:如果一行中的三个单元格都被同一个玩家占据,则有获胜者,函数返回true

检查某一列是否有获胜者:如果一列中的三个单元格都被同一个玩家占据,则有获胜者,函数返回true

检查对角线上是否有获胜者:如果任何一条对角线上的三个方格都被同一个玩家占据,则有获胜者,函数返回true

检查是否平局:最后,函数检查所有单元格是否都已被占据,但没有获胜者。如果是这种情况,则游戏平局,函数返回true

✨ 查看解决方案并练习

确定获胜者

定义了一个名为getWinner的函数,其目的是确定井字棋游戏中是否有获胜者,并返回获胜者的标记(XO),如果没有获胜者,则返回一个空格(' ')。

char getWinner() {
    // 检查行
    for (int i = 0; i < 3; i++) {
        if (board[i][0]!= ' ' && board[i][0] == board[i][1] && board[i][0] == board[i][2]) {
            return board[i][0];
        }
    }

    // 检查列
    for (int j = 0; j < 3; j++) {
        if (board[0][j]!= ' ' && board[0][j] == board[1][j] && board[0][j] == board[2][j]) {
            return board[0][j];
        }
    }

    // 检查对角线
    if (board[0][0]!= ' ' && board[0][0] == board[1][1] && board[0][0] == board[2][2]) {
        return board[0][0];
    }
    if (board[0][2]!= ' ' && board[0][2] == board[1][1] && board[0][2] == board[2][0]) {
        return board[0][2];
    }

    return ' '; // 没有获胜者
}
✨ 查看解决方案并练习

实现主游戏循环

编写主游戏循环,让玩家轮流进行游戏并与游戏进行交互。

int main() {
    initializeBoard();
    int currentPlayer = 1;

    while (1) {
        clearScreen();
        printf("Current board state:\n");
        printBoard();

        int row, col;
        printf("Player %d, please enter a row and column (e.g., 1 2):", currentPlayer);

        while (scanf("%d %d", &row, &col)!= 2) {
            printf("Invalid input, please try again: ");
            while (getchar()!= '\n');
        }

        if (row < 1 || row > 3 || col < 1 || col > 3 || board[row - 1][col - 1]!= ' ') {
            printf("Invalid move, please try again.\n");
        } else {
            if (currentPlayer == 1) {
                board[row - 1][col - 1] = 'X';
                currentPlayer = 2;
            } else {
                board[row - 1][col - 1] = 'O';
                currentPlayer = 1;
            }
        }

        if (isGameOver()) {
            clearScreen();
            printf("Game over!\n");
            printBoard();
            char winner = getWinner();
            if (winner!= ' ') {
                printf("Player %c wins!\n", winner);
            } else {
                printf("It's a draw!\n");
            }
            break;
        }
    }

    return 0;
}

调用initializeBoard函数来初始化游戏棋盘,将所有方格设置为空格。

创建一个整数变量currentPlayer,用于跟踪轮到谁下棋。初始设置为1,表示玩家1。

while (1)主循环中:

  • 调用clearScreen函数清除屏幕,以便在每回合后刷新显示。
  • 调用printBoard函数打印当前游戏棋盘。

玩家输入:通过scanf函数提示当前玩家输入行和列坐标,例如Player 1, please enter a row and column (e.g., 1 2): 。如果输入无效(不是两个整数),则显示消息Invalid input, please try again: 并清除输入缓冲区,直到获得有效输入。

输入验证:然后,检查输入的行和列坐标是否有效(范围为1到3),并且所选位置是否为空格。如果输入无效或所选位置已被占用,则显示消息Invalid move, please try again.并要求玩家重新输入。

落子:如果输入有效,代码会根据当前玩家(1或2)在游戏棋盘的相应位置放置一个X或一个O

游戏结束检测:然后,代码调用isGameOver()函数检查游戏是否结束。如果游戏结束,屏幕会清除并显示游戏结束的消息,包括获胜者(如果有)或平局。

游戏结果:如果有获胜者,代码会根据获胜者是哪个玩家显示Player X wins!Player O wins!。如果没有获胜者,代码会显示It's a draw!表示平局。

✨ 查看解决方案并练习

编译并运行项目

执行gcc命令进行编译:

cd ~/project
gcc -o tictactoe tictactoe.c
./tictactoe
井字棋游戏演示
✨ 查看解决方案并练习

总结

恭喜你!你已经成功地用C语言创建了一个简单的井字棋游戏。玩家可以轮流在3x3的网格上标记他们的位置。游戏在每一轮后检查是否有获胜者或平局,并相应地显示结果。这个简单的项目展示了C编程的基本概念,可以作为更复杂游戏开发的起点。

您可能感兴趣的其他 C 教程