C++小游戏设计——孔明棋

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

计算机实习报告
姓名: XXX
班级: xxxxxxxxx
学号: xxxxxxxxx
小班序号:xx
指导老师:XXX
题目:“孔明棋”游戏设计
邮箱:XXXXXXXXXXX@XXXX
题目《“孔明棋”游戏设计》实验报告一.功能说明
1.1总体功能说明
“孔明棋”游戏的设计,是基于一种古老的同名单人桌面游戏,本程序实现了孔明棋的游戏功能,并提供撤销、重新开始、背景音乐、步数统计、游戏成绩记录等辅助功能,基本满足玩家的游戏需要。

在基本游戏功能方面,赋予棋盘上的33个点有子/无子两种状态,及有子/无子/选定3种状态。

提供了移动光标、选定棋子、移动棋子、自动检测游戏是否结束等功能。

在辅助功能上,本游戏能够重新开始。

同时,设计了步数统计系统,连续移动计一步,撤销也计一步,给玩家探索更简洁的方法提供必要资料。

游戏成绩记录系统可以记录并显示游戏历史上最好的10次成绩。

撤销功能方面,预先申请了足够的空间,可以存储游戏进程中的每一步,玩家可以任意改变操作。

在主菜单中,可以控制背景音乐的开关;游戏各个界面与主菜单之间也可以任意切换,玩家可以随时查阅规则和历史记录。

1.2用户界面
1、主菜单
进入游戏后的界面。

在这个菜单下,通过不同的选项,分别进入游戏,查看游戏规则,开/关背景音乐和查看历史记录,或退出游戏。

2、游戏界面
游戏主要界面。

界面左侧是游戏进行的棋盘,右侧是操作说明。

玩家将在这个界面下进行游戏,在实现基础游戏功能的同时,本游戏还提供了撤销、重新开始及返回主菜单的附加功能,方便玩家进行游戏。

3、游戏胜利界面
玩家在一局游戏胜利,并且成绩能够排进历时前十名的话,就会出现以上界面,要求玩家输入由3个字母的姓名。

之后,将自动转到历史记录界面。

4、游戏失败界面
游戏失败后的界面。

询问玩家是否再次游戏。

5、规则说明
对游戏基本情况及规则的说明,按回车键可返回主菜单。

6、历史记录
该界面将显示游戏历史上前十名的姓名与成绩。

初始条件下,前十名姓名均默认为aaa,成绩均默认为100步。

1.3使用方法
在主菜单下,通过数字键选择下一步操作,4可以选择开/关背景音乐,查看游戏规则后或历史记录后,可按提示返回主菜单。

游戏过程中,W、A、S、D分别控制上下左右;空格为选定/取消选定;退格为撤销上一步操作;M为返回菜单;回车为重新开始。

实心圆为放有棋子的位置,空心圆为未放棋子的位置。

通过上下左右移动光标。

移动棋子时,首先用空格选中一个棋子,然后用方向键选择移动方向。

移动过后按空格键取消选定(实际上任意键均可),之后继续游戏。

错误的操作不会产生任何效果。

当棋盘上无子可走是,游戏会自动结束,并判定玩家是否取得胜利。

创造记录后,须输入3个字母的名字。

二.程序设计说明
2.1 总体设计框架
2.2 关键算法描述
算法1:棋盘初始化
void point::Point(int a,int b)
{
x=a;
y=b;
wColors[0]=BACKGROUND_GREEN|FOREGROUND_RED|FOREGROUND_GRE EN|FOREGROUND_INTENSITY;
wColors[1]=BACKGROUND_GREEN|FOREGROUND_RED|FOREGROUND_GREEN|FORE GROUND_BLUE|FOREGROUND_INTENSITY;
handle=initiate();
st=unavaliable;
if ((a>=2&&a<=4)||(b>=2&&b<=4))
st=on;
if (a==3&&b==3)
st=off; //状态定义
revert(); //棋盘初始状态绘制
}//对棋盘上每个点的初始化定义
void point::revert()
{
if(st==on)
textout(handle,(3*x+10),(6+y),wColors,1,"●");
if(st==off)
textout(handle,(3*x+10),(y+6),wColors,1,"○");
}// 显示点的状态
主函数中:
for(int i=0;i<=6;i++)
{
for(int j=0;j<=6;j++)
pt[i][j].Point(i,j);
} //棋盘初始化
输入:该点在棋盘上的坐标值(int a,int b),输出:无。

作用:在设置的点类下,将棋盘上每个点设置为一个对象。

初始化棋盘上的一点时,枚举类型变量st表示该点状态(有子/无子/不可用)。

主函数中通过循环,构建49格的棋盘,又通过将四角的16格设为不可用,绘制出“井”字形的33格棋盘。

