C语言小游戏——2048
2048
2048这款游戏的玩法很简单,每次可以选择上下左右滑动,每滑动一次,所有的数字方块都会往滑动的方向靠拢,系统也会在空白的地方乱数出现一个数字方块,相同数字的方块在靠拢、相撞时会相加。不断的叠加最终拼凑出2048这个数字就算成功。
这款游戏对于整天和二进制打交道的程序猿们来说简直就是量身定做的,当然作为一个程序猿怎么可能随随便便就去玩别人的游戏,我们程序猿不要面子啊,说干就干,撸起袖子就干,分分钟撸他个游戏出来。
其实完成这个游戏并没有多么难,利用简单的二位数组和一些简单的循环和判断就能做到,对于像我这样的编程菜鸟来说是再适合不过了。
以下只是提供一种思路,能力一般,水平有限,仅供参考,注释全部代码如下:
#include<stdio.h>
#include<conio.h>
#include<string.h>
#include<stdlib.h>
#include<time.h>
//设置颜色宏,可能用到的颜色,用于printf()输出时的颜色设置
//格式为printf(颜色A"输出的内容"颜色B);
//表示输出的该段颜色为A色,下一段为B色,一般B用"\033[m"表示默认的黑色
#define NONE "\033[m"
#define RED "\033[0;32;31m"
#define LIGHT_RED "\033[1;31m"
#define GREEN "\033[0;32;32m"
#define LIGHT_GREEN "\033[1;32m"
#define BLUE "\033[0;32;34m"
#define LIGHT_BLUE "\033[1;34m"
#define DARY_GRAY "\033[1;30m"
#define CYAN "\033[0;36m"
#define LIGHT_CYAN "\033[1;36m"
#define PURPLE "\033[0;35m"
#define LIGHT_PURPLE "\033[1;35m"
#define BROWN "\033[0;33m"
#define YELLOW "\033[1;33m"
#define LIGHT_GRAY "\033[0;37m"
#define WHITE "\033[1;37m"
/*
** //操作
** // 1 上 72
** // 2 下 80
** // 3 左 75
** // 4 右 77
**
**函数
**void Arr(int p[][SIZE]); //初始化数组为为 SIZE 个随机值二位数组
**void SetArr(int p[][SIZE]); //每次移动后调用,使得二维数组随机出现一个2或SIZE
**
**int Up(int p[][SIZE]); //向上移动, 返回1表示移动成功,返回0表示移动失败
**int Down(int p[][SIZE]); //向下移动, 返回1表示移动成功,返回0表示移动失败
**int Left(int p[][SIZE]); //向左移动, 返回1表示移动成功,返回0表示移动失败
**int Right(int p[][SIZE]); //向右移动, 返回1表示移动成功,返回0表示移动失败
**
**int Count(int p[][SIZE]); //记录当前总分,返回分数
**int Full(int p[][SIZE]); //判断数组是否满, 返回1表示数组未满,返回1表示数组已满
**void Play(int p[][SIZE]); //开始游戏,该函数调用了"移动函数""判断结束函数"等多个函数
**
**void Show(int p[][SIZE],int flg=1); //输出游戏界面
**void Table_up(int size); //游戏界面上边框
**void Table_down(int size); //游戏界面下边框
**
**思路:
**1、构建二位数组初始化为0,利用随机数函数随机赋值
**2、捕捉键盘上的方向键,用来触发移动数组的函数
**3、构建移动数组的函数,分两部,第1步求该移动方向上相邻相等的数,合并为一个数
** 第2步进行数组移动,把该(列)上第一个不为0的数移至最前,第二个不为0的数移至……
**4、设计函数判断游戏结束标志,结束时应该为没有剩余空格,不能进行任何方向上的移动
**5、设计输出函数,输出游戏界面,并能时事的展示当前游戏状态
**6、设计函数,利用循环实现连续操作,并调用以上函数实现游戏的进行与结束
**7、调用主函数实现上述功能
**
*/
#define SIZE 4 //定义宏,确定游戏中数组的大小
void Arr(int p[][SIZE]) //初始数组随机产生SIZE个数字
{
srand((unsigned int)time(NULL));//随机种子
int i=SIZE;//初始化有SIZE个值
while(i--)
{
int index_row=rand()%SIZE;
int index_col=rand()%SIZE;
int num=(rand()%2+1)*2; //随机2或4
p[index_row][index_col]= num;
}
}
void SetArr(int p[SIZE][SIZE])//随机一个数字插入数组
{
srand((unsigned int)time(NULL));
while(1)
{
int index_row=rand()%SIZE;
int index_col=rand()%SIZE;
if(p[index_row][index_col] != 0) continue;
int num=(rand()%2+1)*2; //随机2或4
p[index_row][index_col]= num;
break;
}
}
int Up(int p[][SIZE]) //向上移动
{
int flg=0; //标记,若函数退出时标记没变,则表示无法移动
for(int k=0; k<SIZE; k++)
{
for(int i=0; i<SIZE-1; i++)
{
if(p[i][k]==0) continue;
//向上合并
for(int j=i+1; j<SIZE; j++)
{
if(p[j][k]!=0) //不为0的数
{
if(p[j][k]==p[i][k]) //若有相邻相等的数,移动至当前位置加倍
{
p[i][k]*=2;
p[j][k]=0;
flg=1;
}
break;
}
}
}
//向上移动
for(int i=0; i<SIZE; i++)
{
if(p[i][k]==0) continue;
for(int j=0; j<i; j++)
{
if(p[j][k]==0)
{
p[j][k]=p[i][k];
p[i][k]=0;
flg=1;
break;
}
}
}
}
if(flg==1) SetArr(p);
return flg;
}
int Down(int p[][SIZE]) //向下移动
{
int flg=0; //标记是否移动成功
for(int k=0; k<SIZE; k++)
{
for(int i=SIZE-1; i>0; i--)
{
if(p[i][k]==0) continue;
//向下合并
for(int j=i-1; j>=0; j--)
{
if(p[j][k]!=0) //不为0的数
{
if(p[j][k]==p[i][k]) //若有相邻相等的数,移动至当前位置加倍
{
p[i][k]*=2;
p[j][k]=0;
flg=1;
}
break;
}
}
}
//向下移动
for(int i=SIZE-1; i>=0; i--)
{
if(p[i][k]==0) continue; //查找该列上的数字
for(int j=SIZE-1; j>i; j--) //移动该数字
{
if(p[j][k]==0)
{
p[j][k]=p[i][k];
p[i][k]=0;
flg=1;
break;
}
}
}
}
if(flg==1) SetArr(p); //移动成功,插入新元素
return flg;
}
int Left(int p[][SIZE]) //向左移动
{
int flg=0; //标记是否移动成功
for(int k=0; k<SIZE; k++)
{
for(int i=0; i<SIZE-1; i++)
{
if(p[k][i]==0) continue;
//向左合并
for(int j=i+1; j<SIZE; j++)
{
if(p[k][j]!=0) //除过p[k][i]外不为0的数
{
if(p[k][j]==p[k][i]) //若有相邻相等的数,移动至当前位置加倍
{
p[k][i]*=2;
p[k][j]=0;
flg=1;
}
break;
}
}
}
//向左移动
for(int i=0; i<SIZE; i++)
{
if(p[k][i]==0) continue; //查找该列上的数字
for(int j=0; j<i; j++) //移动该数字
{
if(p[k][j]==0)
{
p[k][j]=p[k][i];
p[k][i]=0;
flg=1;
break;
}
}
}
}
if(flg==1) SetArr(p); //移动成功,插入新元素
return flg;
}
int Right(int p[SIZE][SIZE])
{
int flg=0; //标记是否移动成功
for(int k=0; k<SIZE; k++) //K表示该行
{
for(int i=SIZE-1; i>0; i--) //i表示列
{
if(p[k][i]==0) continue;
//向右合并
for(int j=i-1; j>=0; j--)
{
if(p[k][j]!=0) //不为0的数
{
if(p[k][j]==p[k][i]) //若有相邻相等的数,移动至当前位置加倍
{
p[k][i]*=2;
p[k][j]=0;
flg=1;
}
break;
}
}
}
//向右移动
for(int i=SIZE-1; i>=0; i--)
{
if(p[k][i]==0) continue; //查找该列上不为0数字
for(int j=SIZE-1; j>i; j--) //移动该数字
{
if(p[k][j]==0)
{
p[k][j]=p[k][i];
p[k][i]=0;
flg=1;
break;
}
}
}
}
if(flg==1) SetArr(p); //移动成功,插入新元素
return flg;
}
int Count(int p[][SIZE])//计算总分
{
int count = 0;
for(int i=0; i<SIZE; i++)
{
for(int j=0; j<SIZE; j++)
{
count += p[i][j];
}
}
return count;
}
int Full(int p[][SIZE]) //监视数组是否满了
{
int flg=0; //标记,如果数组全部有值,则返回0值的flg,表示数组满了
for(int i=0; i<SIZE; i++)
{
for(int j=0; j<SIZE; j++)
{
if(p[i][j]==0)
{
flg=1;
return flg;
}
}
}
return flg; //如果flg=0.数组满了
}
void Table_up(int size)//上表格
{
printf("\t┌──");
for(int k=0; k<SIZE-1; k++)
{
printf("──┬──");
}
printf("──┐\n");
}
void Table_down(int size)//下表格
{
printf("\n\t└──");
for(int k=0; k<SIZE-1; k++)
{
printf("──┴──");
}
printf("──┘\n");
}
void Show(int p[][SIZE],int flg=1)//输出数组,每次调用清屏
{
int count=0;//计数
system("cls"); //清屏效果
//system("color f9");
printf("\t方向↑↓←→移动,Esc退出\n");
Table_up(SIZE); //调用上表格函数
for(int i=0; i<SIZE; i++) //输出游戏中的数组的值
{
printf("\t┊"); //分割线
for(int j=0; j<SIZE; j++)
{
if(p[i][j]==0)
{
printf(LIGHT_PURPLE" "NONE,p[i][j]);//把0值输出为空白
}
else
printf(LIGHT_PURPLE"%4d"NONE,p[i][j]); //设置颜色
printf("┊"); //分割线
}
Table_down(SIZE); //下表格
}
count=Count(p); //调用计数函数计算总分
printf(BROWN"\t本局总分%d\n"NONE,count);
if(flg==0) //移动失败,该方向不可移动
{
printf(RED"\t无法移动,请重更换方向\n"NONE);
}
//判断结束标志
if(Full(p)==0 && Up(p)==0 && Down(p)==0 && Left(p)==0 && Right(p)==0)//方格满了&&不能移动
{
printf("----------------游戏结束------------\n");
printf("-----------双击键盘退出游戏-----------\n");
_getch();
_getch();
exit(0);
}
}
void Play(int p[][SIZE])
{
char tmp; //接受_getch()的第一个返回值
char ch; //接受键盘键入的值
int flg; //标记移动函数是否成功调用
while((tmp=_getch())!=27) //Esc退出 //ch == 0x1B
{
ch=_getch(); //读取功能键时有两个返回值,第二个为真实值
//if(tmp==0 || tmp==0xe0) continue;//非方向键重新录入//注:若tmp为char类型则 0xe0 银对应变成 -32
if(ch==75)
flg=Left(p); //左移
else if(ch==77)
flg=Right(p); //右移
else if(ch==72)
flg=Up(p); //上移
else if(ch==80)
flg=Down(p); //下移
else //键入了非方向键
{
printf(RED"无效输入(可能输入了非方向键),请按回车继续\n"NONE);
continue;
}
Show(p,flg); //输出当前游戏状态
}
}
int main()
{
//默认SIZE大小为4,可更改SIZE大小改变数组大小
int array[SIZE][SIZE] = {0};//构建数组,初始化为"空白"
Arr(array);//初始化内容,随机值
Show(array);//游戏开始界面
Play(array);//开始游戏,该函数调用了"移动函数""判断结束函数"等多个函数
return 0;
}
输出展示:



