news 2026/1/10 3:41:41

基于C语言实现2048小游戏

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于C语言实现2048小游戏

2048[C语言版]

1.编译环境

*Win10专业版x64 VS2015*

2.项目运行效果

3.思路简介:

1.游戏规则

游戏的规则很简单,你需要控制所有方块向同一个方向运动,两个相同数字的方块撞在一起之后合并成为他们的和,每次操作之后会在空白的方格处随机生成一个2或者4(生成2的概率要大一些),最终得到一个“2048”的方块就算胜利了。

2.核心算法

1、方块移动和合并算法。

主要思想:把游戏数字面板抽象成4行4列的二维数组a[4][4],值为0的位置表示空方块,其他表示对应数字方块。把每一行同等对待,只研究一行的移动和合并算法,然后可以通过遍历行来实现所有行的移动合并算法。在一行中,用b[4]表示一行的一位数组,使用两个下标变量来遍历列项,这里使用j和k,其中j总在k的后面,用来寻找k项后面第一个不为0的数字,而k项用于表示当前待比较的项,总是和j项之间隔着若干个数字0,或者干脆紧挨着。不失一般性,考虑往左滑动时,初始事情况下j等于1,而k等于0,接着判断j项数字是否大于0,若是,则判断j项和k项数字的关系,分成3种情况处理,分别是P1: ,P2: b[k]==0和P3: b[k]!=0且b[k]!=b[j];若否,则j自加1,然后继续寻找k项后面第一个不为0的数字。其中P1,P2和P3分别对应如下:

  • P1:b[k]==b[j],则b[k] = 2 * b[k](说明两数合并了),且b[j] = 0(合并之后要将残留的j项值清零),接着k自加1,然后进行下一次循环。
  • P2:b[k]==0,则表示b[j]之前全是空格子,此时直接移动b[j]到k的位置,也就是b[k] = b[j],然后b[j] = 0(移动后将残留的j项值清零),接着k值不变,然后进行下一次循环。
  • P3:b[k]!=0且b[k]!=b[j],则表示两数不相等且都不为0,此时将两数靠在一起,也就是b[k+1] = b[j]。接着分两种小情况,若j!=k+1,则b[j] = 0(移动后将残留的j项值清零);若否,则表示两数原先就靠在一起,则不进行特殊处理(相当于未移动)。接着k自加1,然后进行下一次循环。

举一个P1的例子,流程表示如下:

一行内移动合并算法描述如下(此例为左移情况,其他方向与之类似,区别仅仅是遍历二维数组的行项和列项的方式)。

4.主要源码:

