现在的位置: 首页 > 综合 > 正文

五子棋AI设计——从门外到门内不得不说的事儿1

2017年12月12日 ⁄ 综合 ⁄ 共 1179字 ⁄ 字号 评论关闭

这学期选了人工智能原理,上课的时候完全没搞懂老师要讲什么,所以听课听得云里雾里的,幸好有几个小实验,可以帮助理解人工智能的精髓。

第一个实验就是基于带alpha-beta剪枝的MinMax搜索的五子棋AI设计。好久没有写过MFC界面了,所以在pudn上down了几个例程,测试了一下,选了两个比较规范的工程作为开发的基础。

第一天:Naive AI——一个称不上AI的AI

比对着选好的工程进行复制,在复制的过程中删去一些暂时用不到的功能,就搞出了如下界面。


有了棋盘,让我们开始下棋吧。可是这是我还对五子棋的规则一知半解,是个门外汉。只好采用投石问路的方法,先来个简单的吧,随机生成合法落子位置。

首先将棋盘定义为一个整形的二维数组points[16][16],0表示空,1表示黑子,2表示白子。为什么是16,只是觉得用1-15比用0-14直观一些,其实模仿程序是这么定义的。

那么,什么样的位置是合法的呢?就是棋盘上满足points[i][j] == 0的(i,j)。这样随机生成1-15之间的任意整数x = rand()%15 + 1; y =rand()%15 + 1;建议在两个语句中间加若干空循环,避免x和y一样,提高“随机性”,虽然这个随机性并不怎么样吧。

这样,一个称不上AI的AI诞生了,我们就叫他Naive吧。

观赏Naive下棋是一种享受,因为他的表现比我还差,我可以很轻易的在五步之内秒杀他。

在解决了有无问题后,应该着眼于提高AI的水平,使其成为真的AI。

如何提高,路在何方?且听下回分解。

--------------------分割线--------------------

“AI”代码如下,

void CWuZiQi::Naive( const int points[16][16], bool first, int oldp[16][16], int newp[16][16], int *nx, int *ny )
{
	int x, y;
	int k = 0;
	// current state quick save
	for ( int i = 1; i <= 15; i++ )
		for ( int j = 1; j <= 15; j++ )
		{
			oldp[i][j] = points[i][j];
			newp[i][j] = points[i][j];
		}
	// place a chess on board
	do
	{
		for ( int j = 0; j < 1000; j++ )
			for ( int k = 0; k < j; k++ )
				;
		x = rand() % 15 + 1;
		for ( int j = 0; j < 1000; j++ )
			for ( int k = 0; k < j; k++ )
				;
		y = rand() % 15 + 1;
		k++;
	}while ( oldp[x][y] != 0 || k > 20 );
	if ( k >= 20 )
	{
		*nx = -1; *ny = -1;
		return;
	}
	else
	{
		*nx = x; *ny = y;
	}
	if ( first )
	{
		newp[x][y] = 1;
	}
	else
	{
		newp[x][y] = 2;
	}
}

抱歉!评论已关闭.