用C语言创建2048游戏

CCBeginner
立即练习

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

简介

2048 是一款广受欢迎的数字益智游戏,目标是通过合并相邻的相同数字方块来达到 2048 这个方块。在这个项目中,你将学习如何用 C 语言创建一个简单的 2048 游戏。我们将提供逐步的指导,从初始化游戏棋盘到实现游戏逻辑并运行游戏。

👀 预览

2048 游戏

🎯 任务

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

  • 如何创建项目文件
  • 如何为游戏定义常量
  • 如何实现 main() 函数来运行游戏循环
  • 如何初始化游戏棋盘
  • 如何实现检查游戏状态的函数
  • 如何创建移动方块的逻辑
  • 如何显示游戏棋盘
  • 如何编译和测试游戏

🏆 成果

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

  • 为游戏创建一个 C 程序
  • 使用数组来表示游戏棋盘
  • 实现合并方块的游戏逻辑
  • 显示游戏棋盘
  • 处理玩家输入
  • 检查游戏结束和胜利条件

创建项目文件

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

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

定义常量

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

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

在编写 main() 函数之前,让我们完成一些基本任务来定义一些常量:

#define SIZE 4
#define WIN_SCORE 2048

int board[SIZE][SIZE];
int score = 0;
✨ 查看解决方案并练习

main 函数

int main() {
    srand(time(NULL));
    init_board();
    print_board();

    while (1) {
        if (is_won()) {
            printf("你赢了!\n");
            break;
        }

        if (is_full() &&!can_move()) {
            printf("游戏结束!\n");
            break;
        }

        int direction;
        printf("输入移动方向(0-上, 1-下, 2-左, 3-右): ");
        scanf("%d", &direction);

        if (move(direction)) {
            // 移动后打印棋盘
            print_board();
        }
    }

    return 0;
}
  • init board():此函数调用初始化游戏棋盘,将游戏棋盘的所有单元格设置为 0,然后在随机位置生成两个初始随机数(2 或 4)。
  • print_board():此函数用于显示游戏棋盘的当前状态,包括当前得分和每个单元格上的数字。
  • while (1):这是一个无限循环,将一直运行游戏,直到满足游戏结束条件。

2048 游戏的主要流程在此实现,包括初始化游戏棋盘、移动数字方块、判断游戏胜负以及等待玩家输入以控制游戏进程。

✨ 查看解决方案并练习

初始化游戏棋盘

为了初始化游戏棋盘,我们将创建一个函数 init_board,用于设置棋盘并生成两个初始随机数。

void init_board() {
    // 通过将所有单元格设置为 0 来初始化棋盘
    for (int i = 0; i < SIZE; i++) {
        for (int j = 0; j < SIZE; j++) {
            board[i][j] = 0;
        }
    }

    // 生成两个初始随机数
    for (int k = 0; k < 2; k++) {
        int i = rand() % SIZE;
        int j = rand() % SIZE;
        int value = (rand() % 2 + 1) * 2; // 随机生成 2 或 4
        board[i][j] = value;
    }
}

此函数的作用是,在游戏开始时,清空游戏棋盘上的所有单元格,并在随机位置生成两个初始随机数字方块,为玩家提供初始游戏状态。

✨ 查看解决方案并练习

实现检查游戏状态的函数

我们需要一些函数来检查玩家是否获胜、棋盘是否已满以及是否还有任何有效的移动。以下是这些函数:

int is_full() {
    // 检查棋盘是否已满
    for (int i = 0; i < SIZE; i++) {
        for (int j = 0; j < SIZE; j++) {
            if (board[i][j] == 0) {
                return 0; // 棋盘未满
            }
        }
    }
    return 1; // 棋盘已满
}

int is_won() {
    // 检查玩家是否获胜
    for (int i = 0; i < SIZE; i++) {
        for (int j = 0; j < SIZE; j++) {
            if (board[i][j] == WIN_SCORE) {
                return 1; // 玩家已获胜
            }
        }
    }
    return 0; // 玩家未获胜
}

int can_move() {
    // 检查是否还有任何有效的移动
    for (int i = 0; i < SIZE; i++) {
        for (int j = 0; j < SIZE; j++) {
            if (board[i][j] == 0) {
                return 1; // 仍有可移动的空单元格
            }
            if (j > 0 && board[i][j] == board[i][j - 1]) {
                return 1; // 可以向左移动
            }
            if (j < SIZE - 1 && board[i][j] == board[i][j + 1]) {
                return 1; // 可以向右移动
            }
            if (i > 0 && board[i][j] == board[i - 1][j]) {
                return 1; // 可以向上移动
            }
            if (i < SIZE - 1 && board[i][j] == board[i + 1][j]) {
                return 1; // 可以向下移动
            }
        }
    }
    return 0; // 没有有效的移动了
}
  • int is_full():此函数用于检查棋盘是否已满,即所有单元格都被占用。

  • int is_won():此函数检查玩家是否获胜,即在游戏中是否存在一个值为 WIN_SCORE(通常为 2048)的单元格以获得胜利。

  • int can_move():此函数用于检查是否还有有效的移动步骤,以确保游戏可以继续进行。

✨ 查看解决方案并练习

创建移动方块的逻辑

move 函数中实现移动方块的逻辑。此函数处理玩家在四个方向上的移动:上、下、左、右。它还会检查移动是否有效,更新分数,并生成一个新的随机数。

