五子棋人机算法

分析:首先在玩家下完子之后,需要ai下棋。那么ai应该是去拦截玩家的棋子或者使自己棋子更容易形成五连,所以在ai眼里并不是所有棋盘上的空位置都是一样的。很定有优先考虑的位置。那么我们将采用对棋盘空位置进行赋分的方法来进行区别每个位置。

思路:每次下子后,遍历整个棋盘,对棋盘的每个空位置进行赋分------然后找到分值最好的位------ai进行落子

方法一:对每个空位置的八个方向进行

下面我们用这个赋分的规则:

机器学习训练下五子棋_c++五子棋算法


这里我们采用对每个空位的上、下、左、右、左上、左下、右上、右下八个方向判断棋子的分布情况。

下面的用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;
}