当前位置: 首页 > news >正文

基于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"); } //游戏结束位置代码---------------------¥¥(一局游戏完整) }
http://www.cnnetsun.cn/news/143185.html

相关文章:

  • 8MP 环视 / DMS 摄像头,带宽到底有多狠?
  • 【Halcon-2D测量】get_metrology_object_fuzzy_param 函数功能(用于读取计量对象模糊测量参数)
  • 银河距离银河距离银河距离银河距离银河距离
  • 生成式深度学习(用变分自编码器生成图像)
  • 显示器分辨率?【图文详解】显示器分辨率调整?电脑分辨率设置?
  • 基于STM32的智能鞋柜系统设计与实现
  • VBA会被Python代替吗
  • python与nodejs哪个性能高
  • 【含文档+PPT+源码】基于小程序的智能停车管理系统设计与开发
  • Doris的自增列介绍
  • C++编程实践——多线程变量共享问题展开分析
  • 【Android FrameWork】第三十六天:随机数EntropyMixer
  • 介观交通流仿真软件:VISSIM (介观模式)_(16).高级仿真技术
  • 安卓 之 PassthruPatchRecord
  • YOLOv8 训练与检测系统智慧化交通公路上落石检测数据集 智慧道路交通路面障碍物检测数据集 智慧交通、山区公路监控、应急预警平台 YOLOv8 训练与检测系统
  • 基于django智慧农业管理系统设计开发实现
  • Android架构师面试指南:基于跨越速运职位要求的全面解析与参考答案
  • 【2025最新】基于SpringBoot+Vue的企业项目管理系统管理系统源码+MyBatis+MySQL
  • 企业级大学生考勤系统管理系统源码|SpringBoot+Vue+MyBatis架构+MySQL数据库【完整版】
  • 【2025最新】基于SpringBoot+Vue的物资综合管理系统管理系统源码+MyBatis+MySQL
  • 数学梗图数据集分析报告:999张高质量数学主题幽默图片资源
  • 【毕业设计】SpringBoot+Vue+MySQL 美食信息推荐系统平台源码+数据库+论文+部署文档
  • AI核心知识59——大语言模型之Mamba(简洁且通俗易懂版)
  • SpringBoot+Vue 流浪动物救助平台平台完整项目源码+SQL脚本+接口文档【Java Web毕设】
  • SpringBoot+Vue 手机销售网站管理平台源码【适合毕设/课设/学习】Java+MySQL
  • DPJ-138 基于单片机的指纹密码锁系统设计(源代码+proteus仿真)
  • SpringBoot+Vue 流浪动物救助平台管理平台源码【适合毕设/课设/学习】Java+MySQL
  • 【2025最新】基于SpringBoot+Vue的考试系统管理系统源码+MyBatis+MySQL
  • 企业级流浪动物救助平台管理系统源码|SpringBoot+Vue+MyBatis架构+MySQL数据库【完整版】
  • 物资综合管理系统信息管理系统源码-SpringBoot后端+Vue前端+MySQL【可直接运行】