黑白棋游戏课程设计.docx
《黑白棋游戏课程设计.docx》由会员分享,可在线阅读,更多相关《黑白棋游戏课程设计.docx(23页珍藏版)》请在冰豆网上搜索。
![黑白棋游戏课程设计.docx](https://file1.bdocx.com/fileroot1/2022-12/12/42e0e31e-6113-437c-bafe-85ae75b24fee/42e0e31e-6113-437c-bafe-85ae75b24fee1.gif)
黑白棋游戏课程设计
湖南文理学院课程设计报告
课程名称:
计算机软件技术基础
学院:
电气与信息工程学院
专业班级:
通信08102班
*********************************
学号:
200816020210
*************************
完成时间:
2010年12月29日
报告成绩:
评阅意见:
评阅老师:
评阅时间:
《黑白棋游戏》C语言课程设计
一、设计目的
本课程设计是计算机软件技术基础重要的实践性环节之一,是在学生学习完《程序设计语言(C)》课程后进行的一次全面的综合练习。
本课程设计的目的和任务:
(1)巩固和加深学生对C语言课程的基本知识的理解和掌握;
(2)掌握C语言编程和程序调试的基本技能;
(3)利用C语言进行基本的软件设计,掌握软件设计一般方法,了解软件设计的思路;
(4)掌握书写程序设计报告的能力;
(5)提高运用C语言解决实际问题的能力;
这个程序也是对编程基本功的一个训练,对于初学C语言的人,讲分支、循环、数组函数综合应用,而不仅限于编制独立的小程序,能够大大提高变成水平。
二、设计要求
(1)收集资料,全面分析课题,分解问题,形成中体编程思路;
(2)深入分析各个小问题,编写个部分程序模块;
(3)对于设计中用到的关键函数,要联系实际问题进行具体介绍;
(4)上机调试,确保程序能正确运行;
(5)设计完成后提交课程设计报告;
三、所需仪器设备
(1)硬件要求能运行Windows2000/XP操作系统的微机系统。
(2)C语言程序设计及相应的开发环境。
(本设计用的是TurboCforWindows集成实验与学习环境V6.0)
四、课题分析
编写一个《黑白棋游戏》的C程序,包括以下功能:
初始状态:
在一个8*8的棋盘中央交叉排放黑白棋子各两枚,白棋先走。
(1)每个棋手下棋时,摆子的位置必须是以自己的棋子能包围住对方一个或多个棋子,被包围住的对方棋子将成为自己的棋子。
包围的方向可以是上下左右以及斜线8个方向,只要能连成一线即可。
(2)当轮到某一个棋手下子,但是他没有可以包围对方棋子的位置时,他必须停步,让对方走棋,直到他可以走为止。
(3)当棋盘上一方的棋子为0或者下满64格,游戏结束,棋子少者输。
五、具体设计过程
5.1、设计思路
程序界面应是一个二维平面图,所以数据的表示用二维数组,数组两个下标可以表示棋盘上的位置,数组元素的值代表棋格中的状态,共有三种情况,分别是空格、黑棋和白棋。
这样给数组元素的取值设定为0、1、2,其中0代表空格,1代表白色棋子,2代表黑色棋子。
这样程序的主要工作是接收棋手按键操作,一旦接收到回车键,说明棋手摆子,先判断是不是有效位置,也就是能不能包围住对方棋子,如果能,便为棋子所在的位置往上下、左右、左上、左下、右上、右下8个方向寻找被包围住的所有棋子(必须是连续的,中间不能有空格),将这些被包围住的对方棋子都变成自己的棋子,然后对当前棋盘中的黑白棋个数进行统计并输出结果。
如果没有这样的位置可以落子,则停步,让对方走棋,重复上述步骤,直到游戏结束。
如果想提前终止游戏,可以按Esc键。
5.2、程序设计流程图
(1)程序整体组成结构框图如下图所示:
图1程序整体组成结构框图
(2)由上述设计思路可画出程序整体流程图,如下图所示:
图2程序整体流程图
(3)人人对战模块程序流程图如下图所示:
图3人人对战模块流程图
(4)成绩输出模块程序流程图如下图所示
图4成绩输出模块程序流程图
5.3、函数实现说明
(1)main()主函数
在主函数中,首先定义使用到的常数、全局变量、函数原型说明。
盘状态用数组a[8][8],初值为0,表示空格。
函数的实体部分,开始初始化图形系统,然后通过调用函数DrawQp()先画出棋盘,调用playtoplay()人人对战函数开始游戏,一旦游戏结束后,关闭图形系统,程序结束。
(2)DrawQp()画棋盘函数
背景颜色设为蓝色,从坐标(100,100)开始每隔40个单位用白色画一条水平直线,一条垂直线,构成棋盘,用循环语句实现。
函数setfillstyle()可以设置填充模式和填充颜色,fillellipse(intx,inty,xradius,intyradius)以x和y为圆心,xradius和yradius为水平和垂直轴画一填充椭圆,当xradius和yradius相等时,则画出的是圆,用它表示棋子。
(3)SetPlayColor()设置棋子的颜色
函数的参数为整型变量t,根据t的值来设计填充棋子的当前颜色,值为1代表白棋,值为2代表黑棋。
(4)MoveColor()恢复原来格子的状态
由于棋手在走棋的时候,他的棋子总是首先出现在棋盘的左上角,棋手要通过移动光标走到要落子的位置,在经过的路程上显示当前棋子,就会覆盖原来的棋盘状态,所以一旦棋子走过后,就应恢复原来的状态,是空格的依然显示空格,是棋子的就显示原来棋子的颜色。
因为棋子移动过程并没有改变数组元素的值,所以可以根据数组元素的值判定原来的状态,如果值是1,就恢复白色棋子,值是2则恢复黑色棋子,否则恢复蓝色空格。
(5)、playtoplay()人人对战函数
这是游戏进行的函数,主要是接收棋手的按键消息,其处理过程如下:
1)按Esc键程序可以随时结束。
2)按上下左右光标键,则改变棋子移动的坐标值。
3)按回车键后判断:
①如落子的位置已经有棋则无效,继续压键。
②如落子位置是空格,可以将棋子落入格内,调用函数QpChange()判断是否引起棋盘的变化,函数值为1有变化,为0没变化。
如果棋盘有变化,说明将包围的对方棋子吃掉,统计当前分数,如果棋盘没有变化,则说明落子的位置无法包围对方的棋子也视为无效棋,可以继续寻找合适的位置,但开始统计其落子次数,一旦尝试次数超过当前棋盘的空格数,则说明他无棋可走,则放弃此步,让对方下棋。
③如果棋子变化后,格子已占满64格或一方棋子为0,则游戏结束,显示胜利方信息。
按任意键程序结束。
④重复上述步骤,直到游戏结束。
(6)、QpChange()判断棋盘变化
当棋手按回车键落子后,就要分别往8个方向判断是否包围住对方棋子,如果是,则改变棋盘,也就是棋盘上黑白棋子的个数要发生变化。
如果所有方向都判断过,并且没有引起棋盘的变化,则棋盘变化标志值yes为0,返回yes,结束本函数。
(7)、DoScore()处理分数
根据当前数组元素的值判断分数,也就是各方棋子的个数,如果数组元素值为1,白棋棋子数累加;如果数组元素值为2,则黑棋棋子数累加。
(8)、PrintScore()输出成绩
利用设置实体填充模式填充矩形条清除掉前次的成绩,再利用sprintf()函数将整数转换为字符串的形式,再利用outtextxy()函数将成绩输出。
(9)、playWin()输出胜利者结果
根据分数值score1和score2的大小得出下棋的结果,输出赢者信息。
如果是白方胜就输出“whitewin!
”,黑方胜就输出“blackwin!
”,平局就输出“youallwin!
”。
5.4、图形库函数介绍
图形库是TC里面的图形库,分为:
像素函数、直线和线型函数、多边形函数、填充函数等。
在本程序中主要应用到了以下功能函数:
(1)、line()画线函数
功能:
函数line()使用当前绘图色、线型及线宽,在给定的两点间画一直线。
函数原型:
voidline(intstartx,intstarty,intendx,intendy);
说明:
参数startx,starty为起点坐标,endx,endy为终点坐标,函数调用前后,图形状态下屏幕光标(一般不可见)当前位置不改变。
(2)、setcolor()图形屏幕函数
函数原型:
voidsetcolor(intcolor)
功能:
将当前图形屏幕的当前笔画颜色置为color.
(3)、setfillstyle()设置填充图样和颜色函数
函数原型:
voidfarsetfillstyle(intpattern,intcolor);
功能:
设置填充模式和颜色
(4)、fillellipse()画椭圆区函数
功能:
画出并填充一椭圆
函数原型:
voidfarfillellipse(intx,inty,intxradius,intyradius);
说明:
填充边框所定义的椭圆的内部,该边框由一对坐标、一个宽度和一个高度指定。
(5)、setbkcolor()
功能:
该函数用指定的颜色值来设置当前的背景色
函数原型:
VoidfarSetBkColor(intColor);
(6)、C语言中的颜色表及填充模式如下两表所示:
5.5、程序源代码及注释
#include"graphics.h"/*图形系统头文件*/
#defineLEFT0x4b00/*光标左键值*/
#defineRIGHT0x4d00/*光标右键值*/
#defineDOWN0x5000/*光标下键值*/
#defineUP0x4800/*光标上键值*/
#defineESC0x011b/*ESC键值*/
#defineENTER0x1c0d/*回车键值*/
inta[8][8]={0},key,score1,score2;/*具体分数以及按键与存放棋子的变量*/
charplayone[3],playtwo[3];/*两个人的得分转换成字符串输出*/
voidplaytoplay(void);/*人人对战函数*/
voidDrawQp(void);/*画棋盘函数*/
voidSetPlayColor(intx);/*设置棋子第一次的颜色*/
voidMoveColor(intx,inty);/*恢复原来棋盘状态*/
intQpChange(intx,inty,intz);/*判断棋盘的变化*/
voidDoScore(void);/*处理分数*/
voidPrintScore(intn);/*输出成绩*/
voidplayWin(void);/*输出胜利者信息*/
/******主函数*********/
voidmain(void)
{
intgd=DETECT,gr;
initgraph(&gd,&gr,"c:
\\tc");/*初始化图形系统*/
DrawQp();/*画棋盘*/
playtoplay();/*人人对战*/
getch();
closegraph();/*关闭图形系统*/
}
voidDrawQp()/*画棋盘*/
{
inti,j;
score1=score2=0;/*棋手一开始得分都为0*/
setbkcolor(BLUE);
for(i=100;i<=420;i+=40)
{
line(100,i,420,i);/*画水平线*/
line(i,100,i,420);/*画垂直线*/
}
setcolor(0);/*取消圆周围的一圈东西*/
setfillstyle(SOLID_FILL,15);/*白色实体填充模式*/
fillellipse(500,200,15,15);/*在显示得分的位置画棋*/
setfillstyle(SOLID_FILL,8);/*黑色实体填充模式*/
fillellipse(500,300,15,15);
a[3][3]=a[4][4]=1;/*初始两个黑棋*/
a[3][4]=a[4][3]=2;/*初始两个白棋*/
setfillstyle(SOLID_FILL,WHITE);
fillellipse(120+3*40,120+3*40,15,15);
fillellipse(120+4*40,120+4*40,15,15);
setfillstyle(SOLID_FILL,8);
fillellipse(120+3*40,120+4*40,15,15);
fillellipse(120+4*40,120+3*40,15,15);
score1=score2=2;/*有棋后改变分数*/
DoScore();/*输出开始分数*/
}
voidplaytoplay()/*人人对战*/
{
intx,y,t=1,i,j,cc=0;
while
(1)/*换棋手走棋*/
{
x=120,y=80;/*每次棋子一开始出来的坐标,x为行坐标,y为列坐标*/
while
(1)/*具体一个棋手走棋的过程*/
{
PrintScore
(1);/*输出棋手1的成绩*/
PrintScore
(2);/*输出棋手2的成绩*/
SetPlayColor(t);/*t变量是用来判断棋手所执棋子的颜色*/
fillellipse(x,y,15,15);
key=bioskey(0);/*接收按键*/
if(key==ESC)/*跳出游戏*/
break;
else
if(key==ENTER)/*如果按键确定就可以跳出循环*/
{
if(y!
=80&&a[(x-120)/40][(y-120)/40]!
=1
&&a[(x-120)/40][(y-120)/40]!
=2)/*如果落子位置没有棋子*/
{
if(t%2==1)/*如果是棋手1移动*/
a[(x-120)/40][(y-120)/40]=1;
else/*否则棋手2移动*/
a[(x-120)/40][(y-120)/40]=2;
if(!
QpChange(x,y,t))/*落子后判断棋盘的变化*/
{
a[(x-120)/40][(y-120)/40]=0;/*恢复空格状态*/
cc++;/*开始统计尝试次数*/
if(cc>=64-score1-score2)/*如果尝试超过空格数则停步*/
{
MoveColor(x,y);
fillellipse(x,y,15,15);
break;
}
else
continue;/*如果按键无效*/
}
DoScore();/*分数的改变*/
break;/*棋盘变化了,则轮对方走棋*/
}
else/*已经有棋子就继续按键*/
continue;
}
else/*四个方向按键的判断*/
if(key==LEFT&&x>120)/*左方向键*/
{
MoveColor(x,y);
fillellipse(x,y,15,15);
SetPlayColor(t);
x-=40;
fillellipse(x,y,15,15);
}
else
if(key==RIGHT&&x<400&&y>80)/*右方向键*/
{
MoveColor(x,y);
fillellipse(x,y,15,15);
SetPlayColor(t);
x+=40;
fillellipse(x,y,15,15);
}
else
if(key==UP&&y>120)/*上方向键*/
{
MoveColor(x,y);
fillellipse(x,y,15,15);
SetPlayColor(t);
y-=40;
fillellipse(x,y,15,15);
}
else
if(key==DOWN&&y<400)/*下方向键*/
{
MoveColor(x,y);
fillellipse(x,y,15,15);
SetPlayColor(t);
y+=40;
fillellipse(x,y,15,15);
}
}
if(key==ESC)/*结束游戏*/
break;
if((score1+score2)==64||score1==0||score2==0)/*格子已经占满或一方棋子为0判断胜负*/
{
playWin();/*输出最后结果*/
break;
}
t=t%2+1;/*一方走后,改变棋子颜色即轮对方走*/
cc=0;/*计数值恢复为0*/
}/*endwhile*/
}
voidSetPlayColor(intt)/*设置棋子颜色*/
{
if(t%2==1)
setfillstyle(SOLID_FILL,15);/*白色*/
else
setfillstyle(SOLID_FILL,8);/*灰色*/
}
voidMoveColor(intx,inty)/*走了一步后恢复原来格子的状态*/
{
if(y<100)/*如果是从起点出发就恢复蓝色*/
setfillstyle(SOLID_FILL,BLUE);
else/*其他情况如果是1就恢复白色棋子,2恢复黑色棋子,或恢复蓝色棋盘*/
switch(a[(x-120)/40][(y-120)/40])
{
case1:
setfillstyle(SOLID_FILL,15);break;/*白色*/
case2:
setfillstyle(SOLID_FILL,8);break;/*黑色*/
default:
setfillstyle(SOLID_FILL,BLUE);/*蓝色*/
}
}
intQpChange(intx,inty,intt)/*判断棋盘的变化*/
{
inti,j,k,kk,ii,jj,yes;
yes=0;
i=(x-120)/40;/*计算数组元素的行下标*/
j=(y-120)/40;/*计算数组元素的列下标*/
SetPlayColor(t);/*设置棋子变化的颜色*/
/*开始往8个方向判断变化*/
if(j<6)/*往右边*/
{
for(k=j+1;k<8;k++)
if(a[i][k]==a[i][j]||a[i][k]==0)/*遇到自己的棋子或空格结束*/
break;
if(a[i][k]!
=0&&k<8)
{
for(kk=j+1;kk{
a[i][kk]=a[i][j];/*改变棋子颜色*/
fillellipse(120+i*40,120+kk*40,15,15);
}
if(kk!
=j+1)/*条件成立则有棋子改变过颜色*/
yes=1;
}
}
if(j>1)/*判断左边*/
{
for(k=j-1;k>=0;k--)
if(a[i][k]==a[i][j]||!
a[i][k])
break;
if(a[i][k]!
=0&&k>=0)
{
for(kk=j-1;kk>k&&k>=0;kk--)
{
a[i][kk]=a[i][j];
fillellipse(120+i*40,120+kk*40,15,15);
}
if(kk!
=j-1)
yes=1;
}
}
if(i<6)/*判断下边*/
{
for(k=i+1;k<8;k++)
if(a[k][j]==a[i][j]||!
a[k][j])
break;
if(a[k][j]!
=0&&k<8)
{
for(kk=i+1;kk{
a[kk][j]=a[i][j];
fillellipse(120+kk*40,120+j*40,15,15);
}
if(kk!
=i+1)
yes=1;
}
}
if(i>1)/*判断上边*/
{
for(k=i-1;k>=0;k--)
if(a[k][j]==a[i][j]||!
a[k][j])
break;
if(a[k][j]!
=0&&k>=0)
{
for(kk=i-1;kk>k&&k>=0;kk--)
{
a[kk][j]=a[i][j];
fillellipse(120+kk*40,120+j*40,15,15);
}
if(kk!
=i-1)
yes=1;
}
}
if(i>1&&j<6)/*右上*/
{
for(k=i-1,kk=j+1;k>=0&&kk<8;k--,kk++)
if(a[k][kk]==a[i][j]||!
a[k][kk])
break;
if(a[k][kk]&&k>=0&&kk<8)
{
for(ii=i-1,jj=j+1;ii>k&&k>=0;ii--,jj++)
{
a[ii][jj]=a[i][j];
fillellipse(120+ii*40,120+jj*40,15,15);
}
if(ii!
=i-1)
yes=1;
}
}
if(i<6&&j>1)/*左下*/
{
for(k=i+1,kk=j-1;k<8&&kk>=0;k++,kk--)
if(a[k][kk]==a[i][j]||!
a[k][kk])
break;
if(a[k][kk]!
=0&&k<8&&kk>=0)
{
for(ii=i+1,jj=j-1;ii{
a[ii][jj]=a[i][j];
fillellipse(120+ii*40,120+jj*40,15,15);
}
if(ii!
=i+1)
yes=1;
}
}
if(i>1&&j>1)/*左上*/
{
for(k=i-1,kk=j-1;k>=0&&kk>=0;k--,kk--)
if(a[k][kk]==a[i][j]||!
a[k][kk])
break;
if(a[k][kk]!
=0&&k>=0&&kk>=0)
{
for(ii=i-1,jj=j-1;ii>k&&k>=0;ii--,jj--)
{
a[ii][jj]=a[i][j];
fillellipse(120+ii*40,120+jj*40,15,15);
}
if(ii!
=i-1)
yes=1;
}
}
if(i<6&&j<6)/*右下*/
{
for(k=i+1,kk=j+1;kk<8&&kk<8;k++,kk++)
if(a[k][kk]==a[i][j]||!
a[k][kk])
break;
if(a[k][kk]!
=0&&kk<8&&k<8)
{
for(ii=i+1,jj=j+1;ii{
a[ii][jj]=a[i][j];
fillellipse(120+ii*40,120+jj*40,15,15);
}
if(ii!
=i+1)
yes=1;
}
}
returnyes;/*返回是否改变过棋子颜色的标记*/
}
voidDoScore()/*处理分数*/
{
inti,j;
score1=score2=0;/*重新开始计分数*/
for(i=0;i<8;i++)
for(j=0;j<8;j++)
if(a[i][j]==1)/*分别统计两个人的分数*/
score1++;
else
if(a[i][j]==2)
score2++;
}
voidPrintScore(intplaynum)/*输出成绩*/
{
if(playnum==1)/*