#include "stdafx.h" #include <time.h> #include <conio.h> #define FRAMERWHIDTH 20 //一个小的格子的宽度 #define FRAMERHIGHT 20 //一个小的格子的高度 int Bound[4][4]; //抽象为地图 int RandNum_nFalge; //是否添加一个新的随机数标志 1--->产生新的随机数 0--->不必产生新的随机数 int Gameover_nFlage; //是否游戏结束 1--->游戏失败结束 2---->游戏胜利结束 0--->继续正常(游戏未结束) int Score; //游戏分数 //数组的移动 下标 k,j; 其中j为k后面的第一个不为0的数字 //左移动 void MoveLeft() { for (int i = 0; i < 4; i++) //一共有4行 { for (int k = 0, j = 1; j < 4; j++) //每一行都是有4列(个数字) { if (Bound[i][j] > 0) //在一行中,只判k只有遇到的第一个非0的个数字 (j>0) { if(Bound[i][k] == Bound[i][j]) //情况一:k == j && j >0 { Score += Bound[i][k++] *= 2; Bound[i][j] = 0; RandNum_nFalge = 1; } else if (Bound[i][k] == 0) //情况二:k == 0 && j>0 { Bound[i][k] = Bound[i][j]; Bound[i][j] = 0; RandNum_nFalge = 1; } else //情况三:k != j &&j >0 { Bound[i][++k] = Bound[i][j]; if (k != j) { Bound[i][j] = 0; RandNum_nFalge = 1; } } } } } } //右移动 void MoveRight() { for (int i = 0; i < 4; i++) //一共有4行 { for (int k = 3, j = 2; j >= 0; j--) //每一行都是有4列(个数字) { if (Bound[i][j] > 0) //在一行中,只判k只有遇到的第一个非0的个数字 (j>0) { if (Bound[i][k] == Bound[i][j]) //情况一:k == j && j >0 { Score += Bound[i][k--] *= 2; Bound[i][j] = 0; RandNum_nFalge = 1; } else if (Bound[i][k] == 0) //情况二:k == 0 && j>0 { Bound[i][k] = Bound[i][j]; Bound[i][j] = 0; RandNum_nFalge = 1; } else //情况三:k != j &&j >0 { Bound[i][--k] = Bound[i][j]; if (k != j) { Bound[i][j] = 0; RandNum_nFalge = 1; } } } } } } //上移动 void MoveUp() { for (int i = 0; i < 4; i++) //一共有4列 { for (int k = 0, j = 1; j < 4; j++) //每一列都是有4个数 { if (Bound[j][i] > 0) //这个里面j为时刻变化的 数组行, i为每一轮变化一次的数组的列(这里面注意体会s数组的i和j的循环和数组里面的区别) { if (Bound[j][i] == Bound[k][i]) //情况一:k == j && j >0 { Score += Bound[k++][i] *= 2; Bound[j][i] = 0; RandNum_nFalge = 1; } else if (Bound[k][i] == 0) //情况二:k == 0 && j>0 { Bound[k][i] = Bound[j][i]; Bound[j][i] = 0; RandNum_nFalge = 1; } else //情况三:k != j &&j >0 { Bound[++k][i] = Bound[j][i]; if (k != j) { Bound[j][i] = 0; RandNum_nFalge = 1; } } } } } } //下移动 void MoveDown() { for (int i = 0; i < 4; i++) //一共有4列 { for (int k = 3, j = 2; j >= 0; j--) //每一列都是有4个数 { if (Bound[j][i] > 0) //这个里面j为时刻变化的 数组行, i为每一轮变化一次的数组的列(这里面注意体会s数组的i和j的循环和数组里面的区别) { if (Bound[j][i] == Bound[k][i]) //情况一:k == j && j >0 { Score += Bound[k--][i] *= 2; Bound[j][i] = 0; RandNum_nFalge = 1; } else if (Bound[k][i] == 0) //情况二:k == 0 && j>0 { Bound[k][i] = Bound[j][i]; Bound[j][i] = 0; RandNum_nFalge = 1; } else //情况三:k != j &&j >0 { Bound[--k][i] = Bound[j][i]; if (k != j) { Bound[j][i] = 0; RandNum_nFalge = 1; } } } } } } //控制游戏的键盘输入 void KeyboardInput() { //char ch; switch (_getch()) { case 'w': case 'W': MoveUp(); break; case 'a': case 'A': MoveLeft(); break; case 's': case 'S': MoveDown(); break; case 'd': case 'D': MoveRight(); break; default: break; } } //绘画出一行数字 void ShowNum_a_Line(int i) { printf_s(" ┃ ┃ ┃ ┃ ┃\n"); printf_s(" ┃"); for (int j = 0; j < 4; j++) { if (0 != Bound[i][j]) { printf_s(" %5d ┃", Bound[i][j]); } else { printf_s(" ┃", Bound[i][j]); } } printf_s("\n"); printf_s(" ┃ ┃ ┃ ┃ ┃\n"); } //检测空余的各自的个数 int nCountNullNum() { int n = 0; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (0 == Bound[i][j]) n++; } } return n; } //生成随机数(该函数只赋值一个空格) void RandNum() { srand((unsigned int)time(NULL)); int n = rand() % nCountNullNum(); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (0 == n) //第n个为0的个子 { Bound[i][j] = rand() % 3 ? 2 : 4; //数组随机生成的第n个为0的空格子,随机赋值的2的该路是4的2倍 goto a; } if (0 == Bound[i][j]) //数到第那n个位0的空格子 { n--; } } } a:; RandNum_nFalge = 0; } void ShowWindows() { printf_s("\n\n\n 游戏名字:2048 分数:%-6d 开发者:诗情画意\n", Score); printf_s(" ------------------------------------------------------------------------------------------\n"); printf_s(" ┏━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┓\n"); for (int i = 0; i < 4; i++) { if (i < 3) { ShowNum_a_Line(i); printf_s(" ┣━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━━┫\n"); } if ( 3 == i) { ShowNum_a_Line(i); printf_s(" ┗━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━━┛\n"); } } printf_s("\n\n W:↑ A:← S:↓ D:→\n"); } //游戏开始之前随机初始化两个格子 void StartDate() { RandNum(); RandNum(); } //游戏是否结束 void CheckGameOver() { int n1 = 0, n2 = 0;//横着、竖着两个两个不相等的 次数 的计数器 for (int i = 0; i < 4; i++) //横着横着2个进行比较 { for (int j = 0; j < 3; j++) { if (Bound[i][j] != Bound[i][j + 1]) { n1++; //n1最多只会比较12次 } if (Bound[i][j] >= 2048) //单独的一个判断单个的Bound[][]是否大于2048,大于就说明游戏结束(胜利) { Gameover_nFlage = 2; } } } for (int i = 0; i < 4; i++) //竖着竖着2个进行比较 { for (int j = 0; j < 3; j++) { if (Bound[j][i] != Bound[j + 1][i]) { n2++; //n2最多只会比较12次 } } } if (n1 == 12 && n2 == 12) { Gameover_nFlage = 1;//游戏结束(游戏失败) } } //开始游戏循环 void StartGame() { system("title 2048"); //改控制台标题名称 system("color 0e"); //改控制台标题背景和内容的颜色 //游戏开始位置代码---------------------¥¥(一局游戏完整) StartDate(); while (true) { ShowWindows(); KeyboardInput(); CheckGameOver(); if (1 == Gameover_nFlage) //判断游戏结束的两种方法(Gameover_nFlage ==1 或 ==2) { printf_s("游戏失败,GAME OVER!!!\n"); } if (2 == Gameover_nFlage) { printf_s("游戏胜利,GAME SUCCESS!!!\n"); } if (1 == RandNum_nFalge) { RandNum(); } system("cls"); } //游戏结束位置代码---------------------¥¥(一局游戏完整) }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/23 13:45:49