算法2;移动棋子
//移动棋子
if(temp==32)
{
int a=pt[row][col].decide();
if(a==1)//判断选中点是否有子
{
int sp=0;
st: pt[row][col].select();
temp=getch(); //读取下一步操作
r[n]=row;
c[n]=col;
t[n]=temp;
n+=1;
//操作记录,撤销功能使用
int a1,a2;
if(temp==119||temp==87)
{
if((col-2)>=0)
{
a1=pt[row][col-1].decide();
a2=pt[row][col-2].decide();
if(a1==1&&a2==2)
{
pt[row][col].sw();
pt[row][col-1].sw();
pt[row][col-2].sw();
pt[row][col].revert();
pt[row][col-1].revert();
pt[row][col-2].revert();
col-=2;
sp++; //计步器判定量
del++; //能否撤销的判定量
goto st;
}
}
pt[row][col].active();
if(sp>=0) step++;
n-=1;
}
……
……
}
else
pt[row][col].active();
}
输入:移动方向。

输入:无。

作用:在游戏中,按下空格选中棋子后,进入这部分代码。

整型变量row、col分别代表横纵坐标。

首先判定光标所在点是否有子,如没有子,系统将自动跳过,等待下一条指令。

如有子,须输入移动方向,之后系统判定指令是否符合要求,如符合要求,首先通过point.sw()函数改变该方向上连续3个点的st变量,然后调用point.revert()函数重绘这些点,并等待下一次输入移动方向。

在玩家看来,即完成了移动。

完成移动后,需输入一次,跳出goto语句。

移动中,输入的移动方向有误,也会跳出。

移动之前会记录移动前的光标位置及移动方向,用于撤销。

变量del、n的作用在撤销部分介绍。

整型变量step用于记录移动步数,连续移动计一步。

以上代码,只包括向上移动部分,向另外3个方向移动的代码类似,未粘贴。

