C语言课程设计报告游戏.docx
《C语言课程设计报告游戏.docx》由会员分享,可在线阅读,更多相关《C语言课程设计报告游戏.docx(19页珍藏版)》请在冰豆网上搜索。
C语言课程设计报告游戏
东华理工大学
C语言课程设计报告
学院:
国际教育学院学院
专业:
电子信息工程
班级:
1420606
学号:
2
姓名:
钟天运
一、课程设计题目:
游戏2048
二、课程设计要求:
a)使用C语言编写2048这款游戏
b)能够正常运行,拥有游戏界面。
c)能正常进行游戏从开始到结束。
d)用户操作方便
三、设计思路:
a)游戏介绍:
i.2048是一款简单的数字类游戏,界面是一个4*4的方形格子。
每个格子里可以为空或者有一个2^n的数值。
ii.用户可以输入4种指令,分别是:
上下左右,游戏会根据用户的指定的方向,将格子中的数值向对应方向进行移动,直至移动到最边上的格子或者有其他数值占用,如果碰到等大数值,将会进行合并。
此外,成功移动后,会在一个空格子随机生成一个2或者4
iii.游戏目标是合成2048这个数值或者更大的数值。
b)实现思路:
i.可以使用二维数组来保存4*4格子中的数值
ii.指令,可以通过输入字符函数,读取用户在键盘上的方向键,进行判断执行对应的代码。
iii.游戏界面,可以使用简单的特殊制表符,来实现,并通过清屏函数来进行反复同位置打印界面。
iv.需要判断游戏结束的函数,以及记录游戏分数和步骤的变量
v.当游戏结束时,能够询问用户是否重新开始。
vi.随机生成一个新数,可以调用随机函数,使用时间做种子。
c)实现难点:
i.打印游戏界面,要实现灵活能根据棋盘数组里面的数据灵活打印。
ii.执行操作时,数值的移动和合并。
四、流程图
五、C语言源代码
//游戏2048.c
#include"windows.h"
#include"time.h"
#include"stdio.h"
#include"conio.h"
#include"string.h"
//宏定义常量方向键值
//constintLEFT=75,UP=72,RIGHT=77,DOWN=80;
#defineLEFT75
#defineUP72
#defineRIGHT77
#defineDOWN80
constcharerror_str[]="您上次输入的指令无法识别,请重新输入。
";
structboard
{
intplace[4][4];
longintstepn;
longintnum;//存储游戏分数
longinttime;
intdtk;//directionkey记录方向键,及操作方向
intover;
intzeronum;
};
//该函数为游戏运行函数,当只是玩游戏的时候。
进入该函数,游戏控制函数。
intmain()
{
//place数组为棋盘,其中为零代表空,-1代表不能合并的牌,其他2的倍数值为本身含义,初始化为全0。
structboardboard1,board_backup;
intnewgame(structboard*,int),
show(structboard*),
operate(structboard*);
charstr[100]="首次运行游戏";//用于记录系统返回给用户的信息,例如:
上一步执行向左合并,按键有误等
newgame(&board1,0);//调用函数为新局初始化,第二个参数为初始化方式
show(&board1);
printf("\n%s\n\n请从键盘上单击方向键,指定下一步操作(ESC键退出游戏)……\n",str);
do
{
switch(_getch())
{
case224:
{
switch(board1.dtk=_getch())
{
caseLEFT:
strcpy_s(str,sizeof(str),"您上次输入的方向键为:
←,已执行左向合并。
");board_backup=board1;operate(&board1);break;
caseUP:
strcpy_s(str,sizeof(str),"您上次输入的方向键为:
↑,已执行上向合并。
");board_backup=board1;operate(&board1);break;
caseRIGHT:
strcpy_s(str,sizeof(str),"您上次输入的方向键为:
→,已执行右向合并。
");board_backup=board1;operate(&board1);break;
caseDOWN:
strcpy_s(str,sizeof(str),"您上次输入的方向键为:
↓,已执行下向合并。
");board_backup=board1;operate(&board1);break;
default:
strcpy_s(str,sizeof(str),error_str);
}
}break;
case27:
exit(27);
default:
strcpy_s(str,sizeof(str),error_str);
}
system("cls");
show(&board1);
printf("\n%s\n\n请从键盘上单击方向键,指定下一步操作(ESC键退出游戏)……\n",str);
if(board1.over)
{
printf("\n游戏结束,是否重新开始?
(y重新开始/n或ECS退出/其他键无效)");
while
(1)
{
str[99]=_getch();
if(str[99]=='y')
{
newgame(&board1,0);
show(&board1);
break;
}
elseif(str[99]=='c')
{
change(&board1,&board_backup);
break;
}
elseif(str[99]=='n'||str[99]==27)
break;
}
}
}while(!
board1.over);
printf("\n按任意键退出……");
_getch();
return0;
}
//该函数为主要打印函数,包括棋盘的打印,分数,等信息
intshow(structboard*pboard)
{
inti,j,x,len,
numlen(int);
printf("游戏2048——游戏运行时间:
%ldS\n",time(NULL)-(*pboard).time);
printf("游戏分数:
%ld",(*pboard).num);
printf("已执行步骤数:
%ld\n",(*pboard).stepn);
//开始绘制棋盘
printf("╔═══╦═══╦═══╦═══╗\n║║║║║\n");
for(i=0;i<7;++i)
{
if(i%2==0)
{
printf("║");
for(j=0;j<8;++j)
{
if(j%2==0)
{
if((*pboard).place[i/2][j/2]==0)
printf("");//如果值为0,输入六个空格
else//打印值时。
调用numlen判断值的位数,控制数值前后的空格数量,最长为6,若为奇数,前面空格比后面多一个。
{
len=numlen((*pboard).place[i/2][j/2]);
for(x=0;x<(6-len+1)/2;++x)
printf("");
printf("%d",(*pboard).place[i/2][j/2]);
for(x=0;x<(6-len)/2;++x)
printf("");
}
}
else
printf("║");
}
}
else
{
printf("║║║║║\n╠═══╬═══╬═══╬═══╣\n║║║║║");
}
printf("\n");
}
printf("║║║║║\n╚═══╩═══╩═══╩═══╝\n");
return0;
}
//这是show函数的附属函数,用于求一个整数长度。
intnumlen(inta)
{
inti,n=1;
for(i=1;i<11;++i)
{
n*=10;
if(a==a%n)
returni;
}
return0;
}
//开始新的游戏,将棋盘和数据初始化,或者载入棋盘,第二个参数决定初始化方案,默认0
intnewgame(structboard*pboard,intproject)
{
inti,j,t;
(*pboard).stepn=0;
(*pboard).num=0;
(*pboard).time=(longint)time(NULL);//取当前时间为开始时间
(*pboard).dtk=0;
(*pboard).over=0;
(*pboard).zeronum=14;
for(i=0;i<4;++i)
for(j=0;j<4;++j)
(*pboard).place[i][j]=0;
do
{
i=(int)(rand()/32768.0*4);
j=(int)(rand()/32768.0*4);
}while((*pboard).place[i][j]);
t=2*((int)(rand()/32768.0*2)+1);
(*pboard).place[i][j]=t;
do
{
i=(int)(rand()/32768.0*4);
j=(int)(rand()/32768.0*4);
}while((*pboard).place[i][j]);
t=2*((int)(rand()/32768.0*2)+1);
(*pboard).place[i][j]=t;
return0;
}
//主要操作函数,调用该函数,将执行结构体中对应按键值的方向的操作,并增加分数和操作次数。
intoperate(structboard*pboard)
{
inti,j,t,shun=-1,alter=0,//alter变量是用来判断执行步骤的时候是否改变了棋局。
shun用来记录已经进行合并的值对应的I或J,用来避免该值再次合并
randget(structboard*),
calczeronum(structboard*);
switch((*pboard).dtk)
{
caseUP:
{
for(j=0;j<4;++j,shun=-1)
{
for(i=1;i<4;++i)
{
if((*pboard).place[i][j]!
=0)
{
for(t=i-1;t>=0;--t)
{
if((*pboard).place[t][j]!
=0)
{
if((*pboard).place[t][j]==(*pboard).place[i][j]&&shun!
=t)
{
(*pboard).num+=(*pboard).place[t][j]*=2;
(*pboard).place[i][j]=0;
shun=t;
alter=1;
}
elseif(t+1!
=i)
{
(*pboard).place[t+1][j]=(*pboard).place[i][j];
(*pboard).place[i][j]=0;
alter=1;
}
break;
}
elseif(t==0)
{
(*pboard).place[t][j]=(*pboard).place[i][j];
(*pboard).place[i][j]=0;
alter=1;
break;
}
}
}
}
}
}break;
caseDOWN:
{
for(j=0;j<4;++j,shun=-1)
{
for(i=2;i>=0;--i)
{
if((*pboard).place[i][j]!
=0)
{
for(t=i+1;t<4;++t)
{
if((*pboard).place[t][j]!
=0)
{
if((*pboard).place[t][j]==(*pboard).place[i][j]&&shun!
=t)
{
(*pboard).num+=(*pboard).place[t][j]*=2;
(*pboard).place[i][j]=0;
shun=t;
alter=1;
}
elseif(t-1!
=i)
{
(*pboard).place[t-1][j]=(*pboard).place[i][j];
(*pboard).place[i][j]=0;
alter=1;
}
break;
}
elseif(t==3)
{
(*pboard).place[t][j]=(*pboard).place[i][j];
(*pboard).place[i][j]=0;
alter=1;
break;
}
}
}
}
}
}break;
caseRIGHT:
{
for(i=0;i<4;++i,shun=-1)
{
for(j=2;j>=0;--j)
{
if((*pboard).place[i][j]!
=0)
{
for(t=j+1;t<4;++t)
{
if((*pboard).place[i][t]!
=0)
{
if((*pboard).place[i][t]==(*pboard).place[i][j]&&shun!
=t)
{
(*pboard).num+=(*pboard).place[i][t]*=2;
(*pboard).place[i][j]=0;
shun=t;
alter=1;
}
elseif(t-1!
=j)
{
(*pboard).place[i][t-1]=(*pboard).place[i][j];
(*pboard).place[i][j]=0;
alter=1;
}
break;
}
elseif(t==3)
{
(*pboard).place[i][t]=(*pboard).place[i][j];
(*pboard).place[i][j]=0;
alter=1;
break;
}
}
}
}
}
}break;
caseLEFT:
{
for(i=0;i<4;++i,shun=-1)
{
for(j=1;j<4;++j)
{
if((*pboard).place[i][j]!
=0)
{
for(t=j-1;t>=0;--t)
{
if((*pboard).place[i][t]!
=0)
{
if((*pboard).place[i][t]==(*pboard).place[i][j]&&shun!
=t)
{
(*pboard).num+=(*pboard).place[i][t]*=2;
(*pboard).place[i][j]=0;
shun=t;
alter=1;
}
elseif(t+1!
=j)
{
(*pboard).place[i][t+1]=(*pboard).place[i][j];
(*pboard).place[i][j]=0;
alter=1;
}
break;
}
elseif(t==0)
{
(*pboard).place[i][t]=(*pboard).place[i][j];
(*pboard).place[i][j]=0;
alter=1;
break;
}
}
}
}
}
}break;
default:
return-1;
}
if(alter)
{
++(*pboard).stepn;
returnrandget(pboard);
}
return1;
}
//计算place数组中有多少个零,即多少个空位,返回值等同于board1.zeronum
intcalczeronum(structboard*pboard)
{
inti,j;
for((*pboard).zeronum=0,i=0;i<4;++i)
for(j=0;j<4;++j)
if((*pboard).place[i][j]==0)
++(*pboard).zeronum;
return(*pboard).zeronum;
}
//新数生成函数。
每次有效执行操作函数时,进行新的数生成
intrandget(structboard*pboard)
{
inti,j,t,x,
ifover(structboard*);
calczeronum(pboard);
t=(int)(rand()/32768.0*(*pboard).zeronum)+1;
for(x=0,i=0;i<4;++i)
for(j=0;j<4;++j)
if((*pboard).place[i][j]==0)
if(++x==t)
{
(*pboard).place[i][j]=2*((int)(rand()/32768.0*2)+1);
if(!
(--(*pboard).zeronum)||(*pboard).zeronum<=0)
ifover(pboard);
return0;
}
return-1;
}
//用来判断游戏是否结束,当board.zeronum的值为零的时候,调用该函数进行判断。
游戏结束时返回1,over值为1,否则返回可操作方向值,DOWN或RIGHT
intifover(structboard*pboard)
{
inti;
for(i=0;i<4;++i)
{
if((*pboard).place[i][0]==(*pboard).place[i][1]||(*pboard).place[i][1]==(*pboard).place[i][2]||(*pboard).place[i][2]==(*pboard).place[i][3])
{
(*pboard).over=0;
returnDOWN;
}
if((*pboard).place[0][i]==(*pboard).place[1][i]||(*pboard).place[1][i]==(*pboard).place[2][i]||(*pboard).place[2][i]==(*pboard).place[3][i])
{
(*pboard).over=0;
returnRIGHT;
}
}
return(*pboard).over=1;
}
六