C语言——2048完整版

2048是一个简单又有趣的小游戏,相信大家都接触并了解过,那如何通过代码来实现他呢?下面就让我们来一起看看。

目录

1、头文件

2、主函数

3、 StarGame

 4、GetNum

 5、Show

6、Picture

 7、GetButton

8、MergeLeft

 9、MergeUp

10、MergeRight

11、MergeDown

 12、MergeNum

 13、IsGameover

 14、Run

15、最后附上运行结果一张


1、头文件

其中<graphics.h>是为了使用easyx图形工具,使我们的游戏最终成品得以图像化,<time.h>是为了生成随机种子,保证每一次所出现的数字足够具有随机性。同时还需要两个宏定义,来规范二维数组。以及各个方向的键盘扫描码。

#define _CRT_SECURE_NO_WARNINGS //这一句必须放在第一行
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <conio.h>
#include <graphics.h>		// 引用图形库头文件#define ROW 4
#define COL ROW
#define KEY_UP 72                                                                 /*  方向键'上'的扫描码码值     */
#define KEY_DOWN 80                                                          /*  方向键'下'的扫描码码值     */
#define KEY_LEFT  75                                                             /*  方向键'左'的扫描码码值     */
#define KEY_RIGHT 77                                                           /*  方向键'右'的扫描码码值     */

2、主函数

首先我们先建立一个图形窗口,设置为450*450像素,并且在代码最后关闭绘图窗口,然后设置一个数组,用来存放2048中的每一个数字。一切准备工作做好之后我们就可以调用StarGame与Run函数了。下面我们来一步一步实现这两个函数

int main()
{initgraph(450, 450);	// 创建绘图窗口,大小为 450x450 像素int arr [ROW][COL] = { 0 };StarGame(arr);Run(arr);//运行游戏closegraph();			// 关闭绘图窗口
}

3、 StarGame

想一想2048,游戏开始时会在随机位置生成一个数字,并且打印在屏幕上,所以在这个函数中我们需要“获取随机数字”GetNum,与“打印”Show。

void StarGame(int (*arr)[COL])
{GetNum(arr);GetNum(arr);//提供一个随机数字Show(arr);
}

 4、GetNum

在这个函数中我们通过两步随机数字组合套路对坐标随机性进行控制,再将生成数字的可能性进行调整,最后进行线性检查,如果生成的随机坐标的位置上已经有数字了就顺延到下一位,如果已经到了末尾就顺延到下一行

void GetNum(int(*arr)[COL])
{static int seed=0;//静态变量不会销毁每次都是一样的值srand((unsigned int)time(NULL) + seed);//上面两步是随机数字套路,产生随机种子seed++;//坐标随机int row = rand() % ROW;int col = rand() % COL;//数字随机int num = 2;if (rand() % 5 == 0)//把4的概率置为1/5num = 4;while (arr[row][col]!=0){col++;if (col == COL){row =(row + 1) % ROW;col = 0;}}//线性检查,如果第row行col列有数字就顺延到下一个arr[row][col] = num;
}

 5、Show

加载背景图片,并且打印在屏幕上,注意这里数字也需要背景图片,所以引入一个新函数Picture。

void Show(int(*arr)[COL])//打印
{//system("cls");IMAGE img;loadimage(&img, _T("bk.png"));putimage(0, 0, &img);for (int i = 0; i < ROW; i++){for (int j = 0; j < COL; j++){Picture(arr, i, j);//输出数字对应的照片}}
}

6、Picture

如果数字为“0”时则不需要调用图片,如果数字为“2”等其他数字时则需要调用图片,注意这里的loadimage为easyx的函数。如果有需要这些数字图片的,可以私信我。