算法3:移动光标
else if
(temp==119||temp==87||temp==115||temp==83||temp==
97||temp==65||temp==100||temp==68)
{
if((temp==119||temp==87)&&col>=1)
{
int k=pt[row][col-1].decide();
if(k!=0)
col-=1;
}
……
……
}
void point::active()
{
while(1)
{
textout(handle,(3*x+10),(6+y),&wColors[1],1,"●");
Sleep(180);
textout(handle,(3*x+10),(6+y),&wColors[1],1,"○");
Sleep(180);
if(kbhit()==1)
break;
}
int point::decide()
{
if(st==on)
return 1;
else if(st==off)
return 2;
else if(st==unavaliable)
return 0;
else
{
system("cls");
cout<<"程序出错,请重启游戏!!!";
}
}//判断点上是否仍有棋子
输入:移动方向;输出:无。

作用:在未选中棋子的情况下按方向键w/a/s/d,进入这部分代码。

光标所在的位置,
在point.active()函数作用下呈闪烁状态。

移动光标时,首先通过point.decide()函数判定是否越界,如移动到的位置仍在33个可用格内,则移动光标到该位置。

算法4:
//撤销
else if(temp==8)
{
del--;
if(del<=0)
goto once;
if(n>=1&&n<=35)
n-=1;
col=c[n];
row=r[n];
temp=t[n];
if(temp==119||temp==87)
{
pt[row][col].sw();
pt[row][col-1].sw();
pt[row][col-2].sw();
pt[row][col].revert();
pt[row][col-1].revert();
pt[row][col-2].revert();
step++;
pt[row][col].active();
}
……
……
}
输入:退格;输出:无。

未选中棋子时,按退格键转入这部分代码。

在程序开始时,申请了r[35],c[35],t[35] 三个整形数组用于存储操作。

整型变量del,每移动一次加1,撤销一次减1.,用于判定是否可执行撤消操作。

整形变量n,用于记录操作的存储位置,撤消操作与移动操作类似。

算法5:游戏结束判定
for(i=0;i<=6;i++)
{
for(int j=0;j<=6;j++)
{
if(pt[i][j].decide()==1)
{
if(i-2>=0)
if(pt[i-1][j].decide()==1)
if(pt[i-2][j].decide()==2)
goto once;
if(i+2<=6)
if(pt[i+1][j].decide()==1)
if(pt[i+2][j].decide()==2)
goto once;
if(j-2<=0)
if(pt[i][j-1].decide()==1)
if(pt[i][j-2].decide()==2)
goto once;
if(j+2<=6)
if(pt[i][j+1].decide()==1)
if(pt[i][j+2].decide()==2)
goto once;
}
}
}
输入:无;输出:无。

作用:每步结束后判定,当棋盘上不存在可以移动的子时,游戏结束。

算法6:游戏获胜判定
int mark=0;
for(i=0;i<=6;i++)
{
for(int j=0;j<=6;j++)
{
mark+=pt[i][j].decide();
}
}
if(mark==65)
{
……
}
else
{
……
}
输入:无;输出:无。

作用:游戏结束后,计算棋盘上的子数,point.decide()的返回值,有子为1,无子为2,不可用为0。

获胜时,所有返回值的和应为65.,以此为标准判定。

算法7:记录判定
FILE *fp;
char ch[10][4];
int stp[10];
if((fp=fopen("save","r"))==NULL)
{
fp=fopen("save","w");
for(int g=0;g<=9;g++)
{
strcpy(ch[g],"aaa");
stp[g]=100;
fwrite(&ch[g],4,1,fp);
}
fwrite(stp,4,10,fp);
fclose(fp);
fp=fopen("save","r");
}
fread(ch,4,10,fp);
fread(stp,4,10,fp);
fclose(fp);
if(step>=stp[9]) //判断是否创造纪录
……
else
……
输入:step;输出:无。

作用:读取save文件中的记录,与本次游戏的step对比,判断是否创造纪录。

算法7:更新记录
for(int g=8;g>=0;g--)
{
if(step>=stp[g])
{
for(int v=9;v>=g+2;v--)
stp[v]=stp[v-1];
stp[g+1]=step;
cout<<"恭喜您创造了记录,请输入您的名字(请输入3个字母):"<<endl;
getchar();
for(int f=0;f<=2;f++)
ch[g+1][f]=getchar();
break;
}
else if(g==0)
{
for(int v=9;v>=1;v--)
stp[v]=stp[v-1];
stp[0]=step;
cout<<"恭喜您创造了记录,请输入您的名字(请输入3个字母):"<<endl;
getchar();
for(int f=0;f<=2;f++)
ch[g][f]=getchar();
}
}
fp=fopen("save","w");
fwrite(ch,4,10,fp);
fwrite(stp,4,10,fp);
fclose(fp);
goto record;
输入:step、stp数组、3个字母的名字;输出:新的“save”文件
作用:将step与stp数组(从旧“save”文件中读出)逐个对比,插入相应位置,然后
从键盘输入长度为3个字母的名字,再将新的记录输出到“save”文件。

2.3 程序设计的难点和关键点
关键点:光标的移动,棋子的移动及在控制台上的表示,结束判定。

难点:撤销操作中应读取哪个记录的判定;游戏记录的生成和读写。

2.4 调试的方法
1、系统崩溃:反复运行程序,推测问题发生点。

在推测的地点设置断点,按F10开始调试,再按F5运行至断点处,然后逐步调试,观察变量变化,找出bug。

2、游戏结束后,胜利判定失败:在判定处设置断点,按F10开始调试,再按F5运行至断点处,然后逐步调试,观察变量变化,找出bug。

2.5 程序性能评价
运行效果
优点:游戏功能基本完善,提供撤销、重新开始、步数记录、成绩排名等功能,游戏结束自动判定,满足玩家需求;程序设置两级菜单,在主菜单与各子菜单之间可以自由切换;提供背景音乐,并且可以开关;程序稳定,基本不会在游戏过程中出现bug。

缺点:游戏结束判定偏慢,需要跳出选定状态才能进行;游戏结束后,因结束自动判定,无法撤销,对最后一步走错的玩家不够友善;游戏未设置存档功能;在游戏过程中无法查看步数。

程序设计
优点:设计点类,用对象表示棋盘上点,体现了面向对象的思想;采用了输入输出流,可以读写游戏历史前10位的成绩记录;使用goto函数,增强程序灵活性;程序游戏部分健壮性好,不易出现问题。

缺点:除类外,程序中只有一个main函数,未设置其它函数,使main函数过于冗长;过多使用了if…else和for语句,其他结构使用不够充分;程序略显繁复,运行速度有待提高。

三.心得体会
在小学期近3周的工作之后,我亲手编制的第一个游戏终于基本成型了。

欣喜之余,在本次实习报告的最后,写下我这段时间的一点体会。

任务开始之初,对自己编写程序还是十分没有把握的。

然而,只是凭借半年学习积累的知识,老师提供的和从网上查阅的一些函数,在一番努力之后,还是成功的完成了这个任务,而且基本还算顺利。

可见,C++的基本知识还是相对简单,真正庞杂的是在编程过程中需要随时查阅的各种函数。

从编写的过程来看,程序主体的构建并没有花太多时间,反而是后期的调试和修改占用了近一半的时间,很多附加功能都是在后期逐个添加进去的。

由此,了解了设计初期详细规划的重要性,添加功能时,读原有代码,添加控制变量,修改代码耗费的时间远比一开始就编写进去要多得多。

再者,后期的bug大多是产生于数据越界,或缺少控制量等原因,同样体现了初期设计完善之必要,也表现了思路完善的重要性。

总之,本次的变成体验是一次十分宝贵的经历,提高了我编程能力,更重要的是使我加深了对C++编程过程的理解,增加了实践经验。

相关文档
最新文档