int move(int dir) {
    int moved = 0;

    // 存储当前棋盘状态
    int prev_board[SIZE][SIZE];
    for (int i = 0; i < SIZE; i++) {
        for (int j = 0; j < SIZE; j++) {
            prev_board[i][j] = board[i][j];
        }
    }

    // 向上移动
    if (dir == 0) {
        for (int j = 0; j < SIZE; j++) {
            for (int i = 1; i < SIZE; i++) {
                if (board[i][j]!= 0) {
                    int k = i;
                    while (k > 0 && board[k - 1][j] == 0) {
                        board[k - 1][j] = board[k][j];
                        board[k][j] = 0;
                        k--;
                        moved = 1;
                    }
                    if (k > 0 && board[k - 1][j] == board[k][j]) {
                        board[k - 1][j] *= 2;
                        score += board[k - 1][j];
                        board[k][j] = 0;
                        moved = 1;
                    }
                }
            }
        }
    }

    // 向下移动
    else if (dir == 1) {
        for (int j = 0; j < SIZE; j++) {
            for (int i = SIZE - 2; i >= 0; i--) {
                if (board[i][j]!= 0) {
                    int k = i;
                    while (k < SIZE - 1 && board[k + 1][j] == 0) {
                        board[k + 1][j] = board[k][j];
                        board[k][j] = 0;
                        k++;
                        moved = 1;
                    }
                    if (k < SIZE - 1 && board[k + 1][j] == board[k][j]) {
                        board[k + 1][j] *= 2;
                        score += board[k + 1][j];
                        board[k][j] = 0;
                        moved = 1;
                    }
                }
            }
        }
    }

    // 向左移动
    else if (dir == 2) {
        for (int i = 0; i < SIZE; i++) {
            for (int j = 1; j < SIZE; j++) {
                if (board[i][j]!= 0) {
                    int k = j;
                    while (k > 0 && board[i][k - 1] == 0) {
                        board[i][k - 1] = board[i][k];
                        board[i][k] = 0;
                        k--;
                        moved = 1;
                    }
                    if (k > 0 && board[i][k - 1] == board[i][k]) {
                        board[i][k - 1] *= 2;
                        score += board[i][k - 1];
                        board[i][k] = 0;
                        moved = 1;
                    }
                }
            }
        }
    }

    // 向右移动
    else if (dir == 3) {
        for (int i = 0; i < SIZE; i++) {
            for (int j = SIZE - 2; j >= 0; j--) {
                if (board[i][j]!= 0) {
                    int k = j;
                    while (k < SIZE - 1 && board[i][k + 1] == 0) {
                        board[i][k + 1] = board[i][k];
                        board[i][k] = 0;
                        k++;
                        moved = 1;
                    }
                    if (k < SIZE - 1 && board[i][k + 1] == board[i][k]) {
                        board[i][k + 1] *= 2;
                        score += board[i][k + 1];
                        board[i][k] = 0;
                        moved = 1;
                    }
                }
            }
        }
    }

    // 检查移动是否成功
    if (moved) {
        // 生成一个新的随机数
        int i = rand() % SIZE;
        int j = rand() % SIZE;
        while (board[i][j]!= 0) {
            i = rand() % SIZE;
            j = rand() % SIZE;
        }
        board[i][j] = (rand() % 2 + 1) * 2; // 生成 2 或 4

        // 移动后打印棋盘
        print_board();
    }

    // 检查移动是否成功
    if (moved) {
        return 1;
    } else {
        // 如果移动失败,恢复之前的棋盘状态
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++) {
                board[i][j] = prev_board[i][j];
            }
        }
        return 0;
    }
}
  • 首先定义一个变量 moved 来标记是否发生了移动。初始值为 0,表示没有移动发生。创建一个名为 prev_board 的临时二维数组来存储游戏棋盘的当前状态,以便在移动失败时可以恢复到之前的状态。

  • 将游戏棋盘的当前状态复制到 prev_board,保存游戏棋盘的当前状态,以防移动失败。

  • 根据 dir 参数的值(0 表示向上,1 表示向下,2 表示向左,3 表示向右),执行相应的移动操作。

  • 如果发生了移动或合并,将 moved 标志设置为 1,表示游戏状态发生了变化。如果移动或合并操作成功执行,将生成一个新的随机数,用于在游戏棋盘的空白位置生成一个新的数字方块。最后,如果发生了移动(moved 为 1),函数返回 1,表示移动成功。如果移动失败(没有移动或合并操作),则将游戏棋盘恢复到之前的状态,返回 0,表示移动失败。

✨ 查看解决方案并练习

显示游戏棋盘

为了显示游戏棋盘,我们将创建一个 print_board 函数,该函数会清除终端并打印棋盘的当前状态。

void print_board() {
    // 清除终端
    system("clear");

    printf("Score: %d\n", score);

    for (int i = 0; i < SIZE; i++) {
        for (int j = 0; j < SIZE; j++) {
            printf("%4d", board[i][j]);
        }
        printf("\n");
    }
}

这里的主要目的是清除终端屏幕,然后在屏幕顶部显示当前得分,接着在屏幕上打印游戏棋盘的状态,以便玩家能够清楚地看到游戏棋盘上的数字方块和得分。这有助于提供一个用户友好的界面,让玩家了解游戏的当前状态。

✨ 查看解决方案并练习

编译与测试

在终端中输入以下命令进行编译和运行:

cd ~/project
gcc -o 2048 2048.c
./2048
2048 游戏
✨ 查看解决方案并练习

总结

在这个项目中,你已经学会了如何用 C 语言创建一个基本的 2048 游戏。你初始化了游戏棋盘,实现了检查游戏状态的函数,创建了移动方块的逻辑,显示了游戏棋盘,并运行了游戏。祝你玩得开心,并进一步完善你的 2048 游戏!

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