刚出来工作的时候,用C++做过一个五子棋的AI,那时候已基本达到了自己战胜不了电脑的水平。当然,自己的水平相当有限,不能以此作为标准。最近心血来潮,想做一款象棋的,看了一些资料之后,发现五子棋也可以再写一遍。于是就使用C#做了象棋和五子棋的AI,都达到了自己无法战胜的水平。
一开始,我以为五子棋更简单一些,毕竟象棋的走法更复杂,但做下来发现,其实五子棋是更复杂、计算量更大的一个棋类。
程序的内容很大一部分参考了《PC游戏编程(人机博弈)》这本书,在阅读本博文之前,请先了解书里的内容。我不打算重复书里讲过的内容,只会讲一些自己的特色。
一、基本数据类型的定义
程序没有以效率至上为原则,充分地考虑了易读性,所以代码看起来还是比较容易理解的。
一些基本的数据类型:
-
/// <summary>
-
/// 棋子颜色
-
/// </summary>
-
public
enum ChessColor
-
{
-
无,
-
黑,
-
红,
-
白,
-
蓝
-
}
-
-
/// <summary>
-
/// 棋子类型
-
/// </summary>
-
public
enum ChessType
-
{
-
空,
-
卒,
-
象,
-
士,
-
炮,
-
马,
-
车,
-
将,
-
有
-
}
-
-
/// <summary>
-
/// 棋子结构
-
/// </summary>
-
public
class
Chess
-
{
-
public Chess()
-
{
-
color = ChessColor.无;
-
type = ChessType.空;
-
}
-
-
public Chess(ChessColor c, ChessType t)
-
{
-
color = c;
-
type = t;
-
}
-
-
public void Set(ChessColor c, ChessType t)
-
{
-
color = c;
-
type = t;
-
}
-
-
public ChessColor color;
-
public ChessType type;
-
}
-
-
/// <summary>
-
/// 移动类棋走步结构
-
/// </summary>
-
public
class
Step :
IComparable
-
{
-
public Step(int fr, int fc, int tr, int tc)
-
{
-
FromRow = fr;
-
FromCol = fc;
-
ToRow = tr;
-
ToCol = tc;
-
}
-
-
public
int FromRow;
-
public
int FromCol;
-
public
int ToRow;
-
public
int ToCol;
-
-
/// <summary>
-
/// 走步价值
-
/// </summary>
-
public
int
value;
-
public int CompareTo(object obj)
-
{
-
return (obj
as Step).
value -
value;
-
}
-
}
-
-
/// <summary>
-
/// 单放类棋走步结构
-
/// </summary>
-
public
class
Put :
IComparable
-
{
-
public Put(int tr, int tc, ChessColor c)
-
{
-
ToRow = tr;
-
ToCol = tc;
-
Color = c;
-
}
-
-
public
int ToRow;
-
public
int ToCol;
-
public ChessColor Color;
-
-
/// <summary>
-
/// 走步价值
-
/// </summary>
-
public
int
value;
-
public int CompareTo(object obj)
-
{
-
return (obj
as Put).
value -
value;
-
}
-
}
整个棋盘用一个二维数组表示,board[Row,Col],它的每一格都是一个Chess类型,而Chess包括了颜色和棋子类型两个属性。在象棋里面,颜色是红和黑,类型有将、象、马、车等;在五子棋里面,颜色是白和黑,类型只有空和有。
象棋和五子棋的走步结构也并不一样,象棋是由一个位置移动到另一个位置,而五子棋是直接放棋子在某一个空位上。我们还能注意到,结构里有一个走步价值的属性。它是排序用的,在历史启发算法里使用。