以上为该程序的界面展示,另外如果不小输入了非方向键字符,程序会给出提示:
无效输入(可能输入了非方向键),请按回车继续
只需按下回车即可继续游戏。
C语言小游戏——2048的更多相关文章
- C语言小游戏: 2048.c
概要:2048.c是一个C语言编写的2048游戏,本文将详细分析它的源码和实现.C语言是一种经典实用的编程语言,本身也不复杂,但是学会C语言和能够编写实用的程序还是有一道鸿沟的.本文试图通过一个例子展 ...
- 【C语言探索之旅】 第一部分第八课:第一个C语言小游戏
内容简介 1.课程大纲 2.第一部分第八课:第一个C语言小游戏 3.第一部分第九课预告: 函数 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答案.还会带大家用C语言编写 ...
- 012-C语言小游戏之推箱子
012-C语言小游戏之推箱子 一.创建游戏地图 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #define ROWS 11 #define COLS 12 char ...
- c语言----<项目>_小游戏<2048>
2048 小游戏 主要是针对逻辑思维的一个训练. 主要学习方面:1.随机数产生的概率.2.行与列在进行移动的时候几种情况.3.MessageBox的使用 #include <iostream&g ...
- c语言小游戏-扫雷的完成
C语言-扫雷游戏 本文将对此游戏做一个大致的概述,此代码适合初学者,编写软件使用了vs2017. 该代码可以实现如下功能: 1.用户可以选择3个难度,分别布置不同个数的雷. 2.随机数设置雷的位置. ...
- C语言小游戏: 推箱子 支线(一)--1
好家伙,考完试了 回顾一下2021 回顾一下某次的作业 妙啊 所以, 做一个推箱子小游戏 1.先去4399找一下关卡灵感 就它了 2.在百度上搜几篇推箱子, 参考其中的"■ ☆"图 ...
- JavaScript小游戏--2048(PC端)
1.初始化棋局 $(document).ready(function() { prepare_for_mobile(); //适配移动端 new_game(); }); 2.开始新游戏 functio ...
- C语言 小游戏之贪吃蛇
还记得非常久曾经听群里人说做贪吃蛇什么的,那时候大一刚学了C语言,认为非常难,根本没什么思路. 前不久群里有些人又在谈论C语言贪吃蛇的事了,看着他们在做,我也打算做一个出来. 如今大三,经过了这一年半 ...
- C语言小游戏:贪吃蛇
#include <graphics.h> #include <conio.h> #include <stdio.h> #define WIDTH 40 //设置宽 ...
随机推荐
- iredmail邮件系统离线搭建手册-从零到无
--时间:2020年10月20日 --作者:飞翔的小胖猪 概述 前言 iRedMail 是一个基于 Linux/BSD 系统的零成本.功能完备.成熟的邮件服务器解决方案.iRedMail 是一个开源. ...
- layout_gravity和gravity
layout_gravity是指控件本身的位置,gravity是指控件内元素的位置.
- webpack--性能优化之打包构建速度和代码调试优化
前言 本文来总结写webpack 在性能方面常见的优化方案. 正文 本文分别总结开发环境和生产环境中在打包构建速度和代码调试功能方面的优化方案,如下: 1.开发环境性能优化 (1)优化打包构建速度 a ...
- Maven插件mybatis-generator,如何让生成的PO类的field上有对应表字段的注释
前言 去年刚入职的时候,我就发现,po类(和数据库表对应的类)上,一片都是光秃秃的,什么注释都没有,类上没注释,field上也没注释. 在以前的项目中,其实我们都是有生成注释的,比如,对于下面这个表: ...
- Linux网卡ifcfg-eth0配置详解
DEVICE="eth1" 网卡名称 NM_CONTROLLED="yes" n ...
- linux su、sudo、sudo su、sudo -i的用法和区别
sudo : 暂时切换到超级用户模式以执行超级用户权限,提示输入密码时该密码为当前用户的密码,而不是超级账户的密码.不过有时间限制,Ubuntu默认一次时长15分钟. su : 切换到某某用户模式,提 ...
- Linux备份数据库,mysqldump命令实例详解
mysqldump是mysql数据库中备份工具,用于将MYSQL服务器中的数据库以标准的sql语言的方式导出,并保存到文件中. 语法: mysqldump (选项) 选项: --add-drop-ta ...
- vue项目启动报错 spawn cmd ENOENT errno: -4058
vue项目启动报错 spawn cmd ENOENT errno: -4058 运行vue项目(npm run dev)报错 提示 'npm' 不是内部或外部命令 cmd输入node -v 有版本号 ...
- 纯css做三角形图标
以前做三角形图标一直是用图片,或者css3旋转,现在才发现原来还有这么简单的三角形 div { border: 10px solid transparent; border-bottom: 10px ...
- python3生成10个成绩列表,求其平均分
import random alist = [random.randint(45,101) for _ in range(10)] #在[45.101)之间生成10个随机数 print(alist) ...