一 游戏描述
2048是一款数字益智类游戏,玩家需要使用键盘控制数字方块的移动,合并相同数字的方块,最终达到数字方块上出现“2048”的目标。
每次移动操作,所有数字方块会朝着指定方向同时滑动,并在靠近边界或其他数字方块时停止。如果两个相邻的数字方块数字相同,则它们会合并成一个方块,数字值为原先相同方块的数字值相加。
二 结果展示
- 游戏显示在终端中,可以通过w(向上)s(向下)a(向左)d(向右)进行上下左右四个方向的移动并且在上方显示游戏得分情况,每次移动都会显示移动方向和分数。
- 每次移动都会从2或4中生成两个随机数
- 当数据不能移动产生新的随机数时我们判定游戏失败。
- 当有数值到达2048显示游戏胜利
三 项目代码介绍
一 结构体介绍
struct data//结构体存数据
{
int x;//存储x轴地址
int y;//存储y轴地址
int score;
};
我们定义一个结构进行存储每个空间的位置和数值
二 显示模块
/*
显示当前棋盘数字的情况
struct data *p接收数组首地址
int *grade接收当前的分数
*/
void show(struct data *p,int *grade)
{
printf("分数为%d\n",*grade);//输出当前的分数
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
printf("%d\t",(p+(4*i+j))->score);
}
printf("\n");
}
}
- 我们定义一个函数进行接受结构体数组的首地址和当前的分数
- 通过当前结构体首地址进行遍历整个结构体然后进行输出每个结构体所在位置的数值
三 随机数生成模块
srand(time(NULL));
while (1)
{
int x = rand() % 4;
int y = rand() % 4;
if ((p+4*x+y)->score == 0) //查看随机的坐标是否等于0
{
if (rand() % 10 <5) //判断随机数取10余数是否<5,来限制4出现的几率为50%
{
(p+4*x+y)->score = 4;
break;
}
else
{
(p+4*x+y)->score = 2; //否则2出现的几率为50%
break;
}
}
}
- srand(time(NULL));用来进行随机数种子的改变,是生成的随机数不是相同的
- rand()%4随机生成0~3中的数字
- rand()%10生成0~9的随机数,如果小于5时生成4,大于等于5时生成2
- 随机选定点位,如果这个点位数值为0我们就随机从2或4中生成一个数
四 向上移动模块
我将移动模块分成两个部分,一是计算每个位置的数值,二根据计算结束的数值进行移动
一数值计算模块
for(int x=0;x<4;x++)
{
for(int y=0;y<3;y++)
{ //左右相邻格子数值相同时并且值小于2048将二者相加
if(((p+4*x+y)->score==(p+4*(x-1)+y)->score)&&((p+4*x+y)->score<2048)&&((p+4*x+y)->score!=0))//两数值相等且不为0时进行计算
{
*grade+=(p+4*x+y)->score;//计算当前的分数
(p+4*x+y)->score=0;//后面的一位置为0
(p+4*x+y+1)->score*=2;//前面的值是原来的二倍
}
}
}
- 我们通过两个for循环来进行结构体数组的遍历
-
(p+4*x+y)->score==(p+4*(x-1)+y)->用来判段上下两个数值是否相等
-
(p+4*x+y)->score<2048相加的数值要小于2048
-
(p+4*x+y)->score!=0当数值为0时不进行相加
-
当满足if条件时我们进行俩数值的相加,将前面的数据变成原来的二倍,后面的数据变成0
-
*grade+=(p+4*x+y)->score每当有数值合并时我们将总分加上数值就是我们当前的得分
二模块移动
//位置移动
for(int x=0;x<4;x++)
{
for(int y=0;y<3;y++)
{
if(((p+4*x+y+1)->score==0)&&((p+4*x+y)->score!=0))//当前面是数为0且后面数不为0时互换两者数值
{
(p+4*x+y+1)->score=(p+4*x+y)->score;
(p+4*x+y)->score=0;
}
}
}
- (p+4*x+y+1)->score==0判断前面的数据是否为0
- (p+4*x+y)->score!=0判断移动的数据是否为0
- 如果前面数据为0并且后面数据不为0时我们将前后位置的数值互换
五 完整的移动模块代码
一 向上移动模块
/*
棋子向上移动
struct data *p接收数组首地址
*/
void up(struct data*p,int *grade)//向上移动操作
{
printf("向上移动\n");
for(int k=0;k<3;k++)
{ //数值移动
for(int y=0;y<4;y++)
{
for(int x=3;x>0;x--)
{ //上下相邻格子数值相同时并且值小于2048将二者相加
if((p+4*x+y)->score==(p+4*(x-1)+y)->score&&(p+4*x+y)->score<2048)
{
*grade+=(p+4*x+y)->score;
(p+4*x+y)->score=0;//后面的一位置为0
(p+4*(x-1)+y)->score*=2;//前面的值是原来的二倍
}
}
}
//位置移动
for(int y=0;y<4;y++)
{
for(int x=3;x>0;x--)
{
if((p+4*(x-1)+y)->score==0)//当前面是数为0是互换两者数值
{
(p+4*(x-1)+y)->score=(p+4*x+y)->score;
(p+4*x+y)->score=0;
}
}
}
}
}
二 向下移动模块
/*
棋子向下移动
struct data *p接收数组首地址
*/
void down(struct data*p,int *grade)//向下移动操作
{
printf("向下移动\n");
for(int k=0;k<3;k++)
{ //数值移动
for(int y=0;y<4;y++)
{
for(int x=0;x<3;x++)
{ //上下相邻格子数值相同时并且值小于2048将二者相加
if((p+4*x+y)->score==(p+4*(1+x)+y)->score&&(p+4*x+y)->score<2048)
{
*grade+=(p+4*x+y)->score;
(p+4*x+y)->score=0;//后面的一位置为0
(p+4*(x+1)+y)->score*=2;//前面的值是原来的二倍
}
}
}
//位置移动
for(int y=0;y<4;y++)
{
for(int x=0;x<4;x++)
{
if((p+4*(x+1)+y)->score==0)//当前面是数为0是互换两者数值
{
(p+4*(x+1)+y)->score=(p+4*x+y)->score;
(p+4*x+y)->score=0;
}
}
}
}
}
三 向左移动模块
/*
棋子向左移动
struct data *p接收数组首地址
*/
void left(struct data*p,int *grade)//向左移动操作
{
printf("向左移动\n");
for(int k=0;k<3;k++)
{ //数值移动
for(int x=0;x<4;x++)
{
for(int y=3;y>0;y--)
{ //左右相邻格子数值相同时并且值小于2048将二者相加
if((p+4*x+y)->score==(p+4*x+y-1)->score&&(p+4*x+y)->score<2048)
{
*grade+=(p+4*x+y)->score;
(p+4*x+y)->score=0;//后面的一位置为0
(p+4*x+y-1)->score*=2;//前面的值是原来的二倍
}
}
}
//位置移动
for(int x=0;x<4;x++)
{
for(int y=3;y>0;y--)
{
if((p+4*x+y-1)->score==0)//当前面是数为0是互换两者数值
{
(p+4*x+y-1)->score=(p+4*x+y)->score;
(p+4*x+y)->score=0;
}
}
}
}
}
四向右移动模块
/*
棋子向右移动
struct data *p接收数组首地址
*/
void right(struct data*p,int *grade)//向右移动操作
{
printf("向右移动\n");
for(int k=0;k<3;k++)
{ //数值移动
for(int x=0;x<4;x++)
{
for(int y=0;y<3;y++)
{ //左右相邻格子数值相同时并且值小于2048将二者相加
if((p+4*x+y)->score==(p+4*x+y+1)->score&&(p+4*x+y)->score<2048)
{
*grade+=(p+4*x+y)->score;
(p+4*x+y)->score=0;//后面的一位置为0
(p+4*x+y+1)->score*=2;//前面的值是原来的二倍
}
}
}
//位置移动
for(int x=0;x<4;x++)
{
for(int y=0;y<3;y++)
{
if((p+4*x+y+1)->score==0)//当前面是数为0是互换两者数值
{
(p+4*x+y+1)->score=(p+4*x+y)->score;
(p+4*x+y)->score=0;
}
}
}
}
}
四 头节点mode.h
#ifndef __MODE__H//每个函.c文件只能调用这个头节点一次
#define __MODE__H
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
struct data//结构体存数据
{
int x;
int y;
int score;
};
void show(struct data* p,int *grade);//显示棋盘数据
void right(struct data*p,int *grade);//向右移动
void left(struct data*p,int *grade);//向左移动
void up(struct data*p,int *grade);//向上移动
void down(struct data*p,int *grade);//向下移动
void newNum(struct data*p,int *grade);//产生随机数
#endif
五 main.c文件介绍
一 数据初始化
struct data *p = calloc(16,sizeof(struct data));//申请空间进行存放数据
int grade = 0;
for(int i=0;i<4;i++)//初始化数据
{
for (int j=0;j<4;j++)
{
(p+(4*i+j))->x=i;
(p+(4*i+j))->y=j;
(p+(4*i+j))->score=0;
//printf("score0 = %d\n", (p+4*i+j)->score);
}
//printf("\n");
}
- 申请一个空间进行存储数据p是空间的首地址
- 定义一个全局变量grade来存储分数
- 将每一个数据的值都赋值为0
二 判断胜负
//判断胜负
int temp=0,win=0;
for(int i=0;i<16;i++)
{
if((p+i)->score!=0)//判断格子有数据的个数
{
temp++;
}
if((p+i)->score==2048)//判断是否有数为2048
{
win++;
}
}
if(win>0)
{
printf("游戏胜利");//数据达到2048游戏胜利
break;
}
if(temp>14)//数据大于14就不能生成两个随机数了,失败
{
printf("游戏失败");
break;
}
- 申请两个变量temp记录已有数据的格子个数win记录是否有数为2048
- 若temp的值大于14,下次随机数生成将不能产生两个数判断游戏失败
- 若win的值大于0就表示有数据生成
六 完整代码
一 main.c
//show((struct data *)p);显示棋盘数据情况
//right((struct data*)p);向右移动
//left((struct data*)p);向左移动
//up(struct data*p);//向上移动
//down(struct data*p);//向下移动
#include "mode.h"
int main()
{
struct data *p = calloc(16,sizeof(struct data));//申请空间进行存放数据
int grade = 0;
for(int i=0;i<4;i++)//初始化数据
{
for (int j=0;j<4;j++)
{
(p+(4*i+j))->x=i;
(p+(4*i+j))->y=j;
(p+(4*i+j))->score=0;
//printf("score0 = %d\n", (p+4*i+j)->score);
}
//printf("\n");
}
while(1)
{
newNum(p,&grade);//产生随机数
char dierction;//存储空间移动的存储
printf("请输入移动方向");
scanf("%c",&dierction);
while(getchar()!='\n');//去除scanf的缓存空间
if(dierction=='!')//方向移动
break;//退出游戏
else if(dierction=='w')
up(p,&grade);
else if(dierction=='s')
down(p,&grade);
else if(dierction=='a')
left(p,&grade);
else if(dierction=='d')
right(p,&grade);
//判断胜负
int temp=0,win=0;
for(int i=0;i<16;i++)
{
if((p+i)->score!=0)//判断格子有数据的个数
{
temp++;
}
if((p+i)->score==2048)//判断是否有数为2048
{
win++;
}
}
if(win>0)
{
printf("游戏胜利");//数据达到2048游戏胜利
break;
}
if(temp>14)//数据大于14就不能生成两个随机数了,失败
{
printf("游戏失败");
break;
}
}
return 0;
}
二mode.c
#include "mode.h"
void newNum(struct data *p,int *grade)
{
srand(time(NULL));
while (1)
{
int x = rand() % 4;
int y = rand() % 4;
if ((p+4*x+y)->score == 0) //查看随机的坐标是否等于0
{
if (rand() % 10 <5) //判断随机数取10余数是否<5,来限制4出现的几率为50%
{
(p+4*x+y)->score = 4;
break;
}
else
{
(p+4*x+y)->score = 2; //否则2出现的几率为50%
break;
}
}
}
while (1)
{
int x = rand() % 4;
int y = rand() % 4;
if ((p+4*x+y)->score == 0) //查看随机的坐标是否等于0
{
if (rand() % 10 <5) //判断随机数取10余数是否<5,来限制4出现的几率为50%
{
(p+4*x+y)->score = 4;
}
else
{
(p+4*x+y)->score = 2; //否则2出现的几率为50%
}
break;
}
}
show(p, grade);
}
/*
显示当前棋盘数字的情况
struct data *p接收数组首地址
*/
void show(struct data *p,int *grade)
{
printf("分数为%d\n",*grade);
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
printf("%d\t",(p+(4*i+j))->score);
}
printf("\n");
}
}
/*
棋子向右移动
struct data *p接收数组首地址
*/
void right(struct data*p,int *grade)//向右移动操作
{
printf("向右移动\n");
for(int k=0;k<3;k++)
{ //数值移动
for(int x=0;x<4;x++)
{
for(int y=0;y<3;y++)
{ //左右相邻格子数值相同时并且值小于2048将二者相加
if((p+4*x+y)->score==(p+4*x+y+1)->score&&(p+4*x+y)->score<2048)
{
*grade+=(p+4*x+y)->score;
(p+4*x+y)->score=0;//后面的一位置为0
(p+4*x+y+1)->score*=2;//前面的值是原来的二倍
}
}
}
//位置移动
for(int x=0;x<4;x++)
{
for(int y=0;y<3;y++)
{
if((p+4*x+y+1)->score==0)//当前面是数为0是互换两者数值
{
(p+4*x+y+1)->score=(p+4*x+y)->score;
(p+4*x+y)->score=0;
}
}
}
}
}
/*
棋子向左移动
struct data *p接收数组首地址
*/
void left(struct data*p,int *grade)//向左移动操作
{
printf("向左移动\n");
for(int k=0;k<3;k++)
{ //数值移动
for(int x=0;x<4;x++)
{
for(int y=3;y>0;y--)
{ //左右相邻格子数值相同时并且值小于2048将二者相加
if((p+4*x+y)->score==(p+4*x+y-1)->score&&(p+4*x+y)->score<2048)
{
*grade+=(p+4*x+y)->score;
(p+4*x+y)->score=0;//后面的一位置为0
(p+4*x+y-1)->score*=2;//前面的值是原来的二倍
}
}
}
//位置移动
for(int x=0;x<4;x++)
{
for(int y=3;y>0;y--)
{
if((p+4*x+y-1)->score==0)//当前面是数为0是互换两者数值
{
(p+4*x+y-1)->score=(p+4*x+y)->score;
(p+4*x+y)->score=0;
}
}
}
}
}
/*
棋子向下移动
struct data *p接收数组首地址
*/
void down(struct data*p,int *grade)//向下移动操作
{
printf("向下移动\n");
for(int k=0;k<3;k++)
{ //数值移动
for(int y=0;y<4;y++)
{
for(int x=0;x<3;x++)
{ //上下相邻格子数值相同时并且值小于2048将二者相加
if((p+4*x+y)->score==(p+4*(1+x)+y)->score&&(p+4*x+y)->score<2048)
{
*grade+=(p+4*x+y)->score;
(p+4*x+y)->score=0;//后面的一位置为0
(p+4*(x+1)+y)->score*=2;//前面的值是原来的二倍
}
}
}
//位置移动
for(int y=0;y<4;y++)
{
for(int x=0;x<4;x++)
{
if((p+4*(x+1)+y)->score==0)//当前面是数为0是互换两者数值
{
(p+4*(x+1)+y)->score=(p+4*x+y)->score;
(p+4*x+y)->score=0;
}
}
}
}
}
/*
棋子向上移动
struct data *p接收数组首地址
*/
void up(struct data*p,int *grade)//向上移动操作
{
printf("向上移动\n");
for(int k=0;k<3;k++)
{ //数值移动
for(int y=0;y<4;y++)
{
for(int x=3;x>0;x--)
{ //上下相邻格子数值相同时并且值小于2048将二者相加
if((p+4*x+y)->score==(p+4*(x-1)+y)->score&&(p+4*x+y)->score<2048)
{
*grade+=(p+4*x+y)->score;
(p+4*x+y)->score=0;//后面的一位置为0
(p+4*(x-1)+y)->score*=2;//前面的值是原来的二倍
}
}
}
//位置移动
for(int y=0;y<4;y++)
{
for(int x=3;x>0;x--)
{
if((p+4*(x-1)+y)->score==0)//当前面是数为0是互换两者数值
{
(p+4*(x-1)+y)->score=(p+4*x+y)->score;
(p+4*x+y)->score=0;
}
}
}
}
}
三 mode.h
#ifndef __MODE__H
#define __MODE__H
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
struct data//结构体存数据
{
int x;
int y;
int score;
};
void show(struct data* p,int *grade);//显示棋盘数据
void right(struct data*p,int *grade);//向右移动
void left(struct data*p,int *grade);//向左移动
void up(struct data*p,int *grade);//向上移动
void down(struct data*p,int *grade);//向下移动
void newNum(struct data*p,int *grade);//产生随机数
#endif
运行时要三个文件一起运行