由来
最近人工智能很火,经常有各种新闻,作为一个程序员多少要懂一点吧,未来万一用得着呢。有心想去了解一下,奈何能力有限,皮毛都没学会。好吧,既然没法系统学,就不管那么多,就从现在开始动手,一步一步的往前走,遇到什么问题就查什么资料。虽然最后不一定能做成什么,起码做的过程遇到问题解决问题,总能学会点什么。
从最简单的五子棋游戏开始,先用普通的规则实现一个电脑下棋的算法,姑且叫做AI算法。作为一个只用过linux环境的C语言,做到这一步也还是需要走不少的路,还要学习不少东西才能做好。这次算是我头一回认真学习而且还坚持这么久,所以记录一下所学和这个过程。本文适合像我一样的新手。
废话说完,正式开工。
五子棋基本规则:
1、棋盘大小15x15
2、五个棋子连成一条线即为赢
3、黑棋先下
4、黑棋禁手先不考虑
棋型基本术语:
5连:5个子连成一条线,已经赢了。
活4:有4个子在一条线,而且连线的两端没有对方的子。
冲4:(也有说眠4)有4个子在一条线,连线的一端没有对方的子,另一端有对方的子。
活3:有3个子在一条线,而且连线的两端没有对方的子。
类似的还有冲3,活2,冲2,活1。
其他更专业的术语就不考虑了。
极大极小值
极大极小值算法需要两个条件:
1、 零和博弈,就是你死我活的游戏。
2、 完全信息,玩家知道之前的所有步骤,象棋、五子棋都是交替落子在棋盘上,之前的步骤都一目了然。
如果把五子棋下子所有可能都列举出来,就可以看做一个树的结构。以电脑AI的视角看,每一步往下走都可以看做是树,树的根节点为0开始。奇数层表示电脑可能走法我们称之为MAX层,偶数层是玩家的可能走法我们称之为MIN层。
显然,
MAX层,电脑需要选择对自己最有利的节点。
MIN层,玩家会选择对自己最有利的节点,也就是对AI最不利的点。
这就是极大极小值算法。
这里有个很核心问题,什么叫最有利什么叫最不利呢?下面用源码一步一步详细讲解评估函数的由来,再用评估函数解释什么棋对电脑AI最有利和最不利。
(下面代码用C语言写的,linux下x86环境编译运行)
首先第一步:定义分值,其中score_e枚举就是分值定义
直接把头文件贴出来,方便后面的代码理解。
#ifndef __COBAND_MAIN_H
#define __COBAND_MAIN_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DEBUG 0 //打开调试信息
#define M_SIZE 15 //棋盘大小为15x15
#define DEEP 3 //最大搜索多少层
#define check(x) (((x)<0) || ((x)>=M_SIZE)) //棋子坐标是否溢出
//棋子状态颜色
#define SPACE 0
#define WHITE 1
#define BLACE 2
/*计分板
分数随意定的,只考虑了不让四个方向上的分数加起来超过更高一级的棋型*/
typedef enum score_e
{
WIN5 = 100000, //5连
ALIVE4 = 10000, //活4
ALIVE3 = 1000, //活3
DIE4 = 1000, //死4
ALIVE2 = 100, //活2
DIE3 = 100, //死3
DIE2 = 10, //死2
ALIVE1 = 10 //活1
}score;
//棋子
typedef struct chess_s
{
u8 x;
u8 y;
}chess_t;
//空子的序列
typedef struct chess_queue_s
{
chess_t chess[M_SIZE*M_SIZE];
u8 len;
}chess_queue;
#endif
第二步:依据连子个数计算分数
/*计分表,依据连子个数(bumber