《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时,分三个情况移动:

  1. arr[i][k] == arr[i][j]时
  2. arr[i][k] == 0时
  3. 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小游戏相关推荐

  1. python小项目——2048小游戏(详解)

    2048游戏 原版游戏地址 第一部分 导入所需要的库 第二部分 确认游戏键位设置,并和对应的操作关联 第三部分 获取用户输入的值,并直到有效键位 第四部分 对矩阵的应用,减少代码量 第五部分 创建棋盘 ...

  2. QT小项目---2048小游戏

    目录 效果展示 游戏简介 游戏详情 操作指南 操作技巧 代码实现 QWidget.h Widget.cpp GameWidget.h GameWidget.cpp 总结 效果展示 游戏简介 游戏详情 ...

  3. 大一C语言课程设计之推箱子小游戏

    大一C语言课程设计之推箱子小游戏 先看一下效果 因为技术原因,开发说明没有加进去 按任意键以后 )] 同时响起来 你笑起来真好看的bgm 胜利界面会弹出一个弹出框 私信我或者加我qq:65245534 ...

  4. java课设小迷宫含代码_Java小项目之迷宫游戏的实现方法

    项目要求: 一个网格迷宫由n行n列的单元格组成,每个大院个要么是空地(用0表示),要么是障碍物(用1表示),你的任务是找一条从起点到终点的移动序列,其中只能上下左右移动到相邻单元格.任何时候都不能在有 ...

  5. java 迷宫游戏_Java小项目之迷宫游戏的实现方法

    项目要求: 一个网格迷宫由n行n列的单元格组成,每个大院个要么是空地(用0表示),要么是障碍物(用1表示),你的任务是找一条从起点到终点的移动序列,其中只能上下左右移动到相邻单元格.任何时候都不能在有 ...

  6. c小项目,小码资金管理工具

    纯c小项目,小码资金管理工具moneykeeper 作者:流浪舟 公众号:小码之光 你小码哥回来啦!最近闷得慌,又在学java(自学,想走这条路,哎,一个人找到所爱的真的很难,说不定哪天真的挂了,就来 ...

  7. 前端项目2048小游戏

    第一章 2048游戏介绍 1.1 项目介绍 相信大家都玩过2048这个游戏,这次我们就一步步地来完成2048的开发,这个项目它需要用到html css和js的知识. 需求分析: 1 游戏是一个4x4的 ...

  8. python小项目-python 小项目

    广告关闭 2017年12月,云+社区对外发布,从最开始的技术博客到现在拥有多个社区产品.未来,我们一起乘风破浪,创造无限可能. 事先录制好一段音频,客户接通电话后,自动播放https:blog.csd ...

  9. 开源一个安信可A9g小项目微信小程序定位器项目②GPS模块如何定位经纬度并且上报到MQTT服务器,实现远程查看模块的经纬度;

    本系列博客学习由非官方人员 半颗心脏 潜心所力所写,仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 1. 如何在windows10上环境搭建,编译烧录代码固件,查看运行 ...

最新文章

  1. WebFrom模拟MVC
  2. 设计模式实例(Lua)笔记之五(Bridge模式)
  3. 2018年高教社杯全国大学生数学建模竞赛题目问题B 智能RGV的动态调度策略
  4. 使用java获取本机mac
  5. python基础 dict和set
  6. 在Java 8中使用不带静态导入的Mockito
  7. java 获取服务器网络名_java-siger java使用siger 获取服务器硬件信息(CPU 内存 网络 io等) - 下载 - 搜珍网...
  8. Linux(Ubuntu 19.10)下 Qt5 连接 MySQL(QMYSQL driver not loaded)
  9. Oracle自定义类型
  10. Go Micro搭建简单微服务
  11. libquickmail 0.1.6 发布,邮件发送包
  12. JavaScript 带给学习者的意外和深入认识
  13. 信号量内核对象 semaphore
  14. 软件架构师的12项修炼——关系技能修炼(2)
  15. Lync Server 服务器版本升级
  16. 笔记本电脑需要计算机管理员提供的,笔记本电脑设置了管理员权限钉钉软件安装不了咋办呢...
  17. 龙之谷服务器列表不显示,龙之谷服务器列表,龙之谷服务器列表弹不出来
  18. 中国农业大学研究生计算机学院宿舍,中国农业大学宿舍条件怎么样
  19. 电视机丢失卫星信号出现花屏——Shader
  20. python一键扣图_Python实例:一键批量抠图

热门文章

  1. 离线安装OneNote for Windows 10
  2. sqlserver2012数据库,日志文件损坏修复
  3. mount 命令介绍
  4. python的简单程序代码_怎么样都要学几个python的简单小程序
  5. vue中如何去掉空格
  6. gbase8a rowid功能测试
  7. 文章-智力与常识有什么区别?
  8. Python实现jpg等格式图片(批量)转PDF
  9. ERP系统物料清单管理:自由选配,随需应变!
  10. git 命令详解——checkout