运行结果预览图
)
源代码展示
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<conio.h>
#include<windows.h>
//过关数字
#define win_number 2048
//定义地图行、列、以及本身
#define row 4
#define col 4
int map[row][col]={0};
//初始化地图
void InitializeMap();
//打印地图
void PrintMap();
//判断是否已经存在2048
int IsWin();
//随机生成一个2或者4,生成2的概率是生成4的概率的3倍
void CreateANumber();
//移动数字
int Move(char turn);
//合并数字
int Combine(char turn);
//gotoxy函数的实现,把光标移到到指定位置
void gotoxy(int x,int y);
int main()
{
srand(time(0)); //时间种子
InitializeMap(); //初始化地图,只有两个数字
char turn;
while(1)
{
PrintMap(); //展示地图
if(IsWin()) //判断是否过关
{
printf("恭喜通关!\n");
break;
}
turn=getch(); //获取用户的移动请求,若移动有效则再次生成一个随机2或4
if(Move(turn)==1)
{
if(Combine(turn))
{
Move(turn);
}
CreateANumber();
}
else if(Combine(turn))
{
Move(turn);
CreateANumber();
}
}
return 0;
}
//初始化地图
void InitializeMap()
{
CreateANumber();
CreateANumber();
}
//打印地图
void PrintMap()
{
int i,j,k;
gotoxy(0,0);
for(i=0;i<row;i++)
{
for(k=1;k<=5*col+1;k++)
{
printf("-");
}
printf("\n|");
for(j=0;j<col;j++)
{
if(map[i][j]>0)
{
printf("%4d|",map[i][j]);
}
else
{
printf("%4s|"," ");
}
}
printf("\n");
}
for(k=1;k<=5*col+1;k++)
{
printf("-");
}
printf("\n");
}
//判断是否已经存在2048
int IsWin()
{
int i,j;
for(i=0;i<row;i++)
{
for(j=0;j<col;j++)
{
if(map[i][j]==win_number)
{
return 1;
}
}
}
return 0;
}
//随机生成一个2或者4,生成2的概率是生成4的概率的3倍
void CreateANumber()
{
int number=rand()%4+1;
if(number!=4)
{
number=2;
}
int i,j;
while(1)
{
i=rand()%row;
j=rand()%col;
if(map[i][j]==0)
{
map[i][j]=number;
break;
}
}
}
//移动数字
int Move(char turn)
{
int flag=0; //是否移动或者合并成功。0:否 1:是
int i,j,k;
switch(turn)
{
case 'w':case 'W'://有空位则下面的非空位往上移
for(i=0;i<row-1;i++)
{
for(j=0;j<col;j++)
{
if(map[i][j]==0)
{
for(k=i+1;k<row;k++)
{
if(map[k][j]>0)
{
map[i][j]=map[k][j];
map[k][j]=0;
flag=1;
break;
}
}
}
}
}
break;
case 's':case 'S'://有空位则上面的非空位往下移
for(i=row-1;i>=1;i--)
{
for(j=0;j<col;j++)
{
if(map[i][j]==0)
{
for(k=i-1;k>=0;k--)
{
if(map[k][j]>0)
{
map[i][j]=map[k][j];
map[k][j]=0;
flag=1;
break;
}
}
}
}
}
break;
case 'a':case 'A'://有空位则右面的非空位往左移
for(j=0;j<col-1;j++)
{
for(i=0;i<row;i++)
{
if(map[i][j]==0)
{
for(k=j+1;k<col;k++)
{
if(map[i][k]>0)
{
map[i][j]=map[i][k];
map[i][k]=0;
flag=1;
break;
}
}
}
}
}
break;
case 'd':case 'D'://有空位则左面的非空位往右移
for(i=0;i<row;i++)
{
for(j=col-1;j>=1;j--)
{
if(map[i][j]==0)
{
for(k=j-1;k>=0;k--)
{
if(map[i][k]>0)
{
map[i][j]=map[i][k];
map[i][k]=0;
flag=1;
break;
}
}
}
}
}
break;
default:
break;
}
return flag;
}
//合并数字
int Combine(char turn)
{
int flag=0; //是否合并成功
int i,j;
switch(turn)
{
case 'w':case 'W'://是否存在下面一个数字和自己的相同且不是0
for(i=0;i<row-1;i++)
{
for(j=0;j<col;j++)
{
if(map[i][j]>0&&map[i][j]==map[i+1][j])
{
map[i][j]*=2;
map[i+1][j]=0;
flag=1;
}
}
}
break;
case 's':case 'S'://是否存在上面一个数字和自己的相同且不是0
for(i=row-1;i>=1;i--)
{
for(j=0;j<col;j++)
{
if(map[i][j]>0&&map[i][j]==map[i-1][j])
{
map[i][j]*=2;
map[i-1][j]=0;
flag=1;
}
}
}
break;
case 'a':case 'A'://是否存在右面一个数字和自己的相同且不是0
for(i=0;i<row;i++)
{
for(j=0;j<col-1;j++)
{
if(map[i][j]>0&&map[i][j]==map[i][j+1])
{
map[i][j]*=2;
map[i][j+1]=0;
flag=1;
}
}
}
break;
case 'd':case 'D'://是否存在左面一个数字和自己的相同且不是0
for(i=0;i<row;i++)
{
for(j=col-1;j>=1;j--)
{
if(map[i][j]>0&&map[i][j]==map[i][j-1])
{
map[i][j]*=2;
map[i][j-1]=0;
flag=1;
}
}
}
break;
default:
break;
}
return flag;
}
//gotoxy函数的实现,把光标移到到指定位置
void gotoxy(int x,int y)
{
COORD pos;
pos.X=y;
pos.Y=x;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);
}
设计解析
总体来说,我们需要准备以下几个步骤:
1.设计存储地图的二维数组
2.打印地图
3.是否已经过关的判断
4.随机将地图中一个为0的元素生成2或4
5.获取玩家的移动或合并请求
6.处理移动和合并是否成功,成功则重新再将一个随机元素为0的生成2或4
7.优化,调用gotoxy使得不闪屏
8.有兴趣的还可以在满屏数字的时候加上判断,判断是否已经无法移动或者合并(提示,在移动和合并的基础上修改便可达到)
设计总结
2048曾是一个广为人知的小游戏,以其简单、有趣的游戏规则深受大家的喜爱,和当初俄罗斯方块刚设计出来一样备受欢迎,如今我们在日渐深入学习c语言的道路上,就可以将平时所见所知尝试着用编程去实现,让编程成为生活不可或缺的一部分。
在设计这个小游戏的过程中,我们首先需要懂得它的详细规则,这意味着我们完成它的制作会涉及到很多逻辑思考,比如生成随机数怎么控制生成2的概率是生成4的概率的3倍呢?怎么让数字移动起来呢?怎么合并数字?合并之后需要再移动一次吗?无形之中,我们的逻辑思维能力会得到很好的提高,为日后用编程处理复杂问题打下基础。
每次设计完成一个作品,然后就写个博客记录下来。以后回头翻看自己的记录,可能会觉得当初的设计非常幼稚,但是肯定也会非常庆幸以前的自己没有学完就把知识扔一边,而是把它运用到最容易提起自己兴趣的地方,每每想到这里,应该会挺开心的吧!