刚出来工作的时候,用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包括了颜色和棋子类型两个属性。在象棋里面,颜色是红和黑,类型有将、象、马、车等;在五子棋里面,颜色是白和黑,类型只有空和有。
象棋和五子棋的走步结构也并不一样,象棋是由一个位置移动到另一个位置,而五子棋是直接放棋子在某一个空位上。我们还能注意到,结构里有一个走步价值的属性。它是排序用的,在历史启发算法里使用。