【C语言】2048游戏完整实现|控制台版 ( 附完整源码)
引言在C语言学习阶段通过实战项目巩固知识点是最高效的方式。本文分享一个基于C语言的2048游戏实现了四方向滑动、数字合并、胜负判定等核心功能涵盖结构体设计、二维数组操作、随机数生成、控制台绘图等关键技术点代码精简不到200行非常适合作为入门级项目练手。一、项目介绍开发背景2048是一款风靡全球的数字益智游戏玩家通过滑动方块使相同数字合并最终目标是合成2048。本文使用纯C语言在控制台环境下实现该游戏无需任何第三方库帮助初学者理解游戏逻辑的设计思路。技术栈编程语言C语言C99标准核心库stdio.h输入输出、stdlib.h随机数与系统调用、stdbool.h布尔类型、conio.h控制台按键输入、time.h时间种子运行环境Windows控制台核心功能功能编号功能名称功能描述1游戏初始化清空棋盘随机生成两个初始数字2四方向滑动支持↑↓←→四个方向移动方块3数字合并相邻相同数字自动合并2244随机生成每次移动后随机生成2或45胜负判定达到2048胜利无法移动则失败6退出游戏按Q键安全退出二、核心技术要点结构体设计使用结构体封装游戏状态将棋盘数据和游戏状态绑定在一起便于函数间传递数据typedef struct { int board[4][4]; // 4x4游戏棋盘0表示空格 bool isWin; // 是否胜利达到2048 bool isOver; // 是否游戏结束无法移动 } GameState;移动算法设计以左移为核心其他方向通过变换复用左移逻辑右移 反转行 左移 反转行上移 矩阵转置 左移 矩阵转置下移 矩阵转置 右移 矩阵转置控制台绘图使用Unicode制表符绘制棋盘边框┌ ┬ ┐ 表示上边框├ ┼ ┤ 表示中间分隔线└ ┴ ┘ 表示下边框│ 表示竖线分隔按键处理使用conio.h库的_getch()函数捕获方向键72 上箭头80 下箭头75 左箭头77 右箭头随机数生成使用srand(time(NULL))初始化随机种子保证每次游戏随机性不同90%概率生成数字210%概率生成数字4三、核心功能解析游戏初始化initGame函数核心逻辑清空棋盘所有格子为0初始化游戏状态标志设置随机数种子生成两个初始数字代码部分void initGame(GameState* game) { for (int i 0; i 4; i) for (int j 0; j 4; j) game-board[i][j] 0; game-isWin false; game-isOver false; srand((unsigned int)time(NULL)); generateNewNumber(game); generateNewNumber(game); }棋盘打印printBoard函数核心逻辑清屏后打印标题和操作提示使用Unicode字符绘制4x4网格根据数字位数自动调整对齐显示游戏胜利或失败状态代码部分void printBoard(GameState* game) { system(cls); printf( 2048 \n); printf(操作: ↑ ↓ ← → 退出:Q\n\n); printf(┌─────────┬─────────┬─────────┬─────────┐\n); for (int i 0; i 4; i) { printf(│); for (int j 0; j 4; j) { if (game-board[i][j] 0) printf( │); else if (game-board[i][j] 10) printf( %d │, game-board[i][j]); else if (game-board[i][j] 100) printf( %d │, game-board[i][j]); else if (game-board[i][j] 1000) printf( %d │, game-board[i][j]); else printf( %d │, game-board[i][j]); } printf(\n); if (i 3) printf(├─────────┼─────────┼─────────┼─────────┤\n); else printf(└─────────┴─────────┴─────────┴─────────┘\n); } if (game-isWin) printf(\n恭喜你赢了\n); else if (game-isOver) printf(\n游戏结束\n); }左移操作moveLeft函数核心逻辑遍历每一行将非零数字靠左存储合并相邻相同数字每个数字每轮只能合并一次合并后再次靠左更新棋盘并返回是否发生移动代码部分bool moveLeft(GameState* game) { bool moved false; int temp[4]; for (int i 0; i 4; i) { int idx 0; for (int j 0; j 4; j) if (game-board[i][j] ! 0) temp[idx] game-board[i][j]; while (idx 4) temp[idx] 0; for (int j 0; j 3; j) if (temp[j] ! 0 temp[j] temp[j1]) { temp[j] * 2; temp[j1] 0; moved true; } idx 0; int newRow[4] {0}; for (int j 0; j 4; j) if (temp[j] ! 0) newRow[idx] temp[j]; for (int j 0; j 4; j) if (game-board[i][j] ! newRow[j]) { moved true; game-board[i][j] newRow[j]; } } return moved; }其他方向移动复用左移核心逻辑右移先反转每行再左移再反转恢复上移先转置矩阵再左移再转置恢复下移先转置矩阵再右移再转置恢复代码部分bool moveRight(GameState* game) { bool moved false; for (int i 0; i 4; i) for (int j 0; j 2; j) { int t game-board[i][j]; game-board[i][j] game-board[i][3-j]; game-board[i][3-j] t; } moved moveLeft(game); for (int i 0; i 4; i) for (int j 0; j 2; j) { int t game-board[i][j]; game-board[i][j] game-board[i][3-j]; game-board[i][3-j] t; } return moved; } bool moveUp(GameState* game) { bool moved false; int temp[4][4]; for (int i 0; i 4; i) for (int j 0; j 4; j) temp[i][j] game-board[i][j]; for (int i 0; i 4; i) for (int j 0; j 4; j) game-board[i][j] temp[j][i]; moved moveLeft(game); for (int i 0; i 4; i) for (int j 0; j 4; j) temp[i][j] game-board[i][j]; for (int i 0; i 4; i) for (int j 0; j 4; j) game-board[i][j] temp[j][i]; return moved; } bool moveDown(GameState* game) { bool moved false; int temp[4][4]; for (int i 0; i 4; i) for (int j 0; j 4; j) temp[i][j] game-board[i][j]; for (int i 0; i 4; i) for (int j 0; j 4; j) game-board[i][j] temp[j][i]; moved moveRight(game); for (int i 0; i 4; i) for (int j 0; j 4; j) temp[i][j] game-board[i][j]; for (int i 0; i 4; i) for (int j 0; j 4; j) game-board[i][j] temp[j][i]; return moved; }随机生成数字generateNewNumber函数核心逻辑检查棋盘是否已满随机选择一个空位置90%概率生成210%概率生成4代码部分void generateNewNumber(GameState* game) { if (isBoardFull(game)) return; int x, y; do { x rand() % 4; y rand() % 4; } while (game-board[x][y] ! 0); game-board[x][y] (rand() % 10 0) ? 4 : 2; }胜负判定checkGameState函数核心逻辑遍历棋盘检查是否有2048有则胜利调用canMove检查是否还能继续移动不能则失败代码部分void checkGameState(GameState* game) { for (int i 0; i 4; i) for (int j 0; j 4; j) if (game-board[i][j] 2048) { game-isWin true; return; } if (!canMove(game)) game-isOver true; } bool canMove(GameState* game) { if (!isBoardFull(game)) return true; for (int i 0; i 4; i) for (int j 0; j 3; j) if (game-board[i][j] game-board[i][j1]) return true; for (int j 0; j 4; j) for (int i 0; i 3; i) if (game-board[i][j] game-board[i1][j]) return true; return false; }主函数main核心逻辑初始化游戏循环打印棋盘 → 获取按键 → 执行移动 → 生成新数字 → 检查状态游戏结束时等待用户按键退出代码部分int main() { GameState game; initGame(game); while (true) { printBoard(game); if (game.isWin || game.isOver) break; char input _getch(); bool moved false; switch (input) { case 72: moved moveUp(game); break; case 80: moved moveDown(game); break; case 75: moved moveLeft(game); break; case 77: moved moveRight(game); break; case q: case Q: return 0; default: continue; } if (moved) { generateNewNumber(game); checkGameState(game); } } printf(\n按任意键退出\n); _getch(); return 0; }四、运行效果演示示例 1游戏初始界面 2048 操作: ↑ ↓ ← → 退出:Q ┌─────────┬─────────┬─────────┬─────────┐ │ │ 2 │ │ │ ├─────────┼─────────┼─────────┼─────────┤ │ │ │ │ 4 │ ├─────────┼─────────┼─────────┼─────────┤ │ │ │ │ │ ├─────────┼─────────┼─────────┼─────────┤ │ │ │ │ │ └─────────┴─────────┴─────────┴─────────┘示例 2游戏中界面 2048 操作: ↑ ↓ ← → 退出:Q ┌─────────┬─────────┬─────────┬─────────┐ │ │ 2 │ │ 4 │ ├─────────┼─────────┼─────────┼─────────┤ │ 8 │ 16 │ 4 │ │ ├─────────┼─────────┼─────────┼─────────┤ │ │ 2 │ 8 │ 2 │ ├─────────┼─────────┼─────────┼─────────┤ │ 4 │ │ 4 │ 8 │ └─────────┴─────────┴─────────┴─────────┘示例 3游戏胜利 2048 操作: ↑ ↓ ← → 退出:Q ┌─────────┬─────────┬─────────┬─────────┐ │ 2 │ 4 │ 8 │ 16 │ ├─────────┼─────────┼─────────┼─────────┤ │ 64 │ 32 │ 16 │ 8 │ ├─────────┼─────────┼─────────┼─────────┤ │ 256 │ 128 │ 64 │ 32 │ ├─────────┼─────────┼─────────┼─────────┤ │ 16 │ 1024 │ 512 │ 2048 │ └─────────┴─────────┴─────────┴─────────┘ 恭喜你赢了示例 4游戏失败 2048 操作: ↑ ↓ ← → 退出:Q ┌─────────┬─────────┬─────────┬─────────┐ │ 2 │ 4 │ 2 │ 4 │ ├─────────┼─────────┼─────────┼─────────┤ │ 4 │ 2 │ 4 │ 2 │ ├─────────┼─────────┼─────────┼─────────┤ │ 2 │ 4 │ 2 │ 4 │ ├─────────┼─────────┼─────────┼─────────┤ │ 4 │ 2 │ 4 │ 2 │ └─────────┴─────────┴─────────┴─────────┘ 游戏结束五、项目总结与改进方向项目收获掌握C语言结构体的定义与使用理解二维数组的操作技巧学会矩阵转置、反转等算法应用掌握随机数生成与种子初始化学会使用控制台字符绘制简单图形改进方向添加分数统计功能实现撤销功能添加最高分记录跨平台支持Linux/macOS图形界面SDL/OpenGL六、完整源码#include stdio.h #include stdlib.h #include stdbool.h #include conio.h #include time.h typedef struct { int board[4][4]; bool isWin; bool isOver; } GameState; void initGame(GameState* game); void printBoard(GameState* game); void generateNewNumber(GameState* game); bool moveLeft(GameState* game); bool moveRight(GameState* game); bool moveUp(GameState* game); bool moveDown(GameState* game); void checkGameState(GameState* game); bool isBoardFull(GameState* game); bool canMove(GameState* game); void initGame(GameState* game) { for (int i 0; i 4; i) for (int j 0; j 4; j) game-board[i][j] 0; game-isWin false; game-isOver false; srand((unsigned int)time(NULL)); generateNewNumber(game); generateNewNumber(game); } void printBoard(GameState* game) { system(cls); printf( 2048 \n); printf(操作: ↑ ↓ ← → 退出:Q\n\n); printf(┌─────────┬─────────┬─────────┬─────────┐\n); for (int i 0; i 4; i) { printf(│); for (int j 0; j 4; j) { if (game-board[i][j] 0) printf( │); else if (game-board[i][j] 10) printf( %d │, game-board[i][j]); else if (game-board[i][j] 100) printf( %d │, game-board[i][j]); else if (game-board[i][j] 1000) printf( %d │, game-board[i][j]); else printf( %d │, game-board[i][j]); } printf(\n); if (i 3) printf(├─────────┼─────────┼─────────┼─────────┤\n); else printf(└─────────┴─────────┴─────────┴─────────┘\n); } if (game-isWin) printf(\n恭喜你赢了\n); else if (game-isOver) printf(\n游戏结束\n); } void generateNewNumber(GameState* game) { if (isBoardFull(game)) return; int x, y; do { x rand() % 4; y rand() % 4; } while (game-board[x][y] ! 0); game-board[x][y] (rand() % 10 0) ? 4 : 2; } bool isBoardFull(GameState* game) { for (int i 0; i 4; i) for (int j 0; j 4; j) if (game-board[i][j] 0) return false; return true; } bool moveLeft(GameState* game) { bool moved false; int temp[4]; for (int i 0; i 4; i) { int idx 0; for (int j 0; j 4; j) if (game-board[i][j] ! 0) temp[idx] game-board[i][j]; while (idx 4) temp[idx] 0; for (int j 0; j 3; j) if (temp[j] ! 0 temp[j] temp[j1]) { temp[j] * 2; temp[j1] 0; moved true; } idx 0; int newRow[4] {0}; for (int j 0; j 4; j) if (temp[j] ! 0) newRow[idx] temp[j]; for (int j 0; j 4; j) if (game-board[i][j] ! newRow[j]) { moved true; game-board[i][j] newRow[j]; } } return moved; } bool moveRight(GameState* game) { bool moved false; for (int i 0; i 4; i) for (int j 0; j 2; j) { int t game-board[i][j]; game-board[i][j] game-board[i][3-j]; game-board[i][3-j] t; } moved moveLeft(game); for (int i 0; i 4; i) for (int j 0; j 2; j) { int t game-board[i][j]; game-board[i][j] game-board[i][3-j]; game-board[i][3-j] t; } return moved; } bool moveUp(GameState* game) { bool moved false; int temp[4][4]; for (int i 0; i 4; i) for (int j 0; j 4; j) temp[i][j] game-board[i][j]; for (int i 0; i 4; i) for (int j 0; j 4; j) game-board[i][j] temp[j][i]; moved moveLeft(game); for (int i 0; i 4; i) for (int j 0; j 4; j) temp[i][j] game-board[i][j]; for (int i 0; i 4; i) for (int j 0; j 4; j) game-board[i][j] temp[j][i]; return moved; } bool moveDown(GameState* game) { bool moved false; int temp[4][4]; for (int i 0; i 4; i) for (int j 0; j 4; j) temp[i][j] game-board[i][j]; for (int i 0; i 4; i) for (int j 0; j 4; j) game-board[i][j] temp[j][i]; moved moveRight(game); for (int i 0; i 4; i) for (int j 0; j 4; j) temp[i][j] game-board[i][j]; for (int i 0; i 4; i) for (int j 0; j 4; j) game-board[i][j] temp[j][i]; return moved; } bool canMove(GameState* game) { if (!isBoardFull(game)) return true; for (int i 0; i 4; i) for (int j 0; j 3; j) if (game-board[i][j] game-board[i][j1]) return true; for (int j 0; j 4; j) for (int i 0; i 3; i) if (game-board[i][j] game-board[i1][j]) return true; return false; } void checkGameState(GameState* game) { for (int i 0; i 4; i) for (int j 0; j 4; j) if (game-board[i][j] 2048) { game-isWin true; return; } if (!canMove(game)) game-isOver true; } int main() { GameState game; initGame(game); while (true) { printBoard(game); if (game.isWin || game.isOver) break; char input _getch(); bool moved false; switch (input) { case 72: moved moveUp(game); break; case 80: moved moveDown(game); break; case 75: moved moveLeft(game); break; case 77: moved moveRight(game); break; case q: case Q: printf(游戏退出\n); return 0; default: continue; } if (moved) { generateNewNumber(game); checkGameState(game); } } printf(\n按任意键退出\n); _getch(); return 0; }