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;
}
输出展示:
以上为该程序的界面展示,另外如果不小输入了非方向键字符,程序会给出提示:
无效输入(可能输入了非方向键),请按回车继续
只需按下回车即可继续游戏。