黑白棋C语言课程设计.docx
- 文档编号:30230081
- 上传时间:2023-08-07
- 格式:DOCX
- 页数:19
- 大小:64.95KB
黑白棋C语言课程设计.docx
《黑白棋C语言课程设计.docx》由会员分享,可在线阅读,更多相关《黑白棋C语言课程设计.docx(19页珍藏版)》请在冰豆网上搜索。
黑白棋C语言课程设计
摘要
黑白棋(Reversi、Othello),也叫苹果棋,翻转棋,是一个经典的策略性游戏。
它使用8*8的棋盘,由两人执黑子和白子轮流下棋,最后子多方为胜方。
轮到一方下棋时,必须把棋下在与对方棋子相邻的空位上,要求所下的棋子和原有的已方棋子夹住对方的至少一个棋子(横竖斜夹均可),然后把被夹住的子变成己方的颜色(也叫吃子)。
下棋过程中,任何棋子既不会从棋盘上拿走,也不会从一个格子移到另一个格子。
黑白棋规则简单,但是变化复杂,是典型的易学难精(aminutetolearn,alifetimetomaster),它看似简单,实际奥妙无穷。
一般说来,下棋过程中,你必须尽量削减对手的行动力,同时增加自己的行动力,这种策略我们称之为行动力原则(或行动力战术)。
当一方达到或接近这个目标时,我们就称该棋手控制了棋局。
另外,这个战术的目的是迫使对方下坏棋,如果对方虽然可选位置很少,但每一步却总有好棋,那战术目的就没有达成。
记住,你必须让对方完全无好棋可下。
黑白棋规则规定只能在对方棋子相邻的空位下棋,这就可以推出另一个原则。
对方棋子边上的空位越多,你下棋的选择也就越多,换句话说,你的行动力就越强;相反,如果你棋子边上的空位越少,对方可下的位置也就越少。
我们把相邻位置上有空位的子称为外子,反之称为内子,连在一起的外子称为前线或墙。
下棋时要尽量减少自己的外子。
关键字:
黑白棋,C语言,数组,函数
黑白棋游戏
一、课程设计目的
1.巩固和加深学生对C语言课程的基本知识的理解和掌握
2.掌握C语言编程和程序调试的基本技能
3.利用C语言进行基本的软件设计
4.提高运用C语言解决实际问题的能力
5.掌握软件开发过程的问题分析、系统设计、程序编码、测试等基本方法和技能。
二、实验器材及实验环境
硬件环境:
装有Windows2000或以上系统的微机系统
软件环境:
TurboC2.0软件
三、黑白棋的总体设想
1.设计思路
从已知的黑白棋游戏中可知,应该用二维数组表示程序的数据,数组两个下标可以表示棋盘上的位置,数组元素的值代表棋格中的状态,共有三种情况,分别是空格、黑棋和白棋,这样给数组元素的取值设定为0、1、2。
其中0代表空格,1代表白色棋子,2代表黑色棋子。
这样程序的主要工作是接收棋手按键操作,一旦接收到回车键,说明棋手摆子,先判定是不是有效位置,也就是能不能包围住对方棋子,如果能,便对棋子所在的位置往上下、左右、左上、左下、右上、右下8个方向寻找被包围住的所有棋子(必须是连续的,中间不能有空格),将这些被包围住的对方棋子都变成自己的棋子,然后对当前棋盘中的黑白棋个数进行统计并输出结果。
如果没有这样的位置可以落子,则停步,让对方走棋,重复上述步骤,直到游戏结束。
如果想提前终止游戏可以按Esc键。
2.结构设计
棋盘状态用数组a[8][8]初值为0表示空格。
函数的实体比较简单,因为要输出图形,所以应初始化图形系统,图形工作方式正确确定后,画出棋盘,调用playtoplay()人人对弈函数开始游戏。
一旦游戏结束后,关闭图形系统,程序结束。
本次设计主要要设计函数有:
1.main()主函数
按照语法规则,首先定义使用到的常数、全局变量、函数原型说明。
棋盘状态用数组a[8][8],初值为0,表示空格。
函数的实体比较简单,因为要输出图形,所以应初始化图形系统,图形工作方式正确确定后,画出棋盘,调用playtoplay()人人对弈函数开始游戏,一旦游戏结束后,关闭图形系统,程序结束。
2.DrawQp()画棋盘函数
背景颜色设为蓝色,从坐标(100,100)开始每隔40个单位用白色画一条水平直线,一条垂直线,构成棋盘,用循环语句实现.画线函数line()的参数为线的起点和终点坐标,注意要计算正确.函数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)按回车键后判断:
1)如落子的位置已经有棋则无效,继续压键。
2)如落子位置是空格,可以将棋子落入格内,调用函数QpChange()判断是否引起棋盘的变化,函数值为1有变化,为0没变化。
如果棋盘有变化,说明将包围的对方棋子吃掉,统计当前分数,如果棋盘没有变化,则说明落子的位置无法包围对方的棋子也视为无效棋。
可以继续寻找合适的位置,但开始统计其落子次数,一旦尝试次数超过当前棋盘的空格数,则说明他无棋可走,则放弃此步,让对方下棋。
3)如果棋子变化后,格子已占满64格或一方棋子为0,则游戏结束,显示胜利方信息。
按任意键程序结束。
(4)重复上述步骤,直到游戏结束。
6.QpChange()判断棋盘变化
当棋手按回车键落子后,就要分别往8个方向判断是否包围住对方棋子,如果是,则改变棋盘,也就是棋盘上黑白棋子的个数要发生变化。
表示黑白棋的图形用屏幕上的像素坐标,而棋子的状态是数组元素a,所以要根据落子的坐标x和y计算出对应数组元素a的下标i和j,i代表行,j代表列,对于8*8的棋盘,它们的值为0-7,如果j<6,往右边判断,从当前位置开始,用循环语句判断右边是否有一个或连续多个对方的棋子,遇到自己的棋子或空格则结束循环,如果循环结束不是遇到空白,且列坐标小于8,则说明这些位置的棋子是被自己包围的对方棋子,将它们吃掉也就是改变为自己的棋子,如果有棋子发生了变化,给棋盘变化标志值yes赋值为1,同样的方法向左、上、下等8个方向进行判断,并作相应的变化。
如果所有方向都判断过,并且没有引起棋盘的变化,则棋盘变化标志值yes为0返回yes结束本函数。
7.DoScore()处理分数
根据当前数组元素的值判断分数,也就是各方棋子的个数,如果数组元素值为1,白棋棋子数累加,如果数组元素值为2,则黑棋棋子数累加。
8.PrintScore()输出成绩
利用设置实体填充模式填充矩形条清除掉前次的成绩,再利用sprintf()函数将整数转换为字符串的形式,再利用outtextxy()函数将成绩输出。
9.playWin()输出胜利者结果
根据分数值score1和score2的大小得出下棋的结果,输出赢者信息。
3.流程图
3.1playtoplay函数流程图:
3.2主函数流程图:
图2
四、C语言实现
本设计是基于TurboC强大的图形函数而成的,TurboC提供了70多个图形函数,这些函数包括在图形库文件graphics.LIB中,他们被定义在graphics.h中。
源程序如下:
#include"graphics.h"/*图形系统头文件*/
#include"conio.h"
#defineBLUE0xA80000
#defineRED0x0000A8
#defineSOLID_FILL2
#defineDETECT
#defineLEFT0x4b00/*光标左键值*/
#defineRIGHT0x4d00/*光标右键值*/
#defineDOWN0x5000
#defineUP0x4800
#defineESC0x011b
#defineENTER0x1c0d
inta[8][8]={0},key,scoreblack[2]={0},scorewhite[2]={0};
voidqipan()/*开始画面*/
{inti;
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);
}
voidplaycolor(intt)/*设置棋子第一次的颜色*/
{
if(t%2==0)
setfillstyle(SOLID_FILL,15);
else
setfillstyle(SOLID_FILL,8);
}
voidplaycolortwo(intxx,intyy)/*走了一步后恢复原来那里的格子*/
{
if(yy<100)
setfillstyle(SOLID_FILL,BLUE);
else
switch(a[(xx-120)/40][(yy-120)/40])
{
case1:
setfillstyle(SOLID_FILL,15);break;
case2:
setfillstyle(SOLID_FILL,8);break;
default:
setfillstyle(SOLID_FILL,BLUE);
}
}
voidqipanchange(intxxx,intyyx,intt)/*棋盘的变化,也就是黑白的变化*/
{
inti,j,k,kk,ii,jj;
i=(xxx-120)/40;
j=(yyx-120)/40;
playcolor(t);
if(j<6)/*开始判断变化*//*往右边*/
{
for(k=j+1;k<8;k++)
if(a[i][k]==a[i][j]||!
a[i][k])
break;
if(a[i][k]&&k<8)
for(kk=j+1;kk { a[i][kk]=a[i][j]; fillellipse(120+i*40,120+kk*40,15,15); } } 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]&&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(i<6)/*往下*/ { for(k=i+1;k<8;k++) if(a[k][j]==a[i][j]||! a[k][j]) break; if(a[k][j]&&k<8) for(kk=i+1;kk { a[kk][j]=a[i][j]; fillellipse(120+kk*40,120+j*40,15,15); } } 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]&&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(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(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]&&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(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]&&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(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]&&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); } } } voiddoscore()/*处理分数*/ {inti,j; scorewhite[0]=scorewhite[1]=scoreblack[0]=scoreblack[1]=0; /*重新开始计分数*/ for(i=0;i<8;i++) for(j=0;j<8;j++) if(a[i][j]==1)/*分别统计两个人的分数*/ { scorewhite[1]++; if(scorewhite[1]==10) {scorewhite[1]=0;scorewhite[0]++;} } elseif(a[i][j]==2) { scoreblack[1]++; if(scoreblack[1]==10) {scoreblack[1]=0;scoreblack[0]++;} } } printscore(playnum)/*输出成绩*/ {inti,j,k; ints[2]; if(playnum==1)/*把分数给这个临时变量*/ for(i=0;i<2;i++) s[i]=scorewhite[i]; else for(i=0;i<2;i++) s[i]=scoreblack[i]; if(playnum==1)/*清楚以前的成绩*/ { setfillstyle(SOLID_FILL,BLUE); bar(550,100,640,400); } if(playnum==1)/*判断输出的行数*/ k=200; else k=300; setcolor(RED); settextstyle(0,0,4); for(i=0,j=550;i<2;i++,j+=40) { switch(s[i])/*判断要输出的分数*/ { case0: outtextxy(j,k,"0");break; case1: outtextxy(j,k,"1");break; case2: outtextxy(j,k,"2");break; case3: outtextxy(j,k,"3");break; case4: outtextxy(j,k,"4");break; case5: outtextxy(j,k,"5");break; case6: outtextxy(j,k,"6");break; case7: outtextxy(j,k,"7");break; case8: outtextxy(j,k,"8");break; case9: outtextxy(j,k,"9");break; } } setcolor(0); } voidplaywin()/*输出最后的胜利者结果*/ {settextstyle(0,0,4); setcolor(12); if(scoreblack[0]>scorewhite[0]) outtextxy(100,50,"blackwin! "); elseif(scoreblack[0] outtextxy(100,50,"whitewin! "); elseif(scoreblack[0]==scorewhite[0]) { if(scoreblack[1]==scorewhite[1]) outtextxy(60,50,"youallwin! "); elseif(scoreblack[1]>scorewhite[1]) outtextxy(100,50,"blackwin! "); elseif(scoreblack[1] outtextxy(100,50,"whitewin! "); } } voidplaytoplay()/*人人对战*/ {intxx,yy,t=0,sum,i,j; while (1) { xx=120,yy=80;/*每次棋子一开始出来的坐标*/ while (1) { printscore (1);/*输出玩家1的成绩*/ printscore (2);/*输出玩家2的成绩*/ playcolor(t); fillellipse(xx,yy,15,15); key=bioskey(0); sound(100); nosound(); if(key==ESC) break; elseif(key==ENTER)/*如果按键确定就可以跳出循环*/ { if(yy! =80&&a[(xx-120)/40][(yy-120)/40]! =1&&a[(xx-120)/40][(yy-120)/40]! =2) /*是否已经有子*/ { if(t%2==0) a[(xx-120)/40][(yy-120)/40]=1; else a[(xx-120)/40][(yy-120)/40]=2; qipanchange(xx,yy,t);/*走好一步棋子后屏幕的变化*/ doscore();/*分数的改变*/ break;/*判断成功就下一个棋子走*/ } else continue;/*不成功就等于白按回车*/ } elseif(key==LEFT&&xx>120)/*四个方向按键盘的判断*/ { playcolortwo(xx,yy);/*判断原来位置因为画什么,这里只画蓝色是不完整的*/ fillellipse(xx,yy,15,15); playcolor(t); xx-=40; fillellipse(xx,yy,15,15); } elseif(key==RIGHT&&xx<400&&yy>80) { playcolortwo(xx,yy); fillellipse(xx,yy,15,15); playcolor(t); xx+=40; fillellipse(xx,yy,15,15); } elseif(key==UP&&yy>120) { playcolortwo(xx,yy); fillellipse(xx,yy,15,15); playcolor(t); yy-=40; fillellipse(xx,yy,15,15); } elseif(key==DOWN&&yy<400) { playcolortwo(xx,yy); fillellipse(xx,yy,15,15); playcolor(t); yy+=40; fillellipse(xx,yy,15,15); } } if(key==ESC) break; sum=0; for(i=0;i<8;i++)/*判断是否棋子填满*/ for(j=0;j<8;j++) if(a[i][j]! =0) sum++; if(sum==64) { playwin();/*判断胜负*/ break; } t++; if(t==11)/*如果t到了11就变成1*/ t=1; } } voidmain() { intgr,gd=DETECT; //intgraphdriver=DETECT,graphmode; //initgraph(&graphdriver,&graphmode,"c: \Programfiles\WINYES\TCPP30H\BGI"); initgraph(&gd,&gr,""); qipan();/*画棋盘*/ playtoplay();/*人人对战*/ getch(); closegraph(); } 五、总结 这个黑白棋游戏原程序是基于TurboC强大的图形处理函数下完成的,其最大特点是采用了在主函数中调用子函数思想,每一种功能都是用子函数的办法来进行处理,简洁,清晰,方便,不容易出现错误。 在输入错误时本来想用一种警告的铃声来提醒用户,由于所学的知识不多,自己的编程经验不足,按现有的知识水平有些东西暂时还无法解决,还有待于在以后的学习中不断提高和改进! 六、心得体会 C语言作为国际上广泛流行的通用程序设计语言,在计算机的研究和应用中已展现出强大的生命力。 C语言兼顾了诸多高级语言的特点,是一种典型的结构化程序设计语言,它处理能力强,使用灵活方便,应用面广,具有良好
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 白棋 语言 课程设计