五子棋游戏C语言.docx
《五子棋游戏C语言.docx》由会员分享,可在线阅读,更多相关《五子棋游戏C语言.docx(21页珍藏版)》请在冰豆网上搜索。
五子棋游戏C语言
五子棋游戏程序设计(C语言实现)
一、设计任务与目标
设计两个人对战的五子棋游戏,游戏开始界面是显示游戏的规则,然后让用户输入命令以确定游戏是否开始,如果用户确定开始,那么要显示棋盘,接下来到了最重要的几步,两个玩家交替落子,当连续五个棋子在一条直线上时,一方赢棋,游戏结束。
其中,有些问题就是平时基本的输入输出问题,例如:
游戏规则,可以直接打印。
棋盘的显示也是一般的图形输出问题,但是稍微复杂一些。
需要改进的地方和达到的目标是:
1、游戏的初始界面显示的是游戏规则,当玩家确定开始的时候要清除界面来显示棋盘。
2、棋盘和棋子的显示,界面(棋子和棋盘)容易分辨,这要从颜色和图形上加以区分。
3、要求一方用‘W’(上)、‘S’(下)、‘A’(左)、‘D’(右),另一方用‘↑’、‘↓’、‘←’、‘→’来移动光标,再分别用‘Z’和‘空格’键确定落子。
4、当一方走棋时,另一方的按键应该设置为无效。
5、游戏进行时打印提示信息,当一方赢棋后,要显示赢棋的字符,并询问玩家是否继续开始。
6、可以随时退出游戏或重新开始游戏。
二、方案设计与论证
首先设置游戏的初始界面,采用白色背景和红色前景,这可以调用‘conio.h’库函数实现打印游戏规则。
询问玩家是不是开始游戏,通过选择Y\N来确定。
其中会遇到这样的问题:
当玩家输入的不是‘Y(y)’或者‘N(n)’时应该怎么办呢?
如果采用scanf函数来接收命令,这样会显示一个不满足要求的字符,于是可以用getch函数来接收命令,判断输入的字符是否为‘Y(y)’和‘N(n)’,如果是再显示出来。
为了界面的简洁,进入游戏前先清除屏幕,调用‘system()’函数来实现。
然后打印棋盘,可以把背景设置为湖蓝色,这样棋盘和棋子更容易分辨。
游戏开始后棋盘用黑色显示,这样易于区分。
具体的思路是:
由于棋盘是网格状的,所以选择一个基本图形字符串‘十’,通过循环打印而构成一张大图。
接下来确定落子的位置,这需要通过改变光标的位置来实现,考虑到是在vc6.0环境下编译文件,c语言中的有些库函数并不支持,所以选择了’gotoxy()’函数并结合‘window.h’下的函数,通过键盘按键控制达到光标移动功能。
定义一个二维数组来记录棋子落点数据,当棋盘上的某一个位置有棋子时,能判断这个位置不能再落子了。
因为游戏设置的是两个玩家操作不同的按键来控制的,所以当一方走棋时,另一方的按键要设置成无效,采用的办法是过滤接收的字符。
例如,当玩家一走棋时,只有当输入的字符为‘W’、‘A’、‘S’、‘D’、‘Z’、‘Q’、‘Esc’时,才响应,而‘↑’、‘↓’、‘←’、‘→’、‘空格’以及其他字符则不响应。
最后是判断输赢。
根据五子棋规则,如果连续的五个相同颜色的棋子在一条直线上就算赢。
于是用代码实现时,就确定了基本的思路:
利用for循环来遍历棋盘上的落点。
这里有四种情况,分别是从左往右,从上往下,从左下往右上,从左上往右下,判断是否有五子连续在一直线上,并且连续五个位置记录的数据相等时就打赢某一方赢了。
要重新开始就输入‘Q’。
三、程序框图或流程图,程序清单与调用关系
程序清单:
函数声明
功能
Main()
主函数
voiddrawqipan()
画棋盘
voidgotoxy()
光标定位
voidmovegb()
移动光标
voidluozi()
落棋子
voidjudgewin()
判断输赢
voidsystem()
系统函数
intstartgame()
游戏初始界面
voidinitdata()
初始化游戏数据
程序调用关系:
程序流程图:
voidmovegb()luozi()
Voiddrawqipan()voidjudgewin()
否
是
是i
intStartGame()
四、全部源程序清单
#include
#defineplay1up'w'
#defineplay1down's'
#defineplay1left'a'
#defineplay1right'd'
#defineplay2up72
#defineplay2down80
#defineplay2left75
#defineplay2right77
#defineplay1lq'z'
#defineplay2lq''
#defineN20
#defineplaynext'q'
#defineexit27
intm=1;/*游戏循环控制*/
intcount=1;/*回合计数器*/
intt=0;/*代表坐标交叉点有无棋子的状态*/
intflag=1;/*输赢标志符*/
intp[N][N];/*记录棋盘落子情况*/
charq[N][N];/*记录棋盘交叉点棋子种类*/
structzuobiao/*坐标位置*/
{
intx;
inty;
}weizhi;
//------------------
voidgotoxy(intx,inty)/*建立坐标函数*/
COORDc;
c.X=x;
c.Y=y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),c);
}
//-------------------
voiddrawqipan()/*建立棋盘*/
inti,j;
for(i=0;i{for(j=0;j{p[i][j]=0;q[i][j]='o';printf("╋");}printf("\n");}}//--------------------voidmovegb(charpress)/*光标的移动*/{switch(press){caseplay1up:if(weizhi.y>-1)weizhi.y--;if(weizhi.y<0)weizhi.y=19;break;/*玩家1光标向下移动*/caseplay1down:if(weizhi.y<20)weizhi.y++;if(weizhi.y>19)weizhi.y=0;break;/*玩家1光标向上移动*/caseplay1left:if(weizhi.x>-1)weizhi.x--;if(weizhi.x<0)weizhi.x=19;break;/*玩家1光标向左移动*/caseplay1right:if(weizhi.x<20)weizhi.x++;if(weizhi.x>19)weizhi.x=0;break;/*玩家1光标向右移动*/caseplay2up:if(weizhi.y>-1)weizhi.y--;if(weizhi.y<0)weizhi.y=19;break;/*玩家2光标向上移动*/caseplay2down:if(weizhi.y<20)weizhi.y++;if(weizhi.y>19)weizhi.y=0;break;/*玩家2光标向下移动*/caseplay2left:if(weizhi.x>-1)weizhi.x--;if(weizhi.x<0)weizhi.x=19;break;/*玩家2光标向左移动*/caseplay2right:if(weizhi.x<20)weizhi.x++;if(weizhi.x>19)weizhi.x=0;break;/*玩家2光标向右移动*/default:return;}gotoxy(2*(weizhi.x),weizhi.y);return;}//------------------------------voidluozi(charpress)/*落子*/{if(press==play1lq){if(t==0&&p[weizhi.x][weizhi.y]==0){printf("●");gotoxy(2*weizhi.x,weizhi.y);q[weizhi.x][weizhi.y]=press;p[weizhi.x][weizhi.y]=1;t=1;count++;}}if(press==play2lq){if(t==1&&p[weizhi.x][weizhi.y]==0){printf("○");gotoxy(2*weizhi.x,weizhi.y);q[weizhi.x][weizhi.y]=press;p[weizhi.x][weizhi.y]=1;t=0;count++;}}}//--------------------------voidjudgewin(charpress)/*判断输赢*/{inti,count1,count2=0,count3=0;structzuobiaop;for(i=0;i<4;i++){for(count1=4;count1>=-4;count1--){switch(i){case0:p.x=weizhi.x-count1;p.y=weizhi.y;break;/*从左往右判断是否有五子连续在一直线上*/case1:p.x=weizhi.x;p.y=weizhi.y+count1;break;/*从上往下判断是否有五子连续在一直线上*/case2:p.x=weizhi.x-count1;p.y=weizhi.y+count1;break;/*从左上往右下判断是否有五子连续在一直线上*/case3:p.x=weizhi.x-count1;p.y=weizhi.y-count1;break;/*从左下往右上判断是否有五子连续在一直线上*/}if(p.x>=0&&p.y>=0){if(q[p.x][p.y]==play1lq){count2++;count3=0;}if(q[p.x][p.y]==play2lq){count3++;count2=0;}}}if(count2>=5){gotoxy(2*22,8);flag=0;printf("黑棋胜!");gotoxy(0,21);printf("Playagainpress'q',andpress'Esc'escape!\n");break;}elsecount2=0;if(count3>=5){gotoxy(2*22,8);flag=0;printf("白棋胜!");gotoxy(0,21);printf("Playagainpress'q',andpress'Esc'escape!\n");break;}elsecount3=0;}}//-------------------------------------------voidInitData()/*数据初始化*/{system("cls");drawqipan();count=1;t=0;flag=1;weizhi.x=0;weizhi.y=0;gotoxy(0,0);}//--------------------------------------------intStartGame()/*游戏开始界面*/{charch;system("COLOR74");printf("\n");printf("☆五子棋游戏☆\n\n");printf("五子棋游戏操作规则:\n");printf("●按键说明:玩家一,W、S、A、D分别为上、下、左、右,Z为确定落棋\n");printf("玩家二,↑、↓、←、→分别为上、下、左、右,空格键为确定落棋。\n");printf("●Q键为重新开始,按Esc键退出。\n");printf("●禁止在棋盘外按空格。\n\n");printf("你是否接受上述的游戏规则(Y/N):");ch=getch();while(ch!='Y'&&ch!='y'&&ch!='N'&&ch!='n'){ch=getch();}if(ch=='Y'||ch=='y'){putchar(ch);getch();putchar('\n');return1;}{putch(ch);putchar('\n');return0;}}//---------------------------------voidmain()/*主函数*/{charpress;if(StartGame()){system("cls");system("COLOR30");/*背景颜色和前景颜色*/drawqipan();gotoxy(0,0);while(m){if(count%2&&flag){gotoxy(2*22,8);printf("黑棋走!");gotoxy(2*weizhi.x,weizhi.y);}if(count%2==0&&flag){gotoxy(2*22,8);printf("白棋走!");gotoxy(2*weizhi.x,weizhi.y);}press=getch();if(count%2&&(press!=play1up&&press!=play1down&&press!=play1left&&press!=play1right&&press!=play1lq&&press!=playnext&&press!=exit))continue;if(!(count%2)&&(press!=play2up&&press!=play2down&&press!=play2left&&press!=play2right&&press!=play2lq&&press!=playnext&&press!=exit))continue;if(flag==0&&press!=playnext&&press!=exit)continue;movegb(press);switch(press){caseplay1lq:caseplay2lq:luozi(press);judgewin(press);break;caseplaynext:InitData();break;caseexit:m=0;break;default:break;}}}}五、程序运行的测试与分析开始用的是getchar()函数接收命令,当玩家输入的不是Y(y)/N(n)时的效果如下图, 此时考虑采用不回显的方式输入命令,这里用getch()函数,只有当玩家输入正确的命令时才会显示到屏幕上。另一个问题出现了,当进入游戏界面,显示棋盘后,光标的位置在左上角,这是因为源代码设置的光标的初始位置为(0,0)坐标。为了解决这个问题,于是调用system(“cls”)函数清屏,这样棋盘的位置就在左上再进一步修改一下界面,达到如下效果:进入游戏发现双方可以同时控制光标的移动,分析了代码知道,在接收了键盘的数据后,直接就调用了‘movgb()’函数,没用对‘press’进行分析过滤加入过滤条件再调试这时虽然能实现对另一方按键的限制,但是又有很多问题。比如玩家一连续按两次‘Z’键(即落棋后又按了一下‘Z’),接下来应该是玩家二控制键盘的,而实际却只有玩家一才能控制。再回过去分析代码:变量count是记录回合的,根据‘count%2’的结果判断该哪一方走棋,如果为1就该玩家一走,否则是玩家二走。问题出在count计数上,因为只要press等于Z’或‘空格’count计数就加1,玩家一按了两次‘Z’‘count%2==1’,所以又该玩家一走修改代码,把上图count计数器移动到‘luozi()’函数中,这个问题解决了。这下应该没问题了吧?进一步测试又出现了Bug,当玩家输入’q’重新开始游戏,按键的控制不单有上面类似的情况,而且光标不是在(0,0)位置,根据以往用软件的体会,一般软件启动时都会有个数据初始化过程,按照这个思路来解决这里的问题会比较容易了。于是再定义一个’InitData()’函数,将部分全局变量初始化,果然效果是立竿见影,至此,还没有再发现有什么Bug。最后,又优化了一下游戏界面,添加了提示文字,最终得到下面的运行效果。 六、结论与心得这次程序设计让我感到自己了解的知识是多么的有限,要想写一个比较大的程序,用到的库函数很多,而这些在平时的练习中又没有涉及到,也因此让我收获不少。现在对C语言模块化设计的好处有了更深的体会,不仅使程序更加易读,逻辑清晰,在代码修改时也容易了许多。这次设计巩固了我的知识点,也锻炼了我的调试能力。其实这次也让我感觉到C语言也挺有趣的,让我对C语言的兴趣更加浓厚。并且C语言编程也不是想象中的那么难,因而也让我的心里障碍减少了很多。七、参考资料XX知道CSDN论坛新浪资料共享《C语言程序设计》(杨路明主编)八、致谢CSDN论坛网友
for(j=0;j{p[i][j]=0;q[i][j]='o';printf("╋");}printf("\n");}}//--------------------voidmovegb(charpress)/*光标的移动*/{switch(press){caseplay1up:if(weizhi.y>-1)weizhi.y--;if(weizhi.y<0)weizhi.y=19;break;/*玩家1光标向下移动*/caseplay1down:if(weizhi.y<20)weizhi.y++;if(weizhi.y>19)weizhi.y=0;break;/*玩家1光标向上移动*/caseplay1left:if(weizhi.x>-1)weizhi.x--;if(weizhi.x<0)weizhi.x=19;break;/*玩家1光标向左移动*/caseplay1right:if(weizhi.x<20)weizhi.x++;if(weizhi.x>19)weizhi.x=0;break;/*玩家1光标向右移动*/caseplay2up:if(weizhi.y>-1)weizhi.y--;if(weizhi.y<0)weizhi.y=19;break;/*玩家2光标向上移动*/caseplay2down:if(weizhi.y<20)weizhi.y++;if(weizhi.y>19)weizhi.y=0;break;/*玩家2光标向下移动*/caseplay2left:if(weizhi.x>-1)weizhi.x--;if(weizhi.x<0)weizhi.x=19;break;/*玩家2光标向左移动*/caseplay2right:if(weizhi.x<20)weizhi.x++;if(weizhi.x>19)weizhi.x=0;break;/*玩家2光标向右移动*/default:return;}gotoxy(2*(weizhi.x),weizhi.y);return;}//------------------------------voidluozi(charpress)/*落子*/{if(press==play1lq){if(t==0&&p[weizhi.x][weizhi.y]==0){printf("●");gotoxy(2*weizhi.x,weizhi.y);q[weizhi.x][weizhi.y]=press;p[weizhi.x][weizhi.y]=1;t=1;count++;}}if(press==play2lq){if(t==1&&p[weizhi.x][weizhi.y]==0){printf("○");gotoxy(2*weizhi.x,weizhi.y);q[weizhi.x][weizhi.y]=press;p[weizhi.x][weizhi.y]=1;t=0;count++;}}}//--------------------------voidjudgewin(charpress)/*判断输赢*/{inti,count1,count2=0,count3=0;structzuobiaop;for(i=0;i<4;i++){for(count1=4;count1>=-4;count1--){switch(i){case0:p.x=weizhi.x-count1;p.y=weizhi.y;break;/*从左往右判断是否有五子连续在一直线上*/case1:p.x=weizhi.x;p.y=weizhi.y+count1;break;/*从上往下判断是否有五子连续在一直线上*/case2:p.x=weizhi.x-count1;p.y=weizhi.y+count1;break;/*从左上往右下判断是否有五子连续在一直线上*/case3:p.x=weizhi.x-count1;p.y=weizhi.y-count1;break;/*从左下往右上判断是否有五子连续在一直线上*/}if(p.x>=0&&p.y>=0){if(q[p.x][p.y]==play1lq){count2++;count3=0;}if(q[p.x][p.y]==play2lq){count3++;count2=0;}}}if(count2>=5){gotoxy(2*22,8);flag=0;printf("黑棋胜!");gotoxy(0,21);printf("Playagainpress'q',andpress'Esc'escape!\n");break;}elsecount2=0;if(count3>=5){gotoxy(2*22,8);flag=0;printf("白棋胜!");gotoxy(0,21);printf("Playagainpress'q',andpress'Esc'escape!\n");break;}elsecount3=0;}}//-------------------------------------------voidInitData()/*数据初始化*/{system("cls");drawqipan();count=1;t=0;flag=1;weizhi.x=0;weizhi.y=0;gotoxy(0,0);}//--------------------------------------------intStartGame()/*游戏开始界面*/{charch;system("COLOR74");printf("\n");printf("☆五子棋游戏☆\n\n");printf("五子棋游戏操作规则:\n");printf("●按键说明:玩家一,W、S、A、D分别为上、下、左、右,Z为确定落棋\n");printf("玩家二,↑、↓、←、→分别为上、下、左、右,空格键为确定落棋。\n");printf("●Q键为重新开始,按Esc键退出。\n");printf("●禁止在棋盘外按空格。\n\n");printf("你是否接受上述的游戏规则(Y/N):");ch=getch();while(ch!='Y'&&ch!='y'&&ch!='N'&&ch!='n'){ch=getch();}if(ch=='Y'||ch=='y'){putchar(ch);getch();putchar('\n');return1;}{putch(ch);putchar('\n');return0;}}//---------------------------------voidmain()/*主函数*/{charpress;if(StartGame()){system("cls");system("COLOR30");/*背景颜色和前景颜色*/drawqipan();gotoxy(0,0);while(m){if(count%2&&flag){gotoxy(2*22,8);printf("黑棋走!");gotoxy(2*weizhi.x,weizhi.y);}if(count%2==0&&flag){gotoxy(2*22,8);printf("白棋走!");gotoxy(2*weizhi.x,weizhi.y);}press=getch();if(count%2&&(press!=play1up&&press!=play1down&&press!=play1left&&press!=play1right&&press!=play1lq&&press!=playnext&&press!=exit))continue;if(!(count%2)&&(press!=play2up&&press!=play2down&&press!=play2left&&press!=play2right&&press!=play2lq&&press!=playnext&&press!=exit))continue;if(flag==0&&press!=playnext&&press!=exit)continue;movegb(press);switch(press){caseplay1lq:caseplay2lq:luozi(press);judgewin(press);break;caseplaynext:InitData();break;caseexit:m=0;break;default:break;}}}}五、程序运行的测试与分析开始用的是getchar()函数接收命令,当玩家输入的不是Y(y)/N(n)时的效果如下图, 此时考虑采用不回显的方式输入命令,这里用getch()函数,只有当玩家输入正确的命令时才会显示到屏幕上。另一个问题出现了,当进入游戏界面,显示棋盘后,光标的位置在左上角,这是因为源代码设置的光标的初始位置为(0,0)坐标。为了解决这个问题,于是调用system(“cls”)函数清屏,这样棋盘的位置就在左上再进一步修改一下界面,达到如下效果:进入游戏发现双方可以同时控制光标的移动,分析了代码知道,在接收了键盘的数据后,直接就调用了‘movgb()’函数,没用对‘press’进行分析过滤加入过滤条件再调试这时虽然能实现对另一方按键的限制,但是又有很多问题。比如玩家一连续按两次‘Z’键(即落棋后又按了一下‘Z’),接下来应该是玩家二控制键盘的,而实际却只有玩家一才能控制。再回过去分析代码:变量count是记录回合的,根据‘count%2’的结果判断该哪一方走棋,如果为1就该玩家一走,否则是玩家二走。问题出在count计数上,因为只要press等于Z’或‘空格’count计数就加1,玩家一按了两次‘Z’‘count%2==1’,所以又该玩家一走修改代码,把上图count计数器移动到‘luozi()’函数中,这个问题解决了。这下应该没问题了吧?进一步测试又出现了Bug,当玩家输入’q’重新开始游戏,按键的控制不单有上面类似的情况,而且光标不是在(0,0)位置,根据以往用软件的体会,一般软件启动时都会有个数据初始化过程,按照这个思路来解决这里的问题会比较容易了。于是再定义一个’InitData()’函数,将部分全局变量初始化,果然效果是立竿见影,至此,还没有再发现有什么Bug。最后,又优化了一下游戏界面,添加了提示文字,最终得到下面的运行效果。 六、结论与心得这次程序设计让我感到自己了解的知识是多么的有限,要想写一个比较大的程序,用到的库函数很多,而这些在平时的练习中又没有涉及到,也因此让我收获不少。现在对C语言模块化设计的好处有了更深的体会,不仅使程序更加易读,逻辑清晰,在代码修改时也容易了许多。这次设计巩固了我的知识点,也锻炼了我的调试能力。其实这次也让我感觉到C语言也挺有趣的,让我对C语言的兴趣更加浓厚。并且C语言编程也不是想象中的那么难,因而也让我的心里障碍减少了很多。七、参考资料XX知道CSDN论坛新浪资料共享《C语言程序设计》(杨路明主编)八、致谢CSDN论坛网友
{p[i][j]=0;q[i][j]='o';
printf("╋");
printf("\n");
//--------------------
voidmovegb(charpress)/*光标的移动*/
switch(press)
caseplay1up:
if(weizhi.y>-1)weizhi.y--;if(weizhi.y<0)weizhi.y=19;break;/*玩家1光标向下移动*/
caseplay1down:
if(weizhi.y<20)weizhi.y++;if(weizhi.y>19)weizhi.y=0;break;/*玩家1光标向上移动*/
caseplay1left:
if(weizhi.x>-1)weizhi.x--;if(weizhi.x<0)weizhi.x=19;break;/*玩家1光标向左移动*/
caseplay1right:
if(weizhi.x<20)weizhi.x++;if(weizhi.x>19)weizhi.x=0;break;/*玩家1光标向右移动*/
caseplay2up:
if(weizhi.y>-1)weizhi.y--;if(weizhi.y<0)weizhi.y=19;break;/*玩家2光标向上移动*/
caseplay2down:
if(weizhi.y<20)weizhi.y++;if(weizhi.y>19)weizhi.y=0;break;/*玩家2光标向下移动*/
caseplay2left:
if(weizhi.x>-1)weizhi.x--;if(weizhi.x<0)weizhi.x=19;break;/*玩家2光标向左移动*/
caseplay2right:
if(weizhi.x<20)weizhi.x++;if(weizhi.x>19)weizhi.x=0;break;/*玩家2光标向右移动*/
default:
return;
gotoxy(2*(weizhi.x),weizhi.y);
//------------------------------
voidluozi(charpress)/*落子*/
if(press==play1lq)
{if(t==0&&p[weizhi.x][weizhi.y]==0)
printf("●");gotoxy(2*weizhi.x,weizhi.y);
q[weizhi.x][weizhi.y]=press;
p[weizhi.x][weizhi.y]=1;t=1;
count++;
if(press==play2lq)
{if(t==1&&p[weizhi.x][weizhi.y]==0)
printf("○");gotoxy(2*weizhi.x,weizhi.y);
p[weizhi.x][weizhi.y]=1;
t=0;
//--------------------------
voidjudgewin(charpress)/*判断输赢*/
inti,count1,count2=0,count3=0;
structzuobiaop;
for(i=0;i<4;i++)
for(count1=4;count1>=-4;count1--)
{switch(i)
case0:
p.x=weizhi.x-count1;p.y=weizhi.y;break;/*从左往右判断是否有五子连续在一直线上*/
case1:
p.x=weizhi.x;p.y=weizhi.y+count1;break;/*从上往下判断是否有五子连续在一直线上*/
case2:
p.x=weizhi.x-count1;p.y=weizhi.y+count1;break;/*从左上往右下判断是否有五子连续在一直线上*/
case3:
p.x=weizhi.x-count1;p.y=weizhi.y-count1;break;/*从左下往右上判断是否有五子连续在一直线上*/
if(p.x>=0&&p.y>=0)
if(q[p.x][p.y]==play1lq)
{count2++;count3=0;}if(q[p.x][p.y]==play2lq)
{count3++;count2=0;}
if(count2>=5)
{gotoxy(2*22,8);flag=0;printf("黑棋胜!
");gotoxy(0,21);printf("Playagainpress'q',andpress'Esc'escape!
\n");break;}
elsecount2=0;
if(count3>=5)
{gotoxy(2*22,8);flag=0;printf("白棋胜!
elsecount3=0;
//-------------------------------------------
voidInitData()/*数据初始化*/
system("cls");
drawqipan();
count=1;
flag=1;
weizhi.x=0;weizhi.y=0;
gotoxy(0,0);
//--------------------------------------------
intStartGame()/*游戏开始界面*/
charch;
system("COLOR74");
printf("☆五子棋游戏☆\n\n");
printf("五子棋游戏操作规则:
\n");
printf("●按键说明:
玩家一,W、S、A、D分别为上、下、左、右,Z为确定落棋\n");
printf("玩家二,↑、↓、←、→分别为上、下、左、右,空格键为确定落棋。
printf("●Q键为重新开始,按Esc键退出。
printf("●禁止在棋盘外按空格。
\n\n");
printf("你是否接受上述的游戏规则(Y/N):
");
ch=getch();
while(ch!
='Y'&&ch!
='y'&&ch!
='N'&&ch!
='n')
if(ch=='Y'||ch=='y')
{putchar(ch);
getch();
putchar('\n');
return1;
putch(ch);
return0;
//---------------------------------
voidmain()/*主函数*/
charpress;
if(StartGame()){
system("COLOR30");/*背景颜色和前景颜色*/
while(m)
if(count%2&&flag){gotoxy(2*22,8);printf("黑棋走!
");gotoxy(2*weizhi.x,weizhi.y);}
if(count%2==0&&flag){gotoxy(2*22,8);printf("白棋走!
press=getch();
if(count%2&&(press!
=play1up&&press!
=play1down&&press!
=play1left&&press!
=play1right&&
press!
=play1lq&&press!
=playnext&&press!
=exit))
continue;
if(!
(count%2)&&(press!
=play2up&&press!
=play2down&&press!
=play2left&&press!
=play2right
&&press!
=play2lq&&press!
if(flag==0&&press!
=exit)continue;
movegb(press);
caseplay1lq:
caseplay2lq:
luozi(press);judgewin(press);break;
caseplaynext:
InitData();break;
caseexit:
m=0;break;
break;
五、程序运行的测试与分析
开始用的是getchar()函数接收命令,当玩家输入的不是Y(y)/N(n)时的效果如下图,
此时考虑采用不回显的方式输入命令,这里用getch()函数,只有当玩家输入正确的命令时才会显示到屏幕上。
另一个问题出现了,当进入游戏界面,显示棋盘后,光标的位置
在左上角,这是因为源代码设置的光标的初始位置为(0,0)坐标。
为了解决这个问题,于是调用system(“cls”)函数清屏,这样棋盘的位置就在左上
再进一步修改一下界面,达到如下效果:
进入游戏发现双方可以同时控制光标的移动,分析了代码知道,在接收了键盘的数据后,直接就调用了‘movgb()’函数,没用对‘press’进行分析过滤
加入过滤条件再调试
这时虽然能实现对另一方按键的限制,但是又有很多问题。
比如玩家一连续按两次‘Z’键(即落棋后又按了一下‘Z’),接下来应该是玩家二控制键盘的,而实际却只有玩家一才能控制。
再回过去分析代码:
变量count是记录回合的,根据‘count%2’的结果判断该哪一方走棋,如果为1就该玩家一走,否则是玩家二走。
问题出在count计数上,因为只要press等于Z’或‘空格’count计数就加1,玩家一按了两次‘Z’‘count%2==1’,所以又该玩家一走
修改代码,把上图count计数器移动到‘luozi()’函数中,这个问题解决了。
这下应该没问题了吧?
进一步测试又出现了Bug,当玩家输入’q’重新开始游戏,按键的控制不单有上面类似的情况,而且光标不是在(0,0)位置,根据以往用软件的体会,一般软件启动时都会有个数据初始化过程,按照这个思路来解决这里的问题会比较容易了。
于是再定义一个’InitData()’函数,将部分全局变量初始化,果然效果是立竿见影,至此,还没有再发现有什么Bug。
最后,又优化了一下游戏界面,添加了提示文字,最终得到下面的运行效果。
六、结论与心得
这次程序设计让我感到自己了解的知识是多么的有限,要想写一个比较大的程序,用到的库函数很多,而这些在平时的练习中又没有涉及到,也因此让我收获不少。
现在对C语言模块化设计的好处有了更深的体会,不仅使程序更加易读,逻辑清晰,在代码修改时也容易了许多。
这次设计巩固了我的知识点,也锻炼了我的调试能力。
其实这次也让我感觉到C语言也挺有趣的,让我对C语言的兴趣更加浓厚。
并且C语言编程也不是想象中的那么难,因而也让我的心里障碍减少了很多。
七、参考资料
XX知道
CSDN论坛
新浪资料共享
《C语言程序设计》(杨路明主编)
八、致谢
CSDN论坛网友
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1