bool Picture(int(*arr)[COL], int row, int col)
{IMAGE img;switch (arr[row][col]){case 0://不需要加载图片return false;case 2:loadimage(&img, _T("2.jpg"), 100, 100, true); //这些图片的大小都超过100,100,需要进行相应的缩小break;case 4:loadimage(&img, _T("4.jpg"), 100, 100, true);break;case 8:loadimage(&img, _T("8.jpg"), 100, 100, true);break;case 16:loadimage(&img, _T("16.jpg"), 100, 100, true);break;case 32:loadimage(&img, _T("32.jpg"), 100, 100, true);break;case 64:loadimage(&img, _T("64.jpg"), 100, 100, true);break;case 128:loadimage(&img, _T("128.jpg"), 100, 100, true);break;case 256:loadimage(&img, _T("256.jpg"), 100, 100, true);break;case 512:loadimage(&img, _T("512.jpg"), 100, 100, true);break;case 1024:loadimage(&img, _T("1024.jpg"), 100, 100, true);break;case 2048:loadimage(&img, _T("2048.jpg"), 100, 100, true);break;default:break;}putimage(10 + col * 110, 10 + row * 110, &img);return true;
}

 7、GetButton

想要控制游戏的方向,就需要从键盘读取,所以在这个函数里我们来进行“方向获取”这项工作。

int GetButton()
{ExMessage m;while (peekmessage(&m, EX_KEY)){if (m.message == WM_KEYDOWN){switch (m.vkcode){case VK_LEFT:return 1;case VK_UP:return 2;case VK_RIGHT:return 3;case VK_DOWN:return 4;}}}return 0;
}

接下来我们来上下左右四个方向来添加代码

8、MergeLeft

bool MergeLeft(int(*arr)[COL])
{int index;bool flg = false;for (int i = 0; i < ROW; i++){index = -1;for (int j = 0; j < COL; j++){if (arr[i][j] != 0 && index == -1)index = j;//如果第ij个数字不是0,并且第一个值还没找到,所以把index赋值成当前数字下标else if (arr[i][j] != 0 && arr[i][j] != arr[i][index])index = j;//如果第ij个数字不是0,并且与找到的前一个数字不相等,则抛弃上一个else if (arr[i][j] != 0){arr[i][index] *= 2;arr[i][j] = 0;//如果第ij个数字不是0,并且与找到的值相等,给找到的值*2,并把当前值赋为0flg = true;//如果发生了合并}}index = 0;//可以保存数据的项的下标for (int j = 0; j < COL; j++){if (arr[i][j] != 0)//需要移动{arr[i][index] = arr[i][j];if (index != j){arr[i][j] = 0;flg = true;//如果发生了移动}index++;}	}}return flg;
}

 9、MergeUp

bool MergeUp(int(*arr)[COL])
{int index;//第一个非0值的下标(行)bool flg = false;for (int j = 0; j < COL; j++)//列{index = -1;for (int i = 0; i < ROW; i++)//行,合并数据{if (arr[i][j] != 0 && index == -1)index = i;else if (arr[i][j] != 0 && arr[i][j] != arr[index][j])index = i;else if (arr[i][j] != 0)//合并{arr[index][j] *= 2;arr[i][j] = 0;flg = true;}}index = 0;//可以存放数据的下标(行)for (int i = 0; i < ROW; i++)//移动数据{if (arr[i][j] != 0){arr[index][j] = arr[i][j];if (index != i){arr[i][j] = 0;flg = true;}index++;}}}return flg;
}

10、MergeRight

bool MergeRight(int(*arr)[COL])
{int index;bool flg = false;for (int i = 0; i <ROW; i++){index = -1;for (int j = 3; j >=0; j--){if (arr[i][j] != 0 && index == -1)index = j;//如果第ij个数字不是0,并且第一个值还没找到,所以把index赋值成当前数字下标else if (arr[i][j] != 0 && arr[i][j] != arr[i][index])index = j;//如果第ij个数字不是0,并且与找到的前一个数字不相等,则抛弃上一个else if (arr[i][j] != 0){arr[i][index] *= 2;arr[i][j] = 0;//如果第ij个数字不是0,并且与找到的值相等,给找到的值*2,并把当前值赋为0flg = true;//如果发生了合并}}index = 3;//可以保存数据的项的下标for (int j =3; j >=0; j--){if (arr[i][j] != 0)//需要移动{arr[i][index] = arr[i][j];if (index != j){arr[i][j] = 0;flg = true;//如果发生了移动}index--;}}}return flg;
}

11、MergeDown

bool MergeDown(int(*arr)[COL])
{int index;//第一个非0值的下标(行)bool flg = false;for (int j = 0; j<COL; j++)//列{index = -1;for (int i =3; i >=0; i--)//行,合并数据{if (arr[i][j] != 0 && index == -1)index = i;else if (arr[i][j] != 0 && arr[i][j] != arr[index][j])index = i;else if (arr[i][j] != 0)//合并{arr[index][j] *= 2;arr[i][j] = 0;flg = true;}}index = 3;//可以存放数据的下标(行)for (int i = 3; i>=0; i--)//移动数据{if (arr[i][j] != 0){arr[index][j] = arr[i][j];if (index != i){arr[i][j] = 0;flg = true;}index--;}}}return flg;
}

 12、MergeNum

保存方向

bool MergeNum(int(*arr)[COL], int direct)
{bool flg = false;switch (direct)//当()里的表达式和某一个case值相同时进入{case 1://向左flg = MergeLeft(arr);break;case 2://向上flg= MergeUp(arr);break;case 3://向右flg = MergeRight(arr);break;case 4://向下flg = MergeDown(arr);break;default:break;}return flg;
}

 13、IsGameover

判断游戏是否结束

bool IsGameover(int(*arr)[COL])
{int count0 = 0;//统计0的个数int i;int j;for (i = 0; i < ROW; i++)//判断是否有空格{for (j = 0; j < COL; j++){if (arr[i][j] == 0)count0++;}}if (count0 != 0)//还有空格return false;//游戏没有结束for (i = 0; i < ROW; i++)//是否有相邻的数字一样{for (j = 0; j < COL; j++){if (j + 1 < COL)//判断当前的值和右边是否相同if (arr[i][j] == arr[i][j + 1])return false;//游戏没有结束if (i + 1 < ROW)//判断当前的值和下边是否相同if (arr[i][j] == arr[i + 1][j])return false;//游戏没有结束}}return true;
}

 14、Run

最后就是我们刚开始提到的Run函数

void Run(int(*arr)[COL])
{int direct;//从键盘获得一个方向while (1){direct= GetButton();//if (!MergeNum(arr, direct))//	continue;//如果没有发生合并或移动就不产生新的数据if (!MergeNum(arr, direct))continue;GetNum(arr);Show(arr);if (IsGameover(arr)){return;//判断游戏是否结束}}
}

15、最后附上运行结果一张

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/205148.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ESP32 S3+3线SPI+HX8347

HX8347 240*320 TFT屏 3线SPI&#xff08;CS,SCL,SDI&#xff09;用ESP32 S3驱动 一、源码 /* SPI Master exampleThis example code is in the Public Domain (or CC0 licensed, at your option.)Unless required by applicable law or agreed to in writing, thissoftware i…

基于下游竞争的在线评论引入策略研究

基于下游竞争的在线评论引入策略研究 分析一下这篇文章吧 中国管理科学的2023年10月的文章&#xff0c;非常新 文章的结论 引入在线评论会使得线下零售商在持续销售阶段降价&#xff0c;线上零售商在持续销售阶段提价&#xff0c;从而使得线上线下零售商的价格差异增大&…

Python 作业解答

1. 在给定的一些数字中找出2个数&#xff0c;使得它们的和为N 题目要求 如给定5个数字 [3&#xff0c;4&#xff0c;9&#xff0c;7&#xff0c;10] 从中选择两个数使用它们的和为11。必须保证这些数据中有答案&#xff0c;并且只有一个答案。 1.1 解题思路一&#xff1a;双…

第2讲、布署Hyper-V软硬件需求:

硬件&#xff1a; 1、处理器&#xff08;CPU&#xff09;&#xff1a; a.处理器必须是64位&#xff0c;1.4GHz b.处理器必须支持硬件虚拟化技术 CPU(主板BIOS启用): Intel VT AMD-V 2、需要启用硬件数据保…

Android平板还能编程?Ubuntu本地安装code-server远程编程写代码

文章目录 1.ubuntu本地安装code-server2. 安装cpolar内网穿透3. 创建隧道映射本地端口4. 安卓平板测试访问5.固定域名公网地址6.结语 1.ubuntu本地安装code-server 准备一台虚拟机,Ubuntu或者centos都可以&#xff0c;这里以VMwhere ubuntu系统为例 下载code server服务,浏览器…

Spark - 输出parqute文件

pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 …

[RK-Linux] 移植Linux-5.10到RK3399(四)| 检查HDMI配置与打开内核LOGO显示

文章目录 一、HDMI二、VOP三、显示内核LOGO一、HDMI RK3399 的 HDMI 接口如图: datasheet 介绍: HDMI 接口各个引脚的作用如下: 接口标签作用HDMI_TX0P HDMI_TX0PA差分信号线,用于传输 HDMI 通道 0 的正向数据HDMI_TX0N HDMI_TX0NA

JavaWeb-Tomcat

1. Web服务器 web服务器由硬件和软件组成&#xff1a; 硬件&#xff1a;计算机系统软件&#xff1a;计算机上安装的服务器软件&#xff0c;安装后可以为web应用提供网络服务。 常见的JavaWeb服务器&#xff1a; Tomcat&#xff08;Apache&#xff09;&#xff1a;应用最广泛的…

数据结构 | 查漏补缺之求叶子结点,分离链接法、最小生成树、DFS、BFS

求叶子结点的个数 参考博文&#xff1a; 树中的叶子结点的个数 计算方法_求树的叶子节点个数-CSDN博客 分离链接法 参考博文 数据结构和算法——哈希查找冲突处理方法&#xff08;开放地址法-线性探测、平方探测、双散列探测、再散列&#xff0c;分离链接法&#xff09;_线性…

如何选择性能测试工具?ab和其它工具的对比分析!

性能测试是保证应用程序高效可靠的重要手段之一&#xff0c;在进行性能测试时&#xff0c;选择合适的性能测试工具非常重要。应当根据测试需求来选择适合的测试工具&#xff0c;本文将会详细介绍ApacheBench&#xff08;简称ab&#xff09;和其他性能测试工具的区别以及如何选择…

Peter算法小课堂—贪心算法

课前思考&#xff1a;贪心是什么&#xff1f;贪心如何“贪”&#xff1f; 课前小视频&#xff1a;什么是贪心算法 - 知乎 (zhihu.com) 贪心 贪心是一种寻找最优解问题的常用方法。 贪心一般将求解过程分拆成若干个步骤&#xff0c;自顶向下&#xff0c;解决问题 太戈编程第…

排序:快速排序(hoare版本)

目录 快速排序&#xff1a; 概念&#xff1a; 动画分析&#xff1a; 代码实现&#xff1a; 代码分析&#xff1a; 代码特性&#xff1a; 常见问题&#xff1a; 快速排序&#xff1a; 概念&#xff1a; 快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法&a…

【项目日记(一)】高并发内存池项目介绍

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:项目日记-高并发内存池⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习C   &#x1f51d;&#x1f51d; 项目日记 1. 前言2. 什么是高并发内存池…

SCI常用的连接词

1、描述相似性连词 Similarly 类似地&#xff0c;相似地 Likewise 同样地 Correspondingly 相应地 Equally 同样地 Not only ….but also 不仅…….而且 In the same way 以同样的方式 2、表示因果关系 Therefore 所以 Thus 因此, 从而&#xff0c;这样 H…

《opencv实用探索·十三》opencv之canny边缘检测

1、canny边缘检测应用场景 目标检测&#xff1a; Canny边缘检测可以用于检测图像中的目标边缘&#xff0c;从而帮助识别和定位物体。在目标检测的流程中&#xff0c;边缘通常是检测的第一步。 图像分割&#xff1a; Canny边缘检测可用于图像分割&#xff0c;即将图像划分为具有…

微服务--08--Seata XA模式 AT模式

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 分布式事务Seata 1.XA模式1.1.两阶段提交1.2.Seata的XA模型1.3.优缺点 AT模式2.1.Seata的AT模型2.2.流程梳理2.3.AT与XA的区别 分布式事务 > 事务–01—CAP理论…

class050 双指针技巧与相关题目【算法】

class050 双指针技巧与相关题目【算法】 算法讲解050【必备】双指针技巧与相关题目 code1 922. 按奇偶排序数组 II // 按奇偶排序数组II // 给定一个非负整数数组 nums。nums 中一半整数是奇数 &#xff0c;一半整数是偶数 // 对数组进行排序&#xff0c;以便当 nums[i] 为…

HarmonyOS开发(十):通知和提醒

1、通知概述 1.1、简介 应用可以通过通知接口发送通知消息&#xff0c;终端用户可以通过通知栏查看通知内容&#xff0c;也可以点击通知来打开应用。 通知使用的的常见场景&#xff1a; 显示接收到的短消息、即使消息...显示应用推送消息显示当前正在进行的事件&#xff0c…

dbug_hub 错误 使用多个ILA导致

记录一下vivado调整dbg_hub时钟调整的方法 (dengkanwen.com) 解决方法参考以上链接。 或&#xff0c;使用高速下载器&#xff1f;

MySQL数据库与其管理工具Navicat

这里介绍MySQL数据库和Navicat的使用 1.下载MySQL数据库及MySQL客户端管理工具Navicat 登录www.mysql.com下载MySQL 登录www.navicat.com.cn/download下载客户端管理工具 2.启动MySQL数据库服务器 以管理员身份打开命令提示窗口 找到mysql的bin目录 输入初始化命令mysqld…