介绍
2048 是一款广受欢迎的数字益智游戏,目标是通过合并相邻的相同数字方块来达到 2048 这个方块。在这个项目中,你将学习如何用 C 语言创建一个简单的 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;
主函数
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

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



