五子棋人机算法
分析:首先在玩家下完子之后,需要ai下棋。那么ai应该是去拦截玩家的棋子或者使自己棋子更容易形成五连,所以在ai眼里并不是所有棋盘上的空位置都是一样的。很定有优先考虑的位置。那么我们将采用对棋盘空位置进行赋分的方法来进行区别每个位置。
思路:每次下子后,遍历整个棋盘,对棋盘的每个空位置进行赋分------然后找到分值最好的位------ai进行落子
方法一:对每个空位置的八个方向进行
下面我们用这个赋分的规则:
这里我们采用对每个空位的上、下、左、右、左上、左下、右上、右下八个方向判断棋子的分布情况。
下面的用c++实现的源码,因为creator是脚本文件所以硬生生从项目中拉出来可能有些地方会有点生硬:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<iostream>
using namespace std;
#include <stdlib.h>
#include<stdlib.h>
#define black 1
#define white 0
char qip[15][15];
char black_flag = '*';
char white_flag = '#';
int qinxingpc[15][15] = { 0 };
int qinxingplayer[15][15] = { 0 };
int player = black;
int playerload();
void pcload();
void jifen();
int jieguo(int left, int right, int count, int k, char num);
int shu(int hang, int lie, char whoflag);
int heng(int hang, int lie, char whoflag);
int zuoxie(int hang, int lie, char whoflag);
int youxie(int hang, int lie, char whoflag);
void init_qip();
void draw_qip();
int iswin();
int main()
{
int result;
int nums;
init_qip();
draw_qip(); //构建棋盘
for (nums = 0; nums < 225; nums++)
{
if (player == black)
{
printf("please (%c) play\n", white_flag);
player = white;
result = playerload();
if (!result) break;
} //玩家下棋
else
{
player = black;
pcload();
} //ai下棋
draw_qip();
if (iswin( ))
{
if (player == white)
{
printf("玩家1(%c) is winner.\n", white_flag);
}
else
{
printf("ai(%c) is winner.\n", black_flag);
}
break;
}
}
}
void init_qip()
{
int i = 0;
int j = 0;
for (i = 0; i <15; i++)
{
for (j = 0; j < 15; j++)
{
qip[i][j] = '.';
}
} //构建棋盘15*15
}
void draw_qip()
{
int i = 0, j = 0, k = 0;
system("cls"); //清零//
printf(" X--------------------------->\n"); //x轴
printf(" ");
for (k = 0; k < 15; k++)
{
if (k >= 0 && k <= 8)
{
printf("%d ", k + 1);
}
else
{
printf("%d", k + 1);
}
}
putchar('\n');
for (i = 0; i < 15; i++)
{
printf("Y");
if (i >= 0 && i <= 8)
{
printf("0%d ", i + 1);
}
else
{
printf("%d ", i + 1);
}
for (j = 0; j <15; j++)
{
putchar(qip[i][j]);
if (j<14) putchar(' ');
}
putchar('\n');
}
}
int heng(int hang, int lie, char whoflag)
{
int spacenum = 0;//空白数
int count = 1;//几连
int lefthad = 0;//左边是否有相同子
int x = hang;
int y = lie;
int liveleft = 0; //0 1表示活死
int liveright = 0;
if (qip[hang][lie] != '.')
{
return 0;
} //该位置不判断
while (y > 0 && (qip[x][y - 1] == '.' || qip[x][y - 1] == whoflag))
{
if (qip[x][y - 1] == '.'&&spacenum < 1)
{
if (qip[x][y - 2] != whoflag)
{
liveleft = 1;
break; //如果该子左边第二个不是该棋子,则跳出
}
spacenum++;
y--; //如果左边第一个为空的话,则空白数加1 ,左活
}
else if (qip[x][y - 1] == whoflag)
{
lefthad = 1;
y--;
count++;
} //如果左边第一个有棋子,则连子数加1
else
{
liveleft = 1;
break;
} //其他情况,左活
} //while判断该位置左边的连子情况
if (!lefthad)
{
spacenum = 0; //如果左边无连子,则不做判断
}
//y = lie;
while (y < 14 && (qip[x][y + 1] == '.' || qip[x][y + 1] == whoflag))
{
if (qip[x][y + 1] == '.'&&spacenum < 1)
{
if (qip[x][y + 2] != whoflag)
{
liveright = 1;
break;
}
spacenum++;
y++;
} //如果右边相邻两个都为空的,则空白数加1,右活
else if (qip[x][y + 1] == '.'&&spacenum>0)
{
liveright = 1;
break;
}
else
{
y++;
count++;
}
}
return jieguo(liveleft, liveright, count, spacenum, whoflag);
}
int shu(int hang, int lie, char whoflag)
{
int spacenum = 0;
int count = 1;
int tophad = 0;
int x = hang;
int y = lie;
int liveleft = 0;
int liveright = 0;
if (qip[hang][lie] != '.')
{
return 0;
}
while (x > 0 && (qip[x - 1][y] == '.' || qip[x - 1][y] == whoflag))
{
if (qip[x - 1][y] == '.'&&spacenum < 1)
{
if (qip[x - 2][y] != whoflag)
{
liveleft = 1;
break;
}
spacenum++;
x--;
}
else if (qip[x - 1][y] == whoflag)
{
tophad = 1;
x--;
count++;
}
else
{
liveleft = 1;
break;
}
}
if (!tophad)
{
spacenum = 0;
}
x = hang;
while (x<14 && (qip[x + 1][y] == '.' || qip[x + 1][y] == whoflag))
{
if (qip[x + 1][y] == '.' && spacenum<1)
{
if (qip[x + 2][y] != whoflag)
{
liveright = 1;
break;
}
spacenum++;
x++;
}
else if (qip[x + 1][y] == '.' && spacenum>0)
{
liveright = 1;
break;
}
else
{
x++;
count++;
}
}
return jieguo(liveleft, liveright, count, spacenum, whoflag);
}
int zuoxie(int hang, int lie, char whoflag)
{
int spacenum = 0;
int count = 1;
int tophad = 0;
int x = hang;
int y = lie;
int liveleft = 0;
int liveright = 0;
if (qip[hang][lie] != '.')
{
return 0;
}
while (x<14 && y>0 && (qip[x + 1][y - 1] == '.' || qip[x + 1][y - 1] == whoflag))
{
if (qip[x + 1][y - 1] == '.' && spacenum<1)
{
if (qip[x + 2][y - 2] != whoflag)
{
liveleft = 1;
break;
}
spacenum++;
x++;
y--;
}
else if (qip[x + 1][y - 1] == whoflag)
{
tophad = 1;
x++;
y--;
count++;
}
else
{
liveleft = 1;
break;
}
}
if
(!tophad)
{
spacenum = 0;
}
x = hang; y = lie;
while (x>0 && y<14 && (qip[x - 1][y + 1] == '.' || qip[x - 1][y + 1] == whoflag))
{
if (qip[x - 1][y + 1] == '.' && spacenum<1)
{
if (qip[x - 2][y + 2] != whoflag)
{
liveright = 1;
break;
}
spacenum++;
x--;
y++;
}
else if (qip[x - 1][y + 1] == '.' && spacenum>0)
{
liveright = 1;
break;
}
else
{
x--;
y++;
count++;
}
}
return jieguo(liveleft, liveright, count, spacenum, whoflag);
}
int youxie(int hang, int lie, char whoflag)
{
int spacenum = 0;
int count = 1;
int tophad = 0;
int x = hang;
int y = lie;
int liveleft = 0;
int liveright = 0;
if (qip[hang][lie] != '.')
{
return 0;
}
while (x>0 && y>0 && (qip[x - 1][y - 1] == '.' || qip[x - 1][y - 1] == whoflag))
{
if (qip[x - 1][y - 1] == '.' && spacenum<1)
{
if (qip[x - 2][y - 2] != whoflag)
{
liveleft = 1;
break;
}
spacenum++;
x--;
y--;
}
else if (qip[x - 1][y - 1] == whoflag)
{
tophad = 1;
x--;
y--;
count++;
}
else
{
liveleft = 1;
break;
}
}
if (!tophad)
{
spacenum = 0;
}
x = hang; y = lie;
while (x<14 && y<14 && (qip[x + 1][y + 1] == '.' || qip[x + 1][y + 1] == whoflag))
{
if (qip[x + 1][y + 1] == '.' && spacenum<1)
{
if (qip[x + 2][y + 2] != whoflag)
{
liveright = 1;
break;
}
spacenum++;
x++;
y++;
}
else if (qip[x + 1][y + 1] == '.' && spacenum>0)
{
liveright = 1;
break;
}
else
{
x++;
y++;
count++;
}
}
return jieguo(liveleft, liveright, count, spacenum, whoflag);
}
int jieguo(int left, int right, int count, int k, char num)
{
if (count == 1) //对1连打分
{
return 1;
}
else if (count == 2) //对2连打分
{
if (left&&right) //活2
{
if (k == 0)
{
return num == black_flag ? 60 : 50; //有两空位及以上
}
else
{
return num == black_flag ? 40 : 35; //仅有一空位
}
}
else if (!left&&!right) //死2
{
return 1;
}
else //半死2
{
return 10;
}
}
else if (count == 3)
{
if (left&&right) //活3
{
if (k == 0)
{
return num == black_flag ? 950 : 700;
}
else
{
return num == black_flag ? 900 : 650;
}
}
else if (!left&&!right) //死3
{
return 1;
}
else //半死3
{
return 100;
}
}
else if (count == 4)
{
if (left&&right) //活4
{
if (k == 0)
{
return num == black_flag ? 6000 : 3500;
}
else
{
return num == black_flag ? 5000 : 3000;
}
}
else if (!left&&!right) //死4
{
return 1;
}
else //半死4
{
if (k == 0)
{
return num == black_flag ? 4000 : 800;
}
else
{
return num == black_flag ? 3600 : 960;
}
}
}
else {
if (k == 0)
{
return num == black_flag ? 20000 : 15000;
}
else
{
return num == black_flag ? 10000 : 3300;
}
}
}
void pcload()
{
jifen();
int count = 0;
int hang = 0;
int lie = 0;
int i = 0;
int j = 0;
for (i = 0; i< 15; i++)
{
for (j = 0; j< 15; j++)
{
if (qinxingpc[i][j] > count)
{
count = qinxingpc[i][j];
hang = i;
lie = j;
}
if (qinxingplayer[i][j] > count)
{
count = qinxingplayer[i][j];
hang = i;
lie = j;
}
} //将判断出分值最高的坐标输出出来
}
printf("qinxingPC[%d][%d]:%d\n", hang, lie, qinxingpc[hang][lie]);
printf("qinxingPlayer[%d][%d]:%d\n", hang, lie, qinxingplayer[hang][lie]);
if (qip[hang][lie] == '.')
{
qip[hang][lie] = black_flag;
} //对分值最高的位置下棋
}
int playerload()
{
int x, y;
int res;
cout << "input" << "x" << " " << "y";
cin >> y >> x;
/*printf("input y x:");
scanf("%d %d", &x, &y);*/
if (x<0 || y<0 || x>15 || y>15)
{
printf("input error,again\n"); //判断棋子是否落在棋盘上
while ((getchar()) != '\n');
res = playerload(); //playerload函数的递归调用
if (res == 1) return 1;
}
x--;
y--;
if (qip[x][y] == '.')
{
if (player == white)
{
qip[x][y] = white_flag;
}
}
else
{
printf("input error2,again\n"); //判断是否重子
while ((getchar()) != '\n');
playerload();
if (res == 1) return 1;
}
return 1;
}
void jifen()
{
int n = 0;
int m = 0;
for (n = 0; n<15; n++)
{
for (m = 0; m<15; m++)
{
qinxingpc[n][m] = heng(n, m, black_flag) + shu(n, m, black_flag) + zuoxie(n, m, black_flag) + youxie(n, m, black_flag); //计算ai在该位置的总分
qinxingplayer[n][m] = heng(n, m, white_flag) + shu(n, m, white_flag) + zuoxie(n, m, white_flag) + youxie(n, m, white_flag); //计算player在该位置的总分
}
}
}
int iswin()
{
char m;
int i, j;
if (player == white) m = white_flag;
else m = black_flag;
for (i = 0; i <15; i++)
{
for (j = 0; j < 15; j++)
{
if (qip[i][j] == m)
{
if ((i + 4) <15)
{
if (qip[i + 1][j] == m && qip[i + 2][j] == m && qip[i + 3][j] == m && qip[i + 4][j] == m) return 1;
}
if ((j + 4) < 15)
{
if (qip[i][j + 1] == m && qip[i][j + 2] == m && qip[i][j + 3] == m &&qip[i][j + 4] == m) return 1;
}
if
((i + 4) <15 && (j + 4) < 15)
{
if (qip[i + 1][j + 1] == m && qip[i + 2][j + 2] == m && qip[i + 3][j + 3] == m && qip[i + 4][j + 4] == m) return 1;
}
if ((i + 4) < 15 && (j - 4) >= 0)
{
if (qip[i + 1][j - 1] == m && qip[i + 2][j - 2] == m && qip[i + 3][j - 3] == m && qip[i + 4][j - 4] == m) return 1;
} //一个子向4个方向来判断是否有5连
}
}
}
return 0;
}