五子棋程序设计(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;}}elsebreak;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);
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("黑方胜利!");elseprintf("白方胜利!");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),棋盘显示如下:

函数具体内容如下:
void draw(int **state, int row, int column)
{
system(“cls”); //ÇåÆÁ
int i,j;
printf(" “);
for (i = 0; i < column; i++)
printf(”%c “, (char)(i+65));
printf(”\n");
for (i = 0; i < row; i++)
{
printf("%c “, (char)(i+65));
for (j = 0; j < column; j++)
{
switch(state[i][j])
{
case 0:
if (j > 0 && j < column-1)
printf(”%s", (i == 0 ? TOP_CENTER : i == row-1? BOTTOM_CENTER : INTERNAL));
else if (j == 0)
printf("%s", (i == 0 ? LEFT_TOP : i == row-1 ? LEFT_BOTTOM : LEFT_CENTER));
else if(j == column-1)
printf("%s", (i == 0 ? RIGHT_TOP : i == row-1 ? RIGHT_BOTTOM : RIGHT_CENTER));
break;
case 1:
printf("%s", BLACK);
break;
case 2:
printf("%s", WHITE);
break;
default:
break;
}
}
printf("\n");
}
}

2.2判断胜负
这是整个程序中需要考虑的情况最多的一个部分。我们既需要考虑横向棋子的布局,还需要考虑纵向,更复杂的是还需要考虑斜率分别为-1和1的直线上的落子情况。
横向和纵向的判断容易理解,斜向的会复杂一些,尤其是在靠近四个角落的地方,因为我们需要保证有足够的空间使得能够有五颗棋子连成一条线,因此在考虑斜向时我又将每种斜率的直线分为了两种情况。
主要代码见附录1

2.3黑棋禁手
黑棋禁手规则:五子棋术语,指对局中禁止先行一方(黑方)使用的战术,具体包括黑方一子落下时同时形成双活三、双四或长连等三种棋形。禁手只对黑方有效,白方无禁手。黑方禁手的位置称为禁手点。
禁手的分类有三种,分别是三三禁手、四四禁手和长连禁手。三三禁手的意思是黑方一子落下同时形成两个或两个以上的活三(或嵌四),此步为三三禁手。 注意:这里一定要两个都是 “活”三才能算。“四三三”指黑方一步使一个四、两个活三同时形成,事实上是一种特殊的三三禁手。四四禁手的意思是黑方一子落下同时形成两个或两个以上的四。活四、冲四、嵌五之四,包括在此四之内。此步为四四禁手。注意:只要是两个“四”即为禁手,无论是活四、冲四都算。“四四三”指黑方一步使两个四、一个活三同时形成,事实上是一种特殊的四四禁手。长连禁手的意思是黑方一子落下形成连续六子或六子以上相连。注意:白棋出现长连与连五同等作用,即白棋出现长连也将获胜。
当充分了解黑棋禁手规则后,就可以编写黑棋禁手函数了,函数主要代码如下:
for (int i = begin0, j = begin1; (i + 4 <= end0) && (j - 4 >= end1); ++i, --j)
{
if(order==1)
{
if (state[i][j] == flag&&state[i + 1][j - 1] == flag&&
state[i + 2][j - 2] == flag&&state[i + 3][j - 3] == flag&&
state[i + 4][j - 4] == flag&&state[i + 5][j - 5]==flag )
{
z=-2;
break;//长连
}
else if (state[i][j] == flag&&state[i + 1][j - 1] == flag&&
state[i + 2][j - 2] == flag&&state[i + 3][j - 3] == flag&&
state[i + 4][j - 4] == flag&&state[i - 1][j + 1]==flag )
{
z=-2;
break;//长连
}
}
if (state[i][j] == flag&&state[i + 1][j - 1] == flag&&
state[i + 2][j - 2] == flag&&state[i + 3][j - 3] == flag&&
state[i + 4][j - 4] == flag)
z=1;
}

五、附录
附录1
int JudgeVictory(int **state,int row,int column, int flag) //判断有没有人胜负(底层判断)
{
int begin0 = 0;
int end0 = 0;
int i,j;
int begin1 = 0;
int end1 = 0;

//判断行是否满足条件
if((column - 4) >=0)begin0 = (column - 4);
elsebegin0 = 1;
if((column + 4) >=N )end0 = N ;
elseend0 = (column + 4);for (i = row, j = begin0; j + 4 <= end0; j++)
{if(order==1){if (state[i][j] == flag&&state[i][j + 1] == flag&&    //长连state[i][j + 2] == flag&&state[i][j + 3] == flag&&state[i][j + 4] == flag&&state[i][j + 5]==flag){z=-2;break;}else if (state[i][j] == flag&&state[i][j + 1] == flag&&state[i][j + 2] == flag&&state[i][j + 3] == flag&&state[i][j + 4] == flag&&state[i][j - 1]==flag){z=-2;break;//长连}}if (state[i][j] == flag&&state[i][j + 1] == flag&&state[i][j + 2] == flag&&state[i][j + 3] == flag&&state[i][j + 4] == flag)z=1;
}//判断列是否满足条件
if((row - 4) >= 0 )begin0 = (row - 4) ;
elsebegin0 = 1;
if((row + 4) >= N )end0 = N ;
elseend0 = (row + 4);for (int j = column, i = begin0; i + 4 <= end0; i++)
{if(order==1){if (state[i][j] == flag&&state[i + 1][j] == flag&&state[i + 2][j] == flag&&state[i + 3][j] == flag&&state[i + 4][j] == flag&&state[i + 5][j]==flag ){z=-2;break;//长连}else if (state[i][j] == flag&&state[i + 1][j] == flag&&state[i + 2][j] == flag&&state[i + 3][j] == flag&&state[i + 4][j] == flag&&state[i -1][j]==flag ){z=-2;break;//长连}}if (state[i][j] == flag&&state[i + 1][j] == flag&&state[i + 2][j] == flag&&state[i + 3][j] == flag&&state[i + 4][j] == flag)z=1;
}int len = 0;//判断主对角线是否满足条件
if(row > column )len = column - 1 ;
elselen = row - 1;
if (len > 4)len = 4;
begin0 = row - len-1;       //横坐标的起始位置
begin1 = column - len-1;      //纵坐标的起始位置if(row > column )len = (N - row) ;
elselen = (N - column);
if (len>4)len = 4;
end0 = row + len-1;       //横坐标的结束位置
end1 = column + len-1;      //纵坐标的结束位置for (int i = begin0, j = begin1; (i + 4 <= end0) && (j + 4 <= end1); ++i, ++j)
{if(order==1){if (state[i][j] == flag&&state[i + 1][j + 1] == flag&&state[i + 2][j + 2] == flag&&state[i + 3][j + 3] == flag&&state[i + 4][j + 4] == flag&&state[i + 5][j + 5]==flag ){z=-2;break;//长连}else if (state[i][j] == flag&&state[i + 1][j + 1] == flag&&state[i + 2][j + 2] == flag&&state[i + 3][j + 3] == flag&&state[i + 4][j + 4] == flag&&state[i - 1][j - 1]==flag ){z=-2;break;//长连}}if (state[i][j] == flag&&state[i + 1][j + 1] == flag&&state[i + 2][j + 2] == flag&&state[i + 3][j + 3] == flag&&state[i + 4][j + 4] == flag)z=1;
}//判断副对角线是否满足条件
if( (row - 1) >(N - column) )len = (N - column) ;
elselen = row - 1;
if (len > 4)len = 4;
begin0 = row - len;       //横坐标的起始位置
begin1 = column + len;      //纵坐标的起始位置if((N - row) > (column - 1) )len = (column - 1) ;
elselen = (N - row);
if (len>4)len = 4;
end0 = row + len;       //横坐标的结束位置
end1 = column - len;      //纵坐标的结束位置//printf("%d  %d  %d  %d",begin0,begin1,end0,end1);
//system("pause");
for (int i = begin0, j = begin1; (i + 4 <= end0) && (j - 4 >= end1); ++i, --j)
{if(order==1){if (state[i][j] == flag&&state[i + 1][j - 1] == flag&&state[i + 2][j - 2] == flag&&state[i + 3][j - 3] == flag&&state[i + 4][j - 4] == flag&&state[i + 5][j - 5]==flag ){z=-2;break;//长连}else if (state[i][j] == flag&&state[i + 1][j - 1] == flag&&state[i + 2][j - 2] == flag&&state[i + 3][j - 3] == flag&&state[i + 4][j - 4] == flag&&state[i - 1][j + 1]==flag ){z=-2;break;//长连}}if (state[i][j] == flag&&state[i + 1][j - 1] == flag&&state[i + 2][j - 2] == flag&&state[i + 3][j - 3] == flag&&state[i + 4][j - 4] == flag)z=1;
}for (int i = 0; i < N ; ++i)           //棋盘有没有下满
{for (int j =0; j < N ; ++j){if (state[i][j] == 0)return 0;                      //0表示棋盘没满}
}
z=-1;
return 0;      //和棋

}

附录二:
全部程序代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>
//#include
//#include
#define ROW 15
#define COLUMN 15
#define LEFT_TOP “┌─”
#define LEFT_BOTTOM “└─”
#define LEFT_CENTER “├─”
#define RIGHT_TOP “┐”
#define RIGHT_BOTTOM “┘”
#define RIGHT_CENTER “┤”
#define TOP_CENTER “┬─”
#define BOTTOM_CENTER “┴─”
#define INTERNAL “┼─”
#define BLACK “○”
#define WHITE “●”
#define N 14
void draw(int **state, int row, int column);
void playermove(int **state, int row, int column, int order);
int JudgeVictory(int **state,int row,int column, int flag);
void turnComputer(int **state, int row, int column);
int **board;
int z=0;
int order = 1;
int computer=2;
int player=1;

int ret; //return

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(P==1)  //人机{while(1){playermove(board, ROW, COLUMN, order);draw(board, ROW, COLUMN);if(z==1){if(order==1)printf("黑方胜利!");elseprintf("白方胜利!");z=0;break;}else if(z==-1){printf("和棋!");z=0;break;}else if(z==-2){printf("黑方禁手犯规!白方胜利!");}else;order = order%2+1;turnComputer(board,ROW,COLUMN);draw(board, ROW, COLUMN);if(z==1){if(order==1)printf("黑方胜利!");elseprintf("白方胜利!");z=0;break;}else if(z==-1){printf("和棋!");z=0;break;}else if(z==-2){printf("黑方禁手犯规!白方胜利!");}else;order = order%2+1;}}else if(P==2){while(1){playermove(board, ROW, COLUMN, order);draw(board, ROW, COLUMN);if(z==1){if(order==1)printf("黑方胜利!");elseprintf("白方胜利!");z=0;break;}else if(z==-1){printf("和棋!");z=0;break;}else if(z==-2){printf("黑方禁手犯规!白方胜利!");}else;order = order%2+1;}}elsebreak;system("pause");for(i = 0; i < ROW; i++)free(board[i]);free(board);
}return 0;

}

void draw(int **state, int row, int column)
{
system(“cls”); //ÇåÆÁ
int i,j;
printf(" “);
for (i = 0; i < column; i++)
printf(”%c “, (char)(i+65));
printf(”\n");
for (i = 0; i < row; i++)
{
printf("%c “, (char)(i+65));
for (j = 0; j < column; j++)
{
switch(state[i][j])
{
case 0:
if (j > 0 && j < column-1)
printf(”%s", (i == 0 ? TOP_CENTER : i == row-1? BOTTOM_CENTER : INTERNAL));
else if (j == 0)
printf("%s", (i == 0 ? LEFT_TOP : i == row-1 ? LEFT_BOTTOM : LEFT_CENTER));
else if(j == column-1)
printf("%s", (i == 0 ? RIGHT_TOP : i == row-1 ? RIGHT_BOTTOM : RIGHT_CENTER));
break;
case 1:
printf("%s", BLACK);
break;
case 2:
printf("%s", WHITE);
break;
default:
break;
}
}
printf("\n");
}
}

void playermove(int **state, int row, int column, int order)
{
int x, y;
int j=0;
char a, b;
char str[100];
sprintf(str, “玩家%d-%s走”, order, order==1? “黑方” : “白方”);
printf("%s,如H行A列,则输入HA:", str);
while (1)
{
scanf("%c%c",&a,&b);
fflush(stdin); //清空输入缓冲
//while (getchar() != ‘\n’);
x = a - ‘A’;
y = b - ‘A’;
if(x >=0 && x <= row-1 && y >= 0 && y <= column-1)
{
if (state[x][y])
{
printf(“该位置已经有棋子了,请下别的位置:”);
continue;
}
else
{
state[x][y] = order;
break;
}
}
else
{
printf(“非法输入,请重新输入:”);
continue;
}
}
JudgeVictory(board,x,y,order);
//{
//printf(“下一步”);
// system(“pause”);
//}
}

int ChoiceMode() //选择模式
{
int i = 0;
printf(“0、退出 1、电脑vs玩家 2、玩家vs玩家”);
while (1)
{
printf(“请选择:”);
scanf("%d",&i);
if (i == 0) //选择0退出
exit(1);
if (i == 1 || i == 2)
return i;
printf(“输入不合法”);
}
}

int JudgeVictory(int **state,int row,int column, int flag) //判断有没有人胜负(底层判断)
{
int begin0 = 0;
int end0 = 0;
int i,j;
int begin1 = 0;
int end1 = 0;

//判断行是否满足条件
if((column - 4) >=0)begin0 = (column - 4);
elsebegin0 = 1;
if((column + 4) >=N )end0 = N ;
elseend0 = (column + 4);for (i = row, j = begin0; j + 4 <= end0; j++)
{if(order==1){if (state[i][j] == flag&&state[i][j + 1] == flag&&    //长连state[i][j + 2] == flag&&state[i][j + 3] == flag&&state[i][j + 4] == flag&&state[i][j + 5]==flag){z=-2;break;}else if (state[i][j] == flag&&state[i][j + 1] == flag&&state[i][j + 2] == flag&&state[i][j + 3] == flag&&state[i][j + 4] == flag&&state[i][j - 1]==flag){z=-2;break;//长连}}if (state[i][j] == flag&&state[i][j + 1] == flag&&state[i][j + 2] == flag&&state[i][j + 3] == flag&&state[i][j + 4] == flag)z=1;
}//判断列是否满足条件
if((row - 4) >= 0 )begin0 = (row - 4) ;
elsebegin0 = 1;
if((row + 4) >= N )end0 = N ;
elseend0 = (row + 4);for (int j = column, i = begin0; i + 4 <= end0; i++)
{if(order==1){if (state[i][j] == flag&&state[i + 1][j] == flag&&state[i + 2][j] == flag&&state[i + 3][j] == flag&&state[i + 4][j] == flag&&state[i + 5][j]==flag ){z=-2;break;//长连}else if (state[i][j] == flag&&state[i + 1][j] == flag&&state[i + 2][j] == flag&&state[i + 3][j] == flag&&state[i + 4][j] == flag&&state[i -1][j]==flag ){z=-2;break;//长连}}if (state[i][j] == flag&&state[i + 1][j] == flag&&state[i + 2][j] == flag&&state[i + 3][j] == flag&&state[i + 4][j] == flag)z=1;
}int len = 0;//判断主对角线是否满足条件
if(row > column )len = column - 1 ;
elselen = row - 1;
if (len > 4)len = 4;
begin0 = row - len-1;       //横坐标的起始位置
begin1 = column - len-1;      //纵坐标的起始位置if(row > column )len = (N - row) ;
elselen = (N - column);
if (len>4)len = 4;
end0 = row + len-1;       //横坐标的结束位置
end1 = column + len-1;      //纵坐标的结束位置for (int i = begin0, j = begin1; (i + 4 <= end0) && (j + 4 <= end1); ++i, ++j)
{if(order==1){if (state[i][j] == flag&&state[i + 1][j + 1] == flag&&state[i + 2][j + 2] == flag&&state[i + 3][j + 3] == flag&&state[i + 4][j + 4] == flag&&state[i + 5][j + 5]==flag ){z=-2;break;//长连}else if (state[i][j] == flag&&state[i + 1][j + 1] == flag&&state[i + 2][j + 2] == flag&&state[i + 3][j + 3] == flag&&state[i + 4][j + 4] == flag&&state[i - 1][j - 1]==flag ){z=-2;break;//长连}}if (state[i][j] == flag&&state[i + 1][j + 1] == flag&&state[i + 2][j + 2] == flag&&state[i + 3][j + 3] == flag&&state[i + 4][j + 4] == flag)z=1;
}//判断副对角线是否满足条件
if( (row - 1) >(N - column) )len = (N - column) ;
elselen = row - 1;
if (len > 4)len = 4;
begin0 = row - len;       //横坐标的起始位置
begin1 = column + len;      //纵坐标的起始位置if((N - row) > (column - 1) )len = (column - 1) ;
elselen = (N - row);
if (len>4)len = 4;
end0 = row + len;       //横坐标的结束位置
end1 = column - len;      //纵坐标的结束位置//printf("%d  %d  %d  %d",begin0,begin1,end0,end1);
//system("pause");
for (int i = begin0, j = begin1; (i + 4 <= end0) && (j - 4 >= end1); ++i, --j)
{if(order==1){if (state[i][j] == flag&&state[i + 1][j - 1] == flag&&state[i + 2][j - 2] == flag&&state[i + 3][j - 3] == flag&&state[i + 4][j - 4] == flag&&state[i + 5][j - 5]==flag ){z=-2;break;//长连}else if (state[i][j] == flag&&state[i + 1][j - 1] == flag&&state[i + 2][j - 2] == flag&&state[i + 3][j - 3] == flag&&state[i + 4][j - 4] == flag&&state[i - 1][j + 1]==flag ){z=-2;break;//长连}}if (state[i][j] == flag&&state[i + 1][j - 1] == flag&&state[i + 2][j - 2] == flag&&state[i + 3][j - 3] == flag&&state[i + 4][j - 4] == flag)z=1;
}for (int i = 0; i < N ; ++i)           //棋盘有没有下满
{for (int j =0; j < N ; ++j){if (state[i][j] == 0)return 0;                      //0表示棋盘没满}
}
z=-1;
return 0;      //和棋

}

void turnComputer(int **state, int row, int column)
{
// 统计玩家或者电脑连成的子
int personNum = 0; // 玩家连成子的个数
int botNum = 0; // AI连成子的个数
int emptyNum = 0; // 各方向空白位的个数
int goodadress[row][column];
int r,col;
int i,j;
int maxscore=0;
int x=0,y=0;
int mp=0;
int a[10];
int b[10];
// 清空评分数组
for( i=0;i<row;i++)
{
for( j=0;j<column;j++)
{
goodadress[i][j]=0;
};
};

        // 计分(此处是完全遍历,其实可以用bfs或者dfs加减枝降低复杂度,通过调整权重值,调整AI智能程度以及攻守风格)for ( r=0; r< row; r++){for ( col = 0; col < column; col++){// 空白点就算if (r >= 0 && col >= 0 &&state[r][col] == 0){// 遍历周围八个方向for ( y = -1; y <= 1; y++)for ( x = -1; x <= 1; x++){// 重置personNum = 0;botNum = 0;emptyNum = 0;// 原坐标不算if (!(y == 0 && x == 0)){// 每个方向延伸4个子// 对玩家白子评分(正反两个方向)for ( i = 1; i <= 4; i++){if (r + i * y > 0 && r + i * y < row &&col + i * x > 0 && col + i * x < column &&state[r + i * y][col + i * x] == 1) // 玩家的子{personNum++;}else if (r + i * y > 0 && r + i * y < row &&col + i * x > 0 && col + i * x < column &&state[r + i * y][col + i * x] == 0) // 空白位{emptyNum++;break;}else// 出边界break;}for ( i = 1; i <= 4; i++){if (r - i * y > 0 && r - i * y < row &&col - i * x > 0 && col - i * x < column &&state[r - i * y][col - i * x] == 1) // 玩家的子{personNum++;}else if (r - i * y > 0 && r - i * y < row &&col - i * x > 0 && col - i * x < column &&state[r - i * y][col - i * x] == 0) // 空白位{emptyNum++;break;}else            // 出边界break;}if (personNum == 1)                      // 杀二goodadress[r][col] += 10;else if (personNum == 2)                 // 杀三{if (emptyNum == 1)goodadress[r][col] += 30;else if (emptyNum == 2)goodadress[r][col] += 40;}else if (personNum == 3)                 // 杀四{// 量变空位不一样,优先级不一样if (emptyNum == 1)goodadress[r][col] += 60;else if (emptyNum == 2)goodadress[r][col] += 110;}else if (personNum == 4)                 // 杀五goodadress[r][col] += 10100;// 进行一次清空emptyNum = 0;// 对AI黑子评分for ( i = 1; i <= 4; i++){if (r + i * y > 0 && r + i * y < row &&col + i * x > 0 && col + i * x < column &&state[r + i * y][col + i * x] == 1) // 玩家的子{botNum++;}else if (r + i * y > 0 && r + i * y < row &&col + i * x > 0 && col + i * x < column &&state[r +i * y][col + i * x] == 0) // 空白位{emptyNum++;break;}else            // 出边界break;}for ( i = 1; i <= 4; i++){if (r - i * y > 0 && r - i * y < row &&col - i * x > 0 && col - i * x < column &&state[r - i * y][col - i * x] == -1) // AI的子{botNum++;}else if (r - i * y > 0 && r - i * y < row &&col - i * x > 0 && col - i * x < column &&state[r - i * y][col - i * x] == 0) // 空白位{emptyNum++;break;}else            // 出边界break;}if (botNum == 0)                      // 普通下子goodadress[r][col] += 5;else if (botNum == 1)                 // 活二goodadress[r][col] += 10;else if (botNum == 2){if (emptyNum == 1)                // 死三goodadress[r][col] += 25;else if (emptyNum == 2)goodadress[r][col] += 50;  // 活三}else if (botNum == 3){if (emptyNum == 1)                // 死四goodadress[r][col] += 55;else if (emptyNum == 2)goodadress[r][col] += 100; // 活四}else if (botNum >= 4)goodadress[r][col] += 10000;   // 活五}}}};} ;// 从评分中找出最大分数的位置for ( r=0; r<row; r++){for ( col=0; col<column; col++){// 前提是这个坐标是空的if (state[r][col] == 0){if (goodadress[r][col]>=maxscore)          // 找最大的数和坐标{maxscore = goodadress[r][col];x=r;y=col;// mp=mp+1;};};};};// 随机落子,如果有多个点的话// srand((unsigned)time(0));//  int last=rand()%mp;state[x][y]=2;

}

五子棋程序设计(C语言、人机对战、禁手)相关推荐

  1. 【C语言五子棋、三子棋人机对战篇的详细介绍】

    C语言--五子棋.井字棋人机对"战" 针对 "[C语言实现五子棋.三子棋人机对战,包含电脑人工智能对战(可攻可守)](非标题党)" 的详细介绍 五子棋.三子棋人 ...

  2. 【C语言实现五子棋、三子棋人机对战,包含电脑人工智能对战(可攻可守)】(非标题党)

    C语言--五子棋.井字棋人机对"战" 针对C语言学习过程中的五子棋.三子棋实现记录 五子棋人机对战 C语言--五子棋.井字棋人机对"战" 实际效果 一.头文件( ...

  3. php判断五子棋是否取胜,五子棋取胜方法—逼黑方走出禁手

    五子棋是一种两人对弈的纯策略型棋类游戏,是起源于中国古代的传统黑白棋种之一;下面是有五子棋取胜方法-逼黑方走出禁手,欢迎参阅. 消弱黑方行的优势,五子棋规则中针对黑方设定了各 种禁手,白方除了因无禁手 ...

  4. 五子棋人人对战功能的C语言实现(无禁手)

    文章目录 前言 显示棋盘 执行落子 胜负判定 功能综合 前言 之前C语言课的大作业是设计一个可以进行人人对战和人机对战的五子棋程序.我在初期开始写的时候参考过很多份代码,但对于当时我的水平而言不够直观 ...

  5. Android 蓝牙对战五子棋项目实现(含人机对战功能)

    上周花了一周时间做的课程设计的项目,实现的功能如下: 基本功能: (1) 该APP能够通过蓝牙自动搜索周围其他使用了该APP的手机,用户可选择其中某一个APP发起对战的要求,被发起方可以同意或者拒绝: ...

  6. Java 五子棋人人对战和人机对战简单实现

    废话不多说,咱直接进入正题 首先,为了方便,咱们先用一个Java接口把一些全局要用的数据写到接口里,这样就不用传来传去了 package wuziqi;public interface Gobang ...

  7. python判断五子棋胜负_一个连珠(带禁手的五子棋)判断胜负的PHP实现

    gist 打不开的凑合看这个吧 xsir317/renju 曾经从一个C++的源码那里(传送门: Index of /renlib/opensrc 就是那个ForbiddenPointFinder ) ...

  8. 五子棋AI图形界面人机对战(JAVA实现)

    前言 改了又改,查了又查,想了又想,我真的不知道怎样让它再聪明了,大多时候走的都是正确的,但偶尔会蹦出那么一步臭棋,全盘皆输.希望有相关经验的道友看到后可以指出原因和不足. 效果图 按钮什么的还未完成 ...

  9. java五子棋禁手规则,复盘等的实现

    五子棋程序实现了判赢,禁手,复盘,低级AI(判断还存在许多问题,欢迎指正),继续游戏,夜间模式,悔棋等基本功能 代码可研究不可复制粘贴. 禁手的定义:是为了限制黑方的先手优势而设定的一种比赛规则 禁手 ...

最新文章

  1. 算法总结---最常用的五大算法(算法题思路)
  2. 2022王道操作系统名词解释概念题
  3. FLASH模仿苹果菜单源码.(AS苹果菜单源码)
  4. 中国在线直播教育行业发展形势与竞争策略研究报告2022-2028年
  5. python创建线程
  6. hive中建立“按天分区“的外表+存储为ORC文件+指定元数据
  7. 【Splay】文艺平衡树(金牌导航 Splay-2)
  8. 快充线与普通线的区别_四种不同线身材质对比:iPhone12首次标配编织线或将引领潮流?...
  9. Bytecoin节点搭建
  10. [UOJ455][UER #8]雪灾与外卖——堆+模拟费用流
  11. 基于Spring中的事务管理机制
  12. eclipse注释中,文字大小不等的解决办法
  13. python手机版做小游戏代码大全-用Python设计一个经典小游戏
  14. 一场农业“人机”对战,能否凿开农村致富新门路呢?
  15. SAP 用户出口合集
  16. matlab中如何画柱状图,如何在用Matlab画柱状图
  17. 有关《家》的经典歌曲_盘点《乐队的夏天》15首经典歌曲,太好听了!
  18. Linux——MySQL分表分区
  19. 一文读懂 Jmeter - 你以为Jmeter只能用来做压力测试?
  20. 【JVM】运行时数据区概述(程序计数器、虚拟机栈、本地方法栈)

热门文章

  1. 扎拉赞恩 服务器 微信群,魔兽世界怀旧服回音群岛扎拉赞恩任务怎么做?WOW怀旧服扎拉赞恩在哪里?...
  2. 医疗行业专业术语知识
  3. 软件或网站(学习 工作 生活)
  4. windows系统中创建以 点 .开头的文件及文件夹的方法
  5. 关于数值策划在使用Excel表时的一点想法
  6. 网络安全管理员_三级_操作技能考核解题过程(1)
  7. 新基建下的城轨,城市群功能还能如何被提升?
  8. 太太太好用了!12款论文润色神器,SCI、EI论文写作必看
  9. 如何在MAC中使用内网穿透
  10. Touchpad驱动分析