springboot古典舞在线交流平台的设计与实现(11525)

有需要的同学&#xff0c;源代码和配套文档领取&#xff0c;加文章最下方的名片哦 一、项目演示 项目演示视频 二、资料介绍 完整源代码&#xff08;前后端源代码SQL脚本&#xff09;配套文档&#xff08;LWPPT开题报告&#xff09;远程调试控屏包运行 三、技术介绍 Java…

作者头像 李华
网站建设 2025/12/21 16:57:17

python 批量将自己的csdn vip文章设为全部可见

你考虑过csdn审核的感受吗.jpg python 获取自己csdn vip可见文章的articleId curlconverter -CSDN博客 import requests# 原始获取文章列表的配置 cookies_get {保护隐私 }headers_get {accept: application/json, text/plain, */*,accept-language: zh-CN,zh;q0.9,en;q0.8,…

作者头像 李华
网站建设 2025/12/26 7:18:44

大学生必备6款AI论文神器:选题开题初稿降重全搞定!

如果你是正在熬夜赶Deadline的毕业生&#xff0c;面对空白的Word文档大脑一片空白&#xff1b;如果你是囊中羞涩的大学生&#xff0c;被知网动辄数百的查重费压得喘不过气&#xff1b;如果你是困在“修改-打回”循环里的研究生&#xff0c;对导师“再改改”的反馈感到绝望……那…

作者头像 李华
网站建设 2026/1/3 23:52:06

LLM API Gateway:LLM API 架构、AI 聚合与成本优化全解(2025深度指南)

摘要&#xff1a;从 OpenAI 引发的 AI API Gateway 经济变革&#xff0c;到企业级多模型聚合架构 n1n.ai 的最佳实践。本文将深入剖析 LLM API 的技术细节&#xff08;协议、鉴权、参数调优&#xff09;&#xff0c;探讨“自建网关”与“聚合服务”的优劣权衡&#xff0c;并提供…

作者头像 李华