c语言课程结束小项目:2048小游戏
《C语言程序设计基础》学习完毕,完成第一个项目:2048小游戏。
//思考:编程时,要先想整个框架还是先想每个函数的算法。
//思考:每一个函数要不要传参数(即数组)
//思考:每一个函数之间的联系是什么,谁调用谁…这里很容易搞得头晕,越想越觉得复杂,便不想完成项目了。
将游戏分为几个步骤,拆分来完成每一个函数。
一、定义一个4*4的二维数组arr[4][4],初始化为0;
二、打印界面函数:Show_game();将数组打印出来;
三、随机函数:Add_rand():在数组中随机选出一个元素赋值,并且赋值要随机2或者4。所以就要定义i,j两个数组下表变量,将随机值%4,(求4的余数)就会得到0、1、2、3,将随机值赋值给i、j。还需要随机的2和4,可以在定义一个随机数m,m%3,得到0、1、2,在m大于1的情况下将m赋值给数组元素arr[i][j]。
这里的arr[i][j] = (m>1) ?2:4;这句代码,一句解决,厉害厉害是我最开始没有想到的。都是c语言中最简单的语句,但自己在实际编程中用得少,下意识的只会用if语句去判断,导致代码可读性差。
srand((unsigned) time (NULL));//随机种子。Srand需要用到头文<stdlib.h>,
这句用到time()函数,所以需要用到头文件<time.h>
关于srand()函数:
3.1设置随机的起点
3.2Void srand(unsigned int seed);
3.3参数seed,随机生成的种子。
3.4用法:srand和rand()配合使用产生伪随机数序列。rand函数在产生随机数前,需要系统提供的生成伪随机数序列的种子,rand根据这个种子的值产生一系列随机数。如果系统提供的种子没有变化,每次调用rand函数生成的伪随机数序列都是一样的。srand(unsigned seed)通过参数seed改变系统提供的种子值,从而可以使得每次调用rand函数生成的伪随机数序列不同,从而实现真正意义上的“随机”。通常可以利用系统时间来改变系统的种子值,即srand(time(NULL)),可以为rand函数提供不同的种子值,进而产生不同的随机数序列
四、游戏初始化函数InitGame():游戏开始第一个随机值要定为2
五、*核心算法*上下左右移动函数:Move_****()
我们这里分析左移(其他移动方法几乎相同)
┏━┳━┳━┳━┓i
┣━╋━╋━╋━┫i
┣━╋━╋━╋━┫i
┣━╋━╋━╋━┫i
┗━┻━┻━┻━┛
K J J J
左移的结果:是将每行的元素移动到最左边。
将k列设置为当前列,遍历数组时:i++;j++
找到arr[i][j] == 0时,不管
找到arr[i][j]不为0时,分三个情况移动:
- arr[i][k] == arr[i][j]时
- arr[i][k] == 0时
- arr[i][k] != 0 && arr[i][k] != arr[i][j] 又分两种情况
a.j、k挨着
b.j、k不挨着
右移同理,将k列的当前放在最右边:
┏━┳━┳━┳━┓i
┣━╋━╋━╋━┫i
┣━╋━╋━╋━┫i
┣━╋━╋━╋━┫i
┗━┻━┻━┻━┛
J J J K
上移动:
┏━┳━┳━┳━┓k
┣━╋━╋━╋━┫j
┣━╋━╋━╋━┫j
┣━╋━╋━╋━┫j
┗━┻━┻━┻━┛
i i i i
向下移动:
┏━┳━┳━┳━┓j
┣━╋━╋━╋━┫j
┣━╋━╋━╋━┫j
┣━╋━╋━╋━┫k
┗━┻━┻━┻━┛
i i i i
每一种情况都相似,所以函数只是在遍历是将条件略微根据k、j、i修改。
六、判断游戏是否结束函数:GameOver(). 游戏结束有两个条件:1.没有一个元素为0 2.没有相邻的元素相等。
条件一:定义一个变量n,初始化为0;写了一个bool函数,遍历每一个元素,如果数组中有一个0元素,n++;判断n的值,若n == 0,返回1,说明条件该成立。(这个写法我一开始没有想到用一个计数器n)。
条件二:同样的方法,定义变量n,判断数组相邻位置是否一样n++。若n == 0则没有相邻位置元素一样,返回1。
最后GameOver函数中判断条件一和二,一&&二,则返回1,表示游戏结束。
(这里我写复杂了,用一个bool函数就可以实现,只需要遍历一次,找出n和m的值,if(n==0 &&m==0),则返回true,表示游戏结束)
七、主函数中,接受键盘字符getchar,用到switch语句写接收到的case
八、用到清屏系统命令system(“cls”),需要加头文件<windows.h>。
九、getchar()和getch()是有区别的。它们都是输入单个字符用的。getch()用户不需要按回车,是读取按键值用的,并且需要头文件conio.h。按键输入时,屏幕没有反应。getchar()需要回车,是在输入设备中得到数据用的。按键输入时,屏幕显示输入的字符.
十、上下左右箭头:72 80 75 77.就是数字,不是字符,写成【case ‘75’: 】就错了。这也导致我开始从键盘怎么也读不上箭头符号。
以下源代码:
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<windows.h>
#include<conio.h>int arr[4][4] = {0};//游戏抽象为二维数组int if_add;//是否生成随机数 1表示生成 0不生成void ShowArr()//和下例的函数功能一样,但是下面例子加了边框,游戏观赏性高
{for(int i = 0;i < 4;i++){for(int j = 0;j < 4;j++){printf("%5d",arr[i][j]);}printf("\n\n");}
}
void ShowGame()//游戏界面(参考网上,加了边框,真香)
{printf("\n\n *****2048*****\n");printf("┏━━━┳━━━┳━━━┳━━━┓\n");for(int i = 0;i<4;i++){printf("┃");for(int j = 0;j < 4;j++){//二维数组元素为0if(arr[i][j] == 0){printf(" ┃");//4个空格}else{printf("%3d┃",arr[i][j]);}}if(i<3){printf("\n┣━━━╋━━━╋━━━╋━━━┫\n");}else{printf("\n┗━━━┻━━━┻━━━┻━━━┛\n");printf("****WELCOME****\n\n\n");}}
}void Add_rand()//在随机数组中放入一个随机的2或者4,2的概率要大。
{srand((unsigned) time (NULL));//随机种子int i;int j;int m = rand() % 3;//m可能的结果为0、1、2。while(1){i = rand() % 4;j = rand() % 4;if(arr[i][j] == 0){arr[i][j] = (m>1) ? 4 :2;//m大于1为4,否则为2。这样2的概率为33.3%,4的概率为66.7%break;//生成一个数,则退出}else{continue;//否则执行下一次循环,重新生成随机值。}}
}
void InitGame()//初始化:游戏开始有两个数字
{if_add = 1;//需要生成一个随机数int i = rand()%4;int j = rand()%4;arr[i][j] = 2;//第一个数字为2
}void Move_left()//左移动
{for(int i = 0;i < 4;i++){for(int j = 1,k = 0;j < 4;j++){//先找到k项后面不为0的项if(arr[i][j] > 0)//分3个情况{//1.k项 == j项if(arr[i][k] == arr[i][j]){arr[i][k++] *= 2;//相当于arr[i][k++] <<= 1这样效率更高arr[i][j] = 0;if_add = 1;}//2.k项 == 0else if(arr[i][k] == 0){arr[i][k] = arr[i][j];arr[i][j] = 0;if_add = 1;}//3.k项 != 0;j项 != k项else//分2种情况{arr[i][++k] = arr[i][j];if(j != k){arr[i][j] = 0;if_add = 1;}}}}}}
void Move_right()//右移
{for(int i = 0;i < 4;i++){for(int j = 2,k = 3;j >= 0;j--){//先找到k项前面不为0的项if(arr[i][j] > 0)//分3个情况{//1.k项 == j项if(arr[i][k] == arr[i][j]){arr[i][k--] *= 2;//相当于arr[i][k--] <<= 1这样效率更高arr[i][j] = 0;if_add = 1;}//2.k项 == 0else if(arr[i][k] == 0){arr[i][k] = arr[i][j];arr[i][j] = 0;if_add = 1;}//3.k项 != 0;j项 != k项else//分2种情况{arr[i][--k] = arr[i][j];if(j != k){arr[i][j] = 0;if_add = 1;}}}}}}
void Move_up()//上移
{for(int i = 0;i < 4;i++)//列{for(int j = 1,k = 0;j < 4;j++)//行。{//先找到k项后面不为0的项if(arr[j][i] > 0)//分3个情况{//1.k项 == j项if(arr[k][i] == arr[j][i]){arr[k++][i] *= 2;arr[j][i] = 0;if_add= 1;}//2.k项 == 0else if(arr[k][i] == 0){arr[k][i] = arr[j][i];arr[j][i] = 0;if_add= 1;}//3.k项 != 0;j项 != k项else//分2种情况{arr[++k][i] = arr[j][i];if(j != k){arr[j][i] = 0;if_add = 1;}}}}}}
void Move_down()//下移
{for(int i = 0;i < 4;i++)//列{for(int j = 2,k = 3;j >= 0;j--)//行{//先找到k项后面不为0的项if(arr[j][i] > 0)//分3个情况{//1.k项 == j项if(arr[k][i] == arr[j][i]){arr[k--][i] *= 2;arr[j][i] = 0;if_add= 1;}//2.k项 == 0else if(arr[k][i] == 0){arr[k][i] = arr[j][i];arr[j][i] = 0;if_add= 1;}//3.k项 != 0;j项 != k项else//分2种情况{arr[--k][i] = arr[j][i];if(j != k){arr[j][i] = 0;if_add = 1;}}}}}}
bool TiaoJian_1()//游戏结束条件1:没有格子为0,游戏结束,return 1
{int n = 0;for(int i = 0;i < 4;i++){for(int j = 0;j < 4;j++){if(arr[i][j] == 0){n++;//有格子为零,游戏继续}}}if( n == 0)//游戏结束{return true;}else//游戏继续{return false;}}
bool TiaoJian_2()//2.相邻(上下,左右)的值不相等,则游戏结束,return 1
{int n = 0;for(int i = 0;i < 4;i++){for(int j = 0;j+1 < 4;j++){if((arr[i][j] == arr[i][j+1]) || (arr[j][i] == arr[j+1][i])){n++;}}}if(n == 0)//表示没有相等,结束{return 1;}else{return 0;}
}
bool GameOver()//判断游戏:true表示结束。
{if(TiaoJian_1() && TiaoJian_2()){return true;}else{return false;}}int main()
{InitGame();Add_rand();ShowGame();ShowArr();while(1){int ch;if_add= 0;switch(ch = getch())//接收字符函数{case 'a':case 'A':case '4':case 75:Move_left();break;case 'd':case'D':case '6':case 77:Move_right();break;case'w':case 'W':case '8':case 72:Move_up();break;case 's':case 'S':case'2':case 80:Move_down();break;default:break;}if(if_add == 1){Add_rand();system("cls");//清屏系统命令 ShowGame();//ShowArr();}if(GameOver()){printf(" ***游戏结束***\n点击回车键退出程序");getchar();break;}}
}
c语言课程结束小项目:2048小游戏相关推荐
- python小项目——2048小游戏(详解)
2048游戏 原版游戏地址 第一部分 导入所需要的库 第二部分 确认游戏键位设置,并和对应的操作关联 第三部分 获取用户输入的值,并直到有效键位 第四部分 对矩阵的应用,减少代码量 第五部分 创建棋盘 ...
- QT小项目---2048小游戏
目录 效果展示 游戏简介 游戏详情 操作指南 操作技巧 代码实现 QWidget.h Widget.cpp GameWidget.h GameWidget.cpp 总结 效果展示 游戏简介 游戏详情 ...
- 大一C语言课程设计之推箱子小游戏
大一C语言课程设计之推箱子小游戏 先看一下效果 因为技术原因,开发说明没有加进去 按任意键以后 )] 同时响起来 你笑起来真好看的bgm 胜利界面会弹出一个弹出框 私信我或者加我qq:65245534 ...
- java课设小迷宫含代码_Java小项目之迷宫游戏的实现方法
项目要求: 一个网格迷宫由n行n列的单元格组成,每个大院个要么是空地(用0表示),要么是障碍物(用1表示),你的任务是找一条从起点到终点的移动序列,其中只能上下左右移动到相邻单元格.任何时候都不能在有 ...
- java 迷宫游戏_Java小项目之迷宫游戏的实现方法
项目要求: 一个网格迷宫由n行n列的单元格组成,每个大院个要么是空地(用0表示),要么是障碍物(用1表示),你的任务是找一条从起点到终点的移动序列,其中只能上下左右移动到相邻单元格.任何时候都不能在有 ...
- c小项目,小码资金管理工具
纯c小项目,小码资金管理工具moneykeeper 作者:流浪舟 公众号:小码之光 你小码哥回来啦!最近闷得慌,又在学java(自学,想走这条路,哎,一个人找到所爱的真的很难,说不定哪天真的挂了,就来 ...
- 前端项目2048小游戏
第一章 2048游戏介绍 1.1 项目介绍 相信大家都玩过2048这个游戏,这次我们就一步步地来完成2048的开发,这个项目它需要用到html css和js的知识. 需求分析: 1 游戏是一个4x4的 ...
- python小项目-python 小项目
广告关闭 2017年12月,云+社区对外发布,从最开始的技术博客到现在拥有多个社区产品.未来,我们一起乘风破浪,创造无限可能. 事先录制好一段音频,客户接通电话后,自动播放https:blog.csd ...
- 开源一个安信可A9g小项目微信小程序定位器项目②GPS模块如何定位经纬度并且上报到MQTT服务器,实现远程查看模块的经纬度;
本系列博客学习由非官方人员 半颗心脏 潜心所力所写,仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 1. 如何在windows10上环境搭建,编译烧录代码固件,查看运行 ...
最新文章
- WebFrom模拟MVC
- 设计模式实例(Lua)笔记之五(Bridge模式)
- 2018年高教社杯全国大学生数学建模竞赛题目问题B 智能RGV的动态调度策略
- 使用java获取本机mac
- python基础 dict和set
- 在Java 8中使用不带静态导入的Mockito
- java 获取服务器网络名_java-siger java使用siger 获取服务器硬件信息(CPU 内存 网络 io等) - 下载 - 搜珍网...
- Linux(Ubuntu 19.10)下 Qt5 连接 MySQL(QMYSQL driver not loaded)
- Oracle自定义类型
- Go Micro搭建简单微服务
- libquickmail 0.1.6 发布,邮件发送包
- JavaScript 带给学习者的意外和深入认识
- 信号量内核对象 semaphore
- 软件架构师的12项修炼——关系技能修炼(2)
- Lync Server 服务器版本升级
- 笔记本电脑需要计算机管理员提供的,笔记本电脑设置了管理员权限钉钉软件安装不了咋办呢...
- 龙之谷服务器列表不显示,龙之谷服务器列表,龙之谷服务器列表弹不出来
- 中国农业大学研究生计算机学院宿舍,中国农业大学宿舍条件怎么样
- 电视机丢失卫星信号出现花屏——Shader
- python一键扣图_Python实例:一键批量抠图