德州学院信息管理学院
课程设计报告
实习名称 自主学习能力 设计题目 五子棋小游戏 实习时间 2015.04.01--2014.04.30 专业班级 14级计算机科学与技术 指导老师 曹金凤 教学单位
小组分工情况:
二〇一四年五月二十五日
i
目 录
1 实习目的 ................................................................ 2 2 需求分析 ................................................................ 2 3 概要设计 ................................................................ 2 3.1 游戏背景 ............................................................ 2 3.2 游戏玩法 ............................................................ 3 3.3 程序需求分析 ........................................................ 3 3.4 开发平台 ............................................................ 3 3.5程序流程设计 ........................................................ 4 4 棋盘与棋子的生成 ........................................................ 5 4.1引言 ................................................................ 5 4.2 程序语句 .......................................... 错误!未定义书签。 5 棋子移动与落子 .......................................................... 6 5.1引言 ................................................................ 6 5.2程序语句 ............................................................ 6 6 胜负判断 ............................................................... 16 6.1引言 .............................................. 错误!未定义书签。 6.2程序设计 ........................................................... 17 7 调整改进 ............................................................... 18 7.1引言 ............................................................... 18 7.2程序功能及调整 ..................................................... 18 7.3总程序语句 ......................................................... 19 8 总结 ................................................................... 28 参考文献: ............................................................... 29
ii
五子棋小游戏的设计与实现
1 实习目的
(1)熟练的运用计算机语言,培养了对计算机编程的热爱程度. (2)学会怎样用c语言做一个完整的系统。 (3)掌握c语言的编辑,链接,运行等环节。
(4)掌握c语言中链表的建立,插入,删除,保存节点。 (5)熟练掌握for while do-while循环语句的使用。
(6)熟练掌握函数的定义、说明、参数传递及嵌套和递归调用方法。 (7)提高遇到困难解决困难的能力。 (8)提高书写代码的速度与正确率。
(9)独立实践,将课本上的理论知识和实际有机的结合起来,锻炼学生的分析解决实际问题的能力,提高学生适应实际,实践编程的能力。
2 需求分析
目前,随着计算机网络的的发展,PK已经成为现在人生活的一部分,人们 以不同的方式通过网络来娱乐,休闲。以计算机技术和网络技术为核心的现代网络技术已经在现实生活和生产中得到了广泛的使用,休闲类网络游戏集趣味性,娱乐性,互动性和益智性于一体,已经成为多数人群的休闲方式,也为多数人所喜好。当然,为了满足没有网络同样能娱乐的要求,许多小游戏做成了单机和网络的双功能。
3 概要设计
3.1 游戏背景
五子棋不仅能增强思维能力,提高智力,而且富含哲理,有助于修身养性。五子棋既有现代休闲的明显特征“短、平、快”,又有古典哲学的高深学问“阴阳易理”;它既有简单易学的特性,为人民群众所喜闻乐见,又有深奥的技巧和高水平的国际性比赛;它的棋文化源渊流长,具有东方的神秘和西方的直观;既
3
有“场”的概念,亦有“点”的连接。它是中西文化的交流点,是古今哲理的结晶。
3.2 游戏玩法
五子棋是一种两人对弈的纯策略 型棋类游戏,五子棋棋子分为黑白两色,棋盘为19×19,棋子放置于棋盘线交叉点上或网格中。两人对局,各执一色,轮流下一子,先将横、竖或斜线的5个同色棋子连成不间断的一排者为胜。
3.3程序需求分析
根据功能需求,将程序分为图形显示、玩家控制、胜负判断和系统帮助四个模块,以下分析各模块的需求。
图形显示模块:程序开始运行时,给出欢迎界面;游戏开始后要求生成19×19的棋盘图像,并在棋盘上方提示 当前落子方棋子颜色,游戏进行过程中,要求实时显示棋盘上已落下的棋子;分出胜负后,要求给出游戏结束画面。 玩家控制模块:程序开始时,需玩家确定而后开始游戏;游戏过程中,两个玩家通过不同的按键移动光标,选择落子;游戏结束时,有玩家选择是否开始新棋局。
胜负判断模块:实时监测棋盘上棋子,一旦某一色棋子出现五子连线,终止游戏程序,弹出该色玩家胜出界面。
系统帮助模块:弹出窗口,窗口中 显示帮助信息,包括棋子移动与落子按 键介绍,获胜方式等。
除以上主要模块之外,程序中还可以添加其他辅助程序,如中途退出等。程序的关键在于胜负判断模块,该模块的设计直接关系到程序的运行速率和运行结果的正确与否。
3.4 开发平台
系统: Windows 7 旗舰版(64位)
处理器: AMD A8-5545M APU with Radeon(tm) HD Graphics 1.70GHz
4
内存: 4.00 GB
程序开发软件:Microsoft Visual C++ 6.0 文档编写:Microsoft Word 2010
3.5 程序流程设计
根据程序需求分析结果,可以得出程序的总体结构图如图1:
图1 程序总体流程图图
程序总体流程图如图2:
5
图2 程序总体设计图
4.棋盘与棋子的生成
4.1引言
根据五子棋的基本规则,棋盘采用19×19方格棋盘,棋子为黑白二色圆形棋子;游戏进行过程中棋盘始终显示,落子后棋子在落子处始终显示;棋盘在程序结束时消失,已落下的棋子在 程序结束时或开始新游戏是消失。
4.2程序语句
棋盘的显示由游戏开始与结束部分控制,棋子的显示与保留由玩家操控部分决定。
board() /*画棋盘*/ { setfillstyle(1,6); bar(120,50,520,450); setfillstyle(1,14); bar(540,50,620,150); bar(20,50,100,150); for(k=0;k
{moveto(140+20*k,70);linerel(0,360);
moveto(140,70+20*k);linerel(360,0); }
moveto(240,170); setcolor(5); settextstyle(3,0,4); outtextxy(50,60,"P1"); outtextxy(560,60,"P2"); }
white() /*画白棋*/ {
setcolor(7);
setfillstyle(1,7);
circle(getx(),gety(),9); fill(getx(),gety(),7); }
black() /*画黑棋*/ {
6
setcolor(0);
setfillstyle(1,0);
circle(getx(),gety(),9); fill(getx(),gety(),0); }
5棋子移动与落子
5.1引言
棋子的移动与落子有键盘上按键控制,本程序选取1P按键为W、S、A、D和空格键,2P按键为↑、↓、←、→和回车键,分别代表上移、下移、左移、右移光标和落子。在光标移动的过程中,光标按照玩家按键移动;在玩家按下落子按键后,程序自动调用棋子显示子程序和判断胜负子程序。1P、2P的落子后,程序会为落子处的数组元素赋一个特定值,用于判定胜负。
5.2程序语句
void p1move() /*玩家1的移动*/ {
switch(bioskey(0)) {
int sum=0;
case ESC: {closegraph(); exit(0);}/*如果按键为ESC就退出游戏 */
case SP:/*落子*/ if(a[X][Y]==6) {
p1del(); p2turn();
7
a[X][Y]=0; sum++; white(); p2move(); if(sum>=5) win(); }
else p1move();
case A: /*向左移*/ if(a[X][Y]==0) {
if(getx()==140)
moveto(520,gety()); moverel(-20,0); white(); }
else if(a[X][Y]==1) {
if(getx()==140) moveto(520,gety()); black();moverel(-20,0); white(); } else {
if(getx()==140)
8
moveto(520,gety()); moverel(-20,0); white(); } p1move(); case D: /*向右移*/ if(a[X][Y]==0) {
if(getx()==500) moveto(120,gety()); moverel(20,0); white();} else if(a[X][Y]==1) {
if(getx()==500) moveto(120,gety()); black();moverel(20,0); white(); } else {
if(getx()==500) moveto(120,gety()) ; moverel(20,0); white(); }
9
p1move(); case W: /*向上移*/ if(a[X][Y]==0) {
if(gety()==70) moveto(getx(),450); moverel(0,-20); white(); }
else if(a[X][Y]==1) {
if(gety()==70) moveto(getx(),450); black(); moverel(0,-20); white(); } else {
if(gety()==70) moveto(getx(),450); moverel(0,-20); white(); } p1move();
case S: /*向下移*/
10
if(a[X][Y]==0) {
if(gety()==430) moveto(getx(),50); moverel(0,20); white(); }
else if(a[X][Y]==1) {
if(gety()==430) moveto(getx(),50); black(); moverel(0,20); white(); } else {
if(gety()==430) moveto(getx(),50); moverel(0,20); white(); } p1move(); default: p1move(); }
11
}
void p2move() /*玩家2的移动*/ {
switch(bioskey(0)) /*如果按键为ESC就退出游戏*/ {
int sum=0;
case ESC: {closegraph(); exit(0);} case ENTER: /*落子*/ if(a[X][Y]==6) {
p2del(); p1turn(); a[X][Y]=1; sum++; black(); p1move(); if(sum>=5) win(); } else p2move(); case LEFT: /*向左移*/ if(a[X][Y]==1) {
if(getx()==140) moveto(520, gety());
12
moverel(-20,0); black(); }
else if(a[X][Y]==0) {
if(getx()==140) moveto(520,gety()); if(getx()==140) moveto(500,gety()); white(); moverel(-20,0); black(); } else {
if(getx()==140) moveto(520,gety()); moverel(-20,0); black(); } p2move();
case RIGHT: /*向右移*/ if(a[X][Y]==1) {
if(getx()==500) moveto(120,gety());
13
moverel(20,0); black(); }
else if(a[X][Y]==0) {
if(getx()==500) moveto(120,gety()); white(); moverel(20,0); black(); } else {
if(getx()==500) moveto(120,gety()); moverel(20,0); black(); } p2move();
case UP: /*向上移*/ if(a[X][Y]==1) {
if(gety()==70) moveto(getx(),450); moverel(0,-20); black();
14
}
else if(a[X][Y]==0) {
if(gety()==70) moveto(getx(),450); white(); moverel(0,-20); black(); } else {
if(gety()==70) moveto(getx(),450); moverel(0,-20); black(); } p2move();
case DOWN: /*向下移*/ if(a[X][Y]==1) {
if(gety()==430) moveto(getx(),50); moverel(0,20); black(); }
else if(a[X][Y]==0)
15
{
if(gety()==430) moveto(getx(),50); white(); moverel(0,20); black(); } else {
if(gety()==430) moveto(getx(),50); moverel(0,20); black(); } p2move(); default: p2move(); } }
6胜负判断
6.1引言
胜负判断模块是程序的关键,该模块的设计直接关系到程序的运行速率和运行结果的正确与否。
本函数根据每次落子的位置,分别向上、下、左、右、左上、左下、右上、右下八个 方向判断是否有相同颜色的棋子连成五子,如果成立,游戏就结束,并显示提示信息,否则继续落子。
16
以下简析本程序流程:如表1所示,令当前落子点坐标为(X,Y),表中 i=X-4, j=Y-4,由获胜条件可以知,通过判断(X,Y)上、下、左、右、斜上、斜下八个方向上是否有连续的5个子即可得出是否获胜结果。在游戏开始时,将棋盘初始化,即将棋盘抽象为一个19*19的数组,数组中每个元素设为某一指定初始值(如8)。1P落子时,将数组内相应坐标处元素赋值为0;2P落子时,将数组内相应坐标处元素赋值为1。当(X,Y) 上、下、左、右、斜上、斜下八个方向某5个连续的子所对应的数组中元素之和等于0时,1P获胜;当(X,Y) 上、下、左、右、斜上、斜下八个方向某5个连续的子所对应的数组中元素之和等于5时,2P获胜。棋盘上的所有格子都被占满时,必有181个1P棋子和180个2P棋子,此时对应数组中所有项之和为180,并且游戏过程中对应数组中所有项之和只可能在这种状况下为180,所以可以用这一条件判断是否和棋。
表1 胜负判断表
为减少程序的运算,还可以将某些特殊情况排除在外。当落子数不大于8时,既不用判断胜负,也不用判断和棋与否,这部分功能在第二章移动与落子程序中实现。此外,还可以通过对落子次数的统计判断是否满足和棋条件,从而减少大量运算,即当判断177次胜负后出现和棋。
6.2程序设计
void win() /*判断输赢*/ {
17
int sum1,sum2,sum3,sum4,sum=1,n,i,j; for(i=X-4,j=Y-4,n=0;i
sum1=a[i][Y]+a[i+1][Y]+a[i+2][Y]+a[i+3][Y]+a[i+4][Y];
sum2=a[i][j]+a[i+1][j+1]+a[i+2][j+2]+a[i+3][j+3]+a[i+4][j+4]; sum3=a[X][j]+a[X][j+1]+a[X][j+2]+a[X][j+3]+a[X][j+4];
sum4=a[i][j+8+n]+a[i+1][j+7+n]+a[i+2][j+6+n]+a[i+3][j+5+n]+a[i+4][j+4+n]; if(sum1==5||sum2==5||sum3==5||sum4==5) p2win(); if
(sum1==0||sum2==0||sum3==0||sum4==0) p1win(); } sum++ if(sum==177) heqi(); }
7调整改进
7.1引言
前6章分别论述了五子棋C语言程序中的四大主要模块,但要生成可执行的程序,则还需将这些模块有机地结合起来。在结合的过程中,需要综合运 用函数调用、函数间书序传递和全局变量等知识。
18
7.2程序功能及调整
为满足实际操作需求,增加程序的兼容性与稳定性,在编写可执行程序的过程中,必须对原有各功能模块进行整合并添加或调整部分功能。
为方便玩家使用本程序,在程序中增加了“悔棋”、“认输”和“退出”功能,玩家可以通过在游戏构成中输入相关指令实现这些功能,具体语句见附录。
为增强程序的兼容性和实用性,在最终的可执行程序中还对原有模块进行了其他修改。
在调试的过程中,发现bios.h 和graphics.h两个头文件只有在Turbo C的编译环境下才能顺利执行,因此,使用bios.h和graphics.h的程序兼容性不高,因此,舍弃使用这两个头文件的图像显示模块,转而使用具有较高兼容性的全屏打印刷新显示块。后者虽然在视觉效果上不如前者,然而它可以在任何Windows系统下工作,而这比视觉效果重要得多。
在调试过程中,发现每当1P在最外圈落子时,系统即可弹出1P获胜的结果,这是由于win函数中是通过对落子点及其周围的若干点求和来判断是否获胜的。当1P在最外圈落子时,棋盘外的点被程序当做0处理,加上落子时被赋值为0的一点,正好满足1P获胜的条件,故而引发错误。改进方法:将用于判断输赢的数组a由原来的19*19改为21*21,并将第0、20行及第0、20列中所有元素赋值为6;再将被这四组元素包围的一个19*19的区间对应到棋盘上的19*19格,即可解决原有问题。
在调试的过程中,还发现原有模块中的按键操作过于复杂,综合兼容性考虑,舍弃原有的光标操作模式,改用输入坐标的操作模式,这样做从某种程度上降低了程序的可操作性,但提高了程序的可实现性与兼容性。
7.3总程序语句
/*函数、变量定义*/
#include #include #include #include
19
#define N 19 int win(int m, int l); void printState(); p1win(); p2win(); heqi(); void help(); int i,j,k,size=N; int isBlack=1; char state[N][N]; int a[N+2][N+2]; char x,y,temp[10]; char c; int z;
/*初始化及指令输入*/
void startGame() {
int m,n,w; for(i=0;i
for(j=0;j
state[i][j]='_'; a[i][j]=6;
20
}
}
printState();
while(1)
{
printf("\n\t请%s方下子:",isBlack?"黑":"白");
fflush(stdin);
scanf("%s",temp);
if(!strcmp(strupr(temp),"OUT"))
{
system("cls");
return;
}
/*悔棋 */
if(!strcmp(temp,"BACK"))
{
i=x-'A';
j=y-'A';
state[i][j]='_';
printState();
isBlack=!isBlack;
continue;
}
if(!strcmp(temp,"LOSE"))
21
/*认输*/
{
printf("\n\t%s方认输,%s方胜!\n\n",isBlack?"黑":"白",isBlack?"白":"黑"); return;
}
x=temp[0];
y=temp[1];
/*避免下面相减的数组越界。*/
if(x'S'||y'S')
{
printf("\t输入有误,请输入属于或正确的口令。\n");
continue;
}
i=x-'A';
j=y-'A';
if(state[i][j]!='_')
{
printf("\t提示:该位置已经有子,请重新指定坐标!");
continue;
}
c=isBlack?'1':'2';
z=isBlack? 0:1;
22
state[i][j]=c;
a[i+1][j+1]=z;
m=i+1;
n=j+1;
w=win(m,n);
if(!w)
{
printState();
isBlack=!isBlack;
}
else
{
return;
}
}
}
/*判断输赢*/
int win(int m, int l)
{
int
sum1,sum2,sum3,sum4,sum=1,n,i,j,X,Y,w;
w=0;
X=m;
Y=l;
23
for(i=X-4,j=Y-4,n=0;i
{
sum1=a[i][Y]+a[i+1][Y]+a[i+2][Y]+a[i+3][Y]+a[i+4][Y];
sum2=a[i][j]+a[i+1][j+1]+a[i+2][j+2]+a[i+3][j+3]+a[i+4][j+4];
sum3=a[X][j]+a[X][j+1]+a[X][j+2]+a[X][j+3]+a[X][j+4];
sum4=a[i][j+8+n]+a[i+1][j+7+n]+a[i+2][j+6+n]+a[i+3][j+5+n]+a[i+4][j+4+n];
if(sum1==5||sum2==5||sum3==5||sum4==5)
{
p2win();
w=1;
}
if
(sum1==0||sum2==0||sum3==0||sum4==0)
{
p1win();
w=1;
}
}
sum1=0;
sum2=0;
sum3=0;
sum4=0;
sum++;
24
if(sum==177)
{
heqi();
w=1;
}
return w;
}
/*和棋界面*/
heqi()
{
printf("和棋");
return;
}
/*玩家1获胜界面*/
p1win()
25
{
printf("玩家1获胜");
return;
}
/*玩家2获胜界面*/
p2win()
{
printf("玩家2获胜");
return;
}
/*帮助*/
void help()
{
system("cls");
printf("\t本程序采用19*19的游戏格式\n\n");
printf("\t输入格子的坐标下子: 先横坐标后纵坐标。比如输入:GG\n\n");
printf("\t输入out(退回主菜单)、back(悔棋)、lose(认输)\n\n");
}
26
/*主函数*/
int main()
{
system("color f1");
while(1)
{
printf("\n\t-----C Programming Language课程作业:五子棋-----\n\n");
printf("\t\t 1.开始游戏\n");
printf("\t\t 2.帮助\n");
printf("\t\t 3.退出\n");
printf("\n\t请选择:");
L:k=scanf("%d",&i);
switch(i)
{
case 1: startGame(); break;
case 2: help(); break;
case 3: return 0;
default:printf("\t 无此选项\n");break;
}
}
}
/*显示、刷屏*/
void printState()
27
{
char p='A';
system("cls");
printf("\t棋盘如下:\n\n");
printf("\t ");
for(i=0;i
{
printf("%c ",p+i);
}
printf("\n\t");
for(i=0;i
{
printf("%c ",p+i);
for(j=0;j
{
printf("%c ",state[i][j]);
}
printf("%c \n\t",p+i);
}
printf(" ");
for(i=0;i
{
printf("%c ",p+i);
}
printf("\n");
}
28
8 总结
C语言课程设计时一次对我们c语言学习的综合检验,它要求我们将所学的c语言代码进行综合运用,设计出一个简单的系统,这不仅是对我们基础知识的检验,还考验我们的动手动脑以及团队协作能力,在这一年学习中要将这些基础知识掌握已经不容易了,在这么短的时间又要做出一个系统更是一次重大的挑战,然而只有迎难而上才能收获成功,做出一个完整的系统。
回顾这次课程设计,至今我感慨颇多。很多的知识只是停留在基本的应用上,当需要结合使用时,往往出现无从入手的情况。在C语言课程设计的过程中,让我深深体会到了这点。一些细节的地方没有看清楚,或者思考妥当,就无法让系统运行,而当一系列调试后,程序能够运行。
通过对各子程序的设计与优化,本程序完成了五子棋软件的主体的设计与制作,基本达到了使用五子棋软件的核 心要求。然而程序还有一些不足之处,首先,程序在判断胜负后无法显示第五枚棋子,输入五子连环的第五个棋子坐标之后直接跳出了重新开始的界面,这是由程序的显示原理造成的;其次,程序的界面过于简陋,而且坐标输入操作也不利于玩家使用。
对于这次课程设计我很不满意,没有达到自己想要的效果,系统中还存在着许多的漏洞,在本次课程设计过程中我也发现了自己的很多缺点,比如做事不认真,粗心大意,考虑问题不够全面等。最后,谢谢老师的教导。
参考文献
[1] 五 子 棋 [EB].
http://baike.baidu.com/view/2697.htm.
[2] C语言制作五子棋[EB].
http://www.vcworld.net/news/200905/022217.html
[3] C语言五棋源代码 设计报告[EB].
http://wenku.baidu.com/view/e253a2c66137ee06eff91859.html
29
[4] C语言五子棋算法[EB].
http://www.4oa.com/Article/html/6/31/445/2005/1541 3.htm
30
注:实习成绩由指导教师或答辩小组评定出成绩,分优秀、良好、中等、及格、不及格五级,分别给小组的每个成员打分。
31
32
德州学院信息管理学院
课程设计报告
实习名称 自主学习能力 设计题目 五子棋小游戏 实习时间 2015.04.01--2014.04.30 专业班级 14级计算机科学与技术 指导老师 曹金凤 教学单位
小组分工情况:
二〇一四年五月二十五日
i
目 录
1 实习目的 ................................................................ 2 2 需求分析 ................................................................ 2 3 概要设计 ................................................................ 2 3.1 游戏背景 ............................................................ 2 3.2 游戏玩法 ............................................................ 3 3.3 程序需求分析 ........................................................ 3 3.4 开发平台 ............................................................ 3 3.5程序流程设计 ........................................................ 4 4 棋盘与棋子的生成 ........................................................ 5 4.1引言 ................................................................ 5 4.2 程序语句 .......................................... 错误!未定义书签。 5 棋子移动与落子 .......................................................... 6 5.1引言 ................................................................ 6 5.2程序语句 ............................................................ 6 6 胜负判断 ............................................................... 16 6.1引言 .............................................. 错误!未定义书签。 6.2程序设计 ........................................................... 17 7 调整改进 ............................................................... 18 7.1引言 ............................................................... 18 7.2程序功能及调整 ..................................................... 18 7.3总程序语句 ......................................................... 19 8 总结 ................................................................... 28 参考文献: ............................................................... 29
ii
五子棋小游戏的设计与实现
1 实习目的
(1)熟练的运用计算机语言,培养了对计算机编程的热爱程度. (2)学会怎样用c语言做一个完整的系统。 (3)掌握c语言的编辑,链接,运行等环节。
(4)掌握c语言中链表的建立,插入,删除,保存节点。 (5)熟练掌握for while do-while循环语句的使用。
(6)熟练掌握函数的定义、说明、参数传递及嵌套和递归调用方法。 (7)提高遇到困难解决困难的能力。 (8)提高书写代码的速度与正确率。
(9)独立实践,将课本上的理论知识和实际有机的结合起来,锻炼学生的分析解决实际问题的能力,提高学生适应实际,实践编程的能力。
2 需求分析
目前,随着计算机网络的的发展,PK已经成为现在人生活的一部分,人们 以不同的方式通过网络来娱乐,休闲。以计算机技术和网络技术为核心的现代网络技术已经在现实生活和生产中得到了广泛的使用,休闲类网络游戏集趣味性,娱乐性,互动性和益智性于一体,已经成为多数人群的休闲方式,也为多数人所喜好。当然,为了满足没有网络同样能娱乐的要求,许多小游戏做成了单机和网络的双功能。
3 概要设计
3.1 游戏背景
五子棋不仅能增强思维能力,提高智力,而且富含哲理,有助于修身养性。五子棋既有现代休闲的明显特征“短、平、快”,又有古典哲学的高深学问“阴阳易理”;它既有简单易学的特性,为人民群众所喜闻乐见,又有深奥的技巧和高水平的国际性比赛;它的棋文化源渊流长,具有东方的神秘和西方的直观;既
3
有“场”的概念,亦有“点”的连接。它是中西文化的交流点,是古今哲理的结晶。
3.2 游戏玩法
五子棋是一种两人对弈的纯策略 型棋类游戏,五子棋棋子分为黑白两色,棋盘为19×19,棋子放置于棋盘线交叉点上或网格中。两人对局,各执一色,轮流下一子,先将横、竖或斜线的5个同色棋子连成不间断的一排者为胜。
3.3程序需求分析
根据功能需求,将程序分为图形显示、玩家控制、胜负判断和系统帮助四个模块,以下分析各模块的需求。
图形显示模块:程序开始运行时,给出欢迎界面;游戏开始后要求生成19×19的棋盘图像,并在棋盘上方提示 当前落子方棋子颜色,游戏进行过程中,要求实时显示棋盘上已落下的棋子;分出胜负后,要求给出游戏结束画面。 玩家控制模块:程序开始时,需玩家确定而后开始游戏;游戏过程中,两个玩家通过不同的按键移动光标,选择落子;游戏结束时,有玩家选择是否开始新棋局。
胜负判断模块:实时监测棋盘上棋子,一旦某一色棋子出现五子连线,终止游戏程序,弹出该色玩家胜出界面。
系统帮助模块:弹出窗口,窗口中 显示帮助信息,包括棋子移动与落子按 键介绍,获胜方式等。
除以上主要模块之外,程序中还可以添加其他辅助程序,如中途退出等。程序的关键在于胜负判断模块,该模块的设计直接关系到程序的运行速率和运行结果的正确与否。
3.4 开发平台
系统: Windows 7 旗舰版(64位)
处理器: AMD A8-5545M APU with Radeon(tm) HD Graphics 1.70GHz
4
内存: 4.00 GB
程序开发软件:Microsoft Visual C++ 6.0 文档编写:Microsoft Word 2010
3.5 程序流程设计
根据程序需求分析结果,可以得出程序的总体结构图如图1:
图1 程序总体流程图图
程序总体流程图如图2:
5
图2 程序总体设计图
4.棋盘与棋子的生成
4.1引言
根据五子棋的基本规则,棋盘采用19×19方格棋盘,棋子为黑白二色圆形棋子;游戏进行过程中棋盘始终显示,落子后棋子在落子处始终显示;棋盘在程序结束时消失,已落下的棋子在 程序结束时或开始新游戏是消失。
4.2程序语句
棋盘的显示由游戏开始与结束部分控制,棋子的显示与保留由玩家操控部分决定。
board() /*画棋盘*/ { setfillstyle(1,6); bar(120,50,520,450); setfillstyle(1,14); bar(540,50,620,150); bar(20,50,100,150); for(k=0;k
{moveto(140+20*k,70);linerel(0,360);
moveto(140,70+20*k);linerel(360,0); }
moveto(240,170); setcolor(5); settextstyle(3,0,4); outtextxy(50,60,"P1"); outtextxy(560,60,"P2"); }
white() /*画白棋*/ {
setcolor(7);
setfillstyle(1,7);
circle(getx(),gety(),9); fill(getx(),gety(),7); }
black() /*画黑棋*/ {
6
setcolor(0);
setfillstyle(1,0);
circle(getx(),gety(),9); fill(getx(),gety(),0); }
5棋子移动与落子
5.1引言
棋子的移动与落子有键盘上按键控制,本程序选取1P按键为W、S、A、D和空格键,2P按键为↑、↓、←、→和回车键,分别代表上移、下移、左移、右移光标和落子。在光标移动的过程中,光标按照玩家按键移动;在玩家按下落子按键后,程序自动调用棋子显示子程序和判断胜负子程序。1P、2P的落子后,程序会为落子处的数组元素赋一个特定值,用于判定胜负。
5.2程序语句
void p1move() /*玩家1的移动*/ {
switch(bioskey(0)) {
int sum=0;
case ESC: {closegraph(); exit(0);}/*如果按键为ESC就退出游戏 */
case SP:/*落子*/ if(a[X][Y]==6) {
p1del(); p2turn();
7
a[X][Y]=0; sum++; white(); p2move(); if(sum>=5) win(); }
else p1move();
case A: /*向左移*/ if(a[X][Y]==0) {
if(getx()==140)
moveto(520,gety()); moverel(-20,0); white(); }
else if(a[X][Y]==1) {
if(getx()==140) moveto(520,gety()); black();moverel(-20,0); white(); } else {
if(getx()==140)
8
moveto(520,gety()); moverel(-20,0); white(); } p1move(); case D: /*向右移*/ if(a[X][Y]==0) {
if(getx()==500) moveto(120,gety()); moverel(20,0); white();} else if(a[X][Y]==1) {
if(getx()==500) moveto(120,gety()); black();moverel(20,0); white(); } else {
if(getx()==500) moveto(120,gety()) ; moverel(20,0); white(); }
9
p1move(); case W: /*向上移*/ if(a[X][Y]==0) {
if(gety()==70) moveto(getx(),450); moverel(0,-20); white(); }
else if(a[X][Y]==1) {
if(gety()==70) moveto(getx(),450); black(); moverel(0,-20); white(); } else {
if(gety()==70) moveto(getx(),450); moverel(0,-20); white(); } p1move();
case S: /*向下移*/
10
if(a[X][Y]==0) {
if(gety()==430) moveto(getx(),50); moverel(0,20); white(); }
else if(a[X][Y]==1) {
if(gety()==430) moveto(getx(),50); black(); moverel(0,20); white(); } else {
if(gety()==430) moveto(getx(),50); moverel(0,20); white(); } p1move(); default: p1move(); }
11
}
void p2move() /*玩家2的移动*/ {
switch(bioskey(0)) /*如果按键为ESC就退出游戏*/ {
int sum=0;
case ESC: {closegraph(); exit(0);} case ENTER: /*落子*/ if(a[X][Y]==6) {
p2del(); p1turn(); a[X][Y]=1; sum++; black(); p1move(); if(sum>=5) win(); } else p2move(); case LEFT: /*向左移*/ if(a[X][Y]==1) {
if(getx()==140) moveto(520, gety());
12
moverel(-20,0); black(); }
else if(a[X][Y]==0) {
if(getx()==140) moveto(520,gety()); if(getx()==140) moveto(500,gety()); white(); moverel(-20,0); black(); } else {
if(getx()==140) moveto(520,gety()); moverel(-20,0); black(); } p2move();
case RIGHT: /*向右移*/ if(a[X][Y]==1) {
if(getx()==500) moveto(120,gety());
13
moverel(20,0); black(); }
else if(a[X][Y]==0) {
if(getx()==500) moveto(120,gety()); white(); moverel(20,0); black(); } else {
if(getx()==500) moveto(120,gety()); moverel(20,0); black(); } p2move();
case UP: /*向上移*/ if(a[X][Y]==1) {
if(gety()==70) moveto(getx(),450); moverel(0,-20); black();
14
}
else if(a[X][Y]==0) {
if(gety()==70) moveto(getx(),450); white(); moverel(0,-20); black(); } else {
if(gety()==70) moveto(getx(),450); moverel(0,-20); black(); } p2move();
case DOWN: /*向下移*/ if(a[X][Y]==1) {
if(gety()==430) moveto(getx(),50); moverel(0,20); black(); }
else if(a[X][Y]==0)
15
{
if(gety()==430) moveto(getx(),50); white(); moverel(0,20); black(); } else {
if(gety()==430) moveto(getx(),50); moverel(0,20); black(); } p2move(); default: p2move(); } }
6胜负判断
6.1引言
胜负判断模块是程序的关键,该模块的设计直接关系到程序的运行速率和运行结果的正确与否。
本函数根据每次落子的位置,分别向上、下、左、右、左上、左下、右上、右下八个 方向判断是否有相同颜色的棋子连成五子,如果成立,游戏就结束,并显示提示信息,否则继续落子。
16
以下简析本程序流程:如表1所示,令当前落子点坐标为(X,Y),表中 i=X-4, j=Y-4,由获胜条件可以知,通过判断(X,Y)上、下、左、右、斜上、斜下八个方向上是否有连续的5个子即可得出是否获胜结果。在游戏开始时,将棋盘初始化,即将棋盘抽象为一个19*19的数组,数组中每个元素设为某一指定初始值(如8)。1P落子时,将数组内相应坐标处元素赋值为0;2P落子时,将数组内相应坐标处元素赋值为1。当(X,Y) 上、下、左、右、斜上、斜下八个方向某5个连续的子所对应的数组中元素之和等于0时,1P获胜;当(X,Y) 上、下、左、右、斜上、斜下八个方向某5个连续的子所对应的数组中元素之和等于5时,2P获胜。棋盘上的所有格子都被占满时,必有181个1P棋子和180个2P棋子,此时对应数组中所有项之和为180,并且游戏过程中对应数组中所有项之和只可能在这种状况下为180,所以可以用这一条件判断是否和棋。
表1 胜负判断表
为减少程序的运算,还可以将某些特殊情况排除在外。当落子数不大于8时,既不用判断胜负,也不用判断和棋与否,这部分功能在第二章移动与落子程序中实现。此外,还可以通过对落子次数的统计判断是否满足和棋条件,从而减少大量运算,即当判断177次胜负后出现和棋。
6.2程序设计
void win() /*判断输赢*/ {
17
int sum1,sum2,sum3,sum4,sum=1,n,i,j; for(i=X-4,j=Y-4,n=0;i
sum1=a[i][Y]+a[i+1][Y]+a[i+2][Y]+a[i+3][Y]+a[i+4][Y];
sum2=a[i][j]+a[i+1][j+1]+a[i+2][j+2]+a[i+3][j+3]+a[i+4][j+4]; sum3=a[X][j]+a[X][j+1]+a[X][j+2]+a[X][j+3]+a[X][j+4];
sum4=a[i][j+8+n]+a[i+1][j+7+n]+a[i+2][j+6+n]+a[i+3][j+5+n]+a[i+4][j+4+n]; if(sum1==5||sum2==5||sum3==5||sum4==5) p2win(); if
(sum1==0||sum2==0||sum3==0||sum4==0) p1win(); } sum++ if(sum==177) heqi(); }
7调整改进
7.1引言
前6章分别论述了五子棋C语言程序中的四大主要模块,但要生成可执行的程序,则还需将这些模块有机地结合起来。在结合的过程中,需要综合运 用函数调用、函数间书序传递和全局变量等知识。
18
7.2程序功能及调整
为满足实际操作需求,增加程序的兼容性与稳定性,在编写可执行程序的过程中,必须对原有各功能模块进行整合并添加或调整部分功能。
为方便玩家使用本程序,在程序中增加了“悔棋”、“认输”和“退出”功能,玩家可以通过在游戏构成中输入相关指令实现这些功能,具体语句见附录。
为增强程序的兼容性和实用性,在最终的可执行程序中还对原有模块进行了其他修改。
在调试的过程中,发现bios.h 和graphics.h两个头文件只有在Turbo C的编译环境下才能顺利执行,因此,使用bios.h和graphics.h的程序兼容性不高,因此,舍弃使用这两个头文件的图像显示模块,转而使用具有较高兼容性的全屏打印刷新显示块。后者虽然在视觉效果上不如前者,然而它可以在任何Windows系统下工作,而这比视觉效果重要得多。
在调试过程中,发现每当1P在最外圈落子时,系统即可弹出1P获胜的结果,这是由于win函数中是通过对落子点及其周围的若干点求和来判断是否获胜的。当1P在最外圈落子时,棋盘外的点被程序当做0处理,加上落子时被赋值为0的一点,正好满足1P获胜的条件,故而引发错误。改进方法:将用于判断输赢的数组a由原来的19*19改为21*21,并将第0、20行及第0、20列中所有元素赋值为6;再将被这四组元素包围的一个19*19的区间对应到棋盘上的19*19格,即可解决原有问题。
在调试的过程中,还发现原有模块中的按键操作过于复杂,综合兼容性考虑,舍弃原有的光标操作模式,改用输入坐标的操作模式,这样做从某种程度上降低了程序的可操作性,但提高了程序的可实现性与兼容性。
7.3总程序语句
/*函数、变量定义*/
#include #include #include #include
19
#define N 19 int win(int m, int l); void printState(); p1win(); p2win(); heqi(); void help(); int i,j,k,size=N; int isBlack=1; char state[N][N]; int a[N+2][N+2]; char x,y,temp[10]; char c; int z;
/*初始化及指令输入*/
void startGame() {
int m,n,w; for(i=0;i
for(j=0;j
state[i][j]='_'; a[i][j]=6;
20
}
}
printState();
while(1)
{
printf("\n\t请%s方下子:",isBlack?"黑":"白");
fflush(stdin);
scanf("%s",temp);
if(!strcmp(strupr(temp),"OUT"))
{
system("cls");
return;
}
/*悔棋 */
if(!strcmp(temp,"BACK"))
{
i=x-'A';
j=y-'A';
state[i][j]='_';
printState();
isBlack=!isBlack;
continue;
}
if(!strcmp(temp,"LOSE"))
21
/*认输*/
{
printf("\n\t%s方认输,%s方胜!\n\n",isBlack?"黑":"白",isBlack?"白":"黑"); return;
}
x=temp[0];
y=temp[1];
/*避免下面相减的数组越界。*/
if(x'S'||y'S')
{
printf("\t输入有误,请输入属于或正确的口令。\n");
continue;
}
i=x-'A';
j=y-'A';
if(state[i][j]!='_')
{
printf("\t提示:该位置已经有子,请重新指定坐标!");
continue;
}
c=isBlack?'1':'2';
z=isBlack? 0:1;
22
state[i][j]=c;
a[i+1][j+1]=z;
m=i+1;
n=j+1;
w=win(m,n);
if(!w)
{
printState();
isBlack=!isBlack;
}
else
{
return;
}
}
}
/*判断输赢*/
int win(int m, int l)
{
int
sum1,sum2,sum3,sum4,sum=1,n,i,j,X,Y,w;
w=0;
X=m;
Y=l;
23
for(i=X-4,j=Y-4,n=0;i
{
sum1=a[i][Y]+a[i+1][Y]+a[i+2][Y]+a[i+3][Y]+a[i+4][Y];
sum2=a[i][j]+a[i+1][j+1]+a[i+2][j+2]+a[i+3][j+3]+a[i+4][j+4];
sum3=a[X][j]+a[X][j+1]+a[X][j+2]+a[X][j+3]+a[X][j+4];
sum4=a[i][j+8+n]+a[i+1][j+7+n]+a[i+2][j+6+n]+a[i+3][j+5+n]+a[i+4][j+4+n];
if(sum1==5||sum2==5||sum3==5||sum4==5)
{
p2win();
w=1;
}
if
(sum1==0||sum2==0||sum3==0||sum4==0)
{
p1win();
w=1;
}
}
sum1=0;
sum2=0;
sum3=0;
sum4=0;
sum++;
24
if(sum==177)
{
heqi();
w=1;
}
return w;
}
/*和棋界面*/
heqi()
{
printf("和棋");
return;
}
/*玩家1获胜界面*/
p1win()
25
{
printf("玩家1获胜");
return;
}
/*玩家2获胜界面*/
p2win()
{
printf("玩家2获胜");
return;
}
/*帮助*/
void help()
{
system("cls");
printf("\t本程序采用19*19的游戏格式\n\n");
printf("\t输入格子的坐标下子: 先横坐标后纵坐标。比如输入:GG\n\n");
printf("\t输入out(退回主菜单)、back(悔棋)、lose(认输)\n\n");
}
26
/*主函数*/
int main()
{
system("color f1");
while(1)
{
printf("\n\t-----C Programming Language课程作业:五子棋-----\n\n");
printf("\t\t 1.开始游戏\n");
printf("\t\t 2.帮助\n");
printf("\t\t 3.退出\n");
printf("\n\t请选择:");
L:k=scanf("%d",&i);
switch(i)
{
case 1: startGame(); break;
case 2: help(); break;
case 3: return 0;
default:printf("\t 无此选项\n");break;
}
}
}
/*显示、刷屏*/
void printState()
27
{
char p='A';
system("cls");
printf("\t棋盘如下:\n\n");
printf("\t ");
for(i=0;i
{
printf("%c ",p+i);
}
printf("\n\t");
for(i=0;i
{
printf("%c ",p+i);
for(j=0;j
{
printf("%c ",state[i][j]);
}
printf("%c \n\t",p+i);
}
printf(" ");
for(i=0;i
{
printf("%c ",p+i);
}
printf("\n");
}
28
8 总结
C语言课程设计时一次对我们c语言学习的综合检验,它要求我们将所学的c语言代码进行综合运用,设计出一个简单的系统,这不仅是对我们基础知识的检验,还考验我们的动手动脑以及团队协作能力,在这一年学习中要将这些基础知识掌握已经不容易了,在这么短的时间又要做出一个系统更是一次重大的挑战,然而只有迎难而上才能收获成功,做出一个完整的系统。
回顾这次课程设计,至今我感慨颇多。很多的知识只是停留在基本的应用上,当需要结合使用时,往往出现无从入手的情况。在C语言课程设计的过程中,让我深深体会到了这点。一些细节的地方没有看清楚,或者思考妥当,就无法让系统运行,而当一系列调试后,程序能够运行。
通过对各子程序的设计与优化,本程序完成了五子棋软件的主体的设计与制作,基本达到了使用五子棋软件的核 心要求。然而程序还有一些不足之处,首先,程序在判断胜负后无法显示第五枚棋子,输入五子连环的第五个棋子坐标之后直接跳出了重新开始的界面,这是由程序的显示原理造成的;其次,程序的界面过于简陋,而且坐标输入操作也不利于玩家使用。
对于这次课程设计我很不满意,没有达到自己想要的效果,系统中还存在着许多的漏洞,在本次课程设计过程中我也发现了自己的很多缺点,比如做事不认真,粗心大意,考虑问题不够全面等。最后,谢谢老师的教导。
参考文献
[1] 五 子 棋 [EB].
http://baike.baidu.com/view/2697.htm.
[2] C语言制作五子棋[EB].
http://www.vcworld.net/news/200905/022217.html
[3] C语言五棋源代码 设计报告[EB].
http://wenku.baidu.com/view/e253a2c66137ee06eff91859.html
29
[4] C语言五子棋算法[EB].
http://www.4oa.com/Article/html/6/31/445/2005/1541 3.htm
30
注:实习成绩由指导教师或答辩小组评定出成绩,分优秀、良好、中等、及格、不及格五级,分别给小组的每个成员打分。
31
32