这学期选了人工智能原理,上课的时候完全没搞懂老师要讲什么,所以听课听得云里雾里的,幸好有几个小实验,可以帮助理解人工智能的精髓。
第一个实验就是基于带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; } }