五⼦棋程序设计(C语⾔、⼈机对战、禁⼿)
五⼦棋程序设计(C语⾔、⼈机对战、禁⼿)
⼀、程序需求分析
1.1五⼦棋简介
双因素方差分析法五⼦棋是全国智⼒运动会竞技项⽬之⼀,是⼀种两⼈对弈的纯策略型棋类游戏。 五⼦棋有两种玩法。玩法⼀:双⽅分别使⽤⿊⽩两⾊的棋⼦,下在棋盘直线与横线的交叉点上,先形成五⼦连线者获胜。玩法⼆:⾃⼰形成五⼦连线就替换对⽅任意⼀枚棋⼦。被替换的棋⼦可以和对⽅交换棋⼦。最后以先出完所有棋⼦的⼀⽅为胜。我们本次程序设计采⽤的玩法是第⼀种玩法。 传统五⼦棋的棋具与围棋相同,棋⼦分为⿊⽩两⾊,棋盘为15×15,棋⼦放置于棋盘线交叉点上。两⼈对局,各执⼀⾊,轮流下⼀⼦,先将横、竖或斜线的5个或5个以上同⾊棋⼦连成不间断的⼀排者为胜。
1.2程序设计要求
本程序设计要求游戏功能有⼈与⼈对弈和⼈机对弈,并要求⿊棋有禁⼿规则。游戏需要实现功能是游戏
双⽅⼀⽅执⿊棋,⼀⽅执⽩棋,轮流⾛棋,每⽅都试图在游戏结束前让⾃⼰的棋⼦五⼦相连,⾸先实现五⼦相连的⼀⽅获胜。程序执⾏过程中,要求棋盘、棋⼦时时可见,并且⼈可以通过按键盘按键摆放棋⼦。
1.3程序需求分析
根据功能需求,将程序分为棋盘显⽰、玩家控制、胜负判断、⼈机对战和机器⼈落⼦计分五个模块,以下分析各模块的需求。 棋盘显⽰模块:游戏开始后要求⽣成15×15的棋盘图像,游戏下⽅显⽰0、退出,1、电脑VS玩家,2、玩家VS玩家三种选择,当⽤户选择后,进去下棋界⾯,要求实时显⽰棋盘上已落下的棋⼦;分出胜负后,要求给出游戏结束画⾯。
玩家控制模块:程序开始时,需玩家确定⽽后开始游戏;游戏过程中,两个玩家通过键盘,选择落⼦。
胜负判断模块:实时监测棋盘上棋⼦,⼀旦某⼀⾊棋⼦出现五⼦连线,终⽌游戏程序,并着⾊连成⼀线的五⼦,弹出该⾊玩家胜出界⾯。
⼈机对战模块:程序设计需要拥有⼈机对战模块。
机器⼈落⼦计分模块:这个模块是通过计算机器⼈下每⼀步棋⼦的得分情况,来让⼈机对战是机器⼈更加聪明。
1.4程序整体设计流程图
⼆、玩家与玩家对战设计思路及主要程序
2.1设计思路
现在我想先说⼀说玩家对战部分的实现思路,因为这⼀部分的实现会简单很多。⽽⼈机对战规则和代码⽐较复杂留在下⼀点分析,因为⼈机对战这⼀部分涉及策略的问题,这包含⼏个层次,⽐如让电脑空位随机落⼦,更进⼀步可以在对⽅活三或其他情况的棋⼦附近随机落⼦;更⾼级的策略可以让计算机考虑到更多的情况和步骤,但是程序也会复杂很多。
第⼀步,显⽰棋盘。绘制出来的棋盘如下:
第⼆步,执⾏落⼦。这个过程我们使⽤了playermove(int **state, int row, int column, int order)这个函数让玩家执⾏落⼦。当玩家输⼊要下的位置的坐标的时候,棋⼦坐标就会被写⼊state[x][y]数组内,然后重新显⽰棋盘,棋盘上就会出现棋⼦。如果输⼊的坐标上已经有棋⼦了,会提⽰“该位置已经有棋⼦了,请下别的位置”。落⼦过程如下:
当完成上⾯两个步骤之后剩下的就是判断⿊棋是否有禁⼿和判断双⽅胜负的函数的编写了,这两个函数我会在第四段单独讲解。
2.2设计流程图
2.3主要程序代码
int main()
{
while(1)
{
order = 1;
int i,j;
//int *board;
//1⿊⽅,2⽩⽅;规则是⿊⽅先⾛,但⿊⽅会有禁⼿board = malloc(sizeof(int)*ROW);
for(i = 0; i < ROW; i++)
board[i] = malloc(sizeof(int)*COLUMN);
for(i = 0; i < ROW; i++)
for(j = 0; j < COLUMN; j++)
board[i][j] = 0;
draw(board, ROW, COLUMN);
int P=ChoiceMode();
余热锅炉if(P2) //玩家VS玩家
while(1)
{
playermove(board, ROW, COLUMN, order); draw(board, ROW, COLUMN);
if(z1)
{
if(order1)
printf(“⿊⽅胜利!”);
else
printf(“⽩⽅胜利!”);
z=0;
break;
}
else if(z-1)
{
printf(“和棋!”);
z=0;
break;
}
else if(z==-2)
{
printf(“⿊⽅禁⼿犯规!⽩⽅胜利!”);
}
else
;
order = order%2+1;
}
}
else
break;
system("pause");
for(i = 0; i < ROW; i++)
free(board[i]);
free(board);
}
return 0;
}
男医生与女病人
三、⼈机对战设计思路及主要程序
3.1设计思路
⾸先在main函数⾥选择玩家VS电脑,调⽤不同的函数。轮到电脑下⼦时,基本思路就是遍历棋盘上的每⼀个空位,并逐个计算价值量,寻价值量最⼤的那个位置,并将这个位置传回score函数中进⾏价值量的⽐较,并且最终进⾏电脑的下⼦。 每到⼀个空档,⾸先逐⼀检查它上、下、左、右、左上、左下、右上、右下⼋个⽅位是否有棋⼦。例如该空档上⽅向⽆⼦则跳过价值量为零,检查到左下发现有棋⼦,则继续查看有⼏个棋⼦,从是否有⼀个颜⾊相同的棋⼦开始,⼀直到有四个棋⼦,逐⼀累加价值量,每次应判断这些棋⼦的颜⾊是否和电脑⾃⼰的颜⾊相同,有相同、不同两种情况,两者所叠加的价值量不同,然后再判断这⼏个颜⾊相同的棋⼦组成的这条线的下⼀个位置是否有棋⼦,有颜⾊相同、不同、⽆棋⼦三种情况,三者所叠加的价值量不同。
另外为了使价值量的区别更⼤,更容易把控,判断出不同数量的连续棋⼦后会先加不同的权重,数量越多,权重指数级增长。另外,为了区分活三和连四两种特殊情况,为它们单独加了极⼤的价值量,⽅便电脑判断。
3.2设计流程图
3.3主要程序代码
int main()
{
while(1)
{
order = 1;
int i,j;
//int *board;
//1⿊⽅,2⽩⽅;规则是⿊⽅先⾛,但⿊⽅会有禁⼿board = malloc(sizeof(int)*ROW);
for(i = 0; i < ROW; i++)
board[i] = malloc(sizeof(int)*COLUMN);
for(i = 0; i < ROW; i++)
for(j = 0; j < COLUMN; j++)
board[i][j] = 0;
draw(board, ROW, COLUMN);
qc工程图int P=ChoiceMode();
王安忆佳
if(P1) //⼈机
{
While(1)
{ playermove(board, ROW, COLUMN, order); draw(board, ROW, COLUMN);
if(z1)
{
if(order1)
printf(“⿊⽅胜利!”);
else
printf(“⽩⽅胜利!”);
z=0;
break;
}
else if(z-1)
{
printf(“和棋!”);
z=0;微分算子
break;
}
else if(z==-2)
{
printf(“⿊⽅禁⼿犯规!⽩⽅胜利!”);
}
else
;
order = order%2+1;
actionByAI(board,ROW,COLUMN);
draw(board, ROW, COLUMN);
if(z==1)
{
if(order==1)
printf("⿊⽅胜利!");
else
printf("⽩⽅胜利!");
z=0;
break;
}
else if(z==-1)
{
printf("和棋!");
z=0;
break;
}
else if(z==-2)
{
printf("⿊⽅禁⼿犯规!⽩⽅胜利!");
}
else
;
order = order%2+1;
}
}
四、关键函数的讲解
2.1棋盘显⽰
我们要先绘制出⼀个1515的棋盘。为此,⽤⼀个1515的⼆维数组来储存棋盘上每⼀个位置的信息(应包括此处为空或者有⽩⼦或⿊⼦),把这个数组命名为state,其中每⼀个元素表⽰为state[ i ][ j ]。棋盘是完全由制表符组成的。因此,我们需要将数组board存储的数值与制表符进⾏⼀个对应。弄清了棋盘每⼀个位置的信息的储存⽅式后,我们就需要⼀个函数,读取实时的棋盘信息,并根据读取到的信息绘制棋盘,并且使得棋盘的每⼀个位置能直观地读取到坐标,我们把这个函数命名为void draw(int **state, int row, int column),棋盘显⽰如下: