象棋函数库ChessFunctions功能与用法
ChessFunctions是我用VB6开发的动态链接库,目的在于为象棋软件开发者提供便利,降低开发难度。
首先讲述一下象棋编程的基础知识。
象棋软件的功能与构成
一个象棋软件,应该具备如下基本功能:
- 新建棋局
- 支持双人对弈、人机对弈
- 保存棋谱、打开棋谱
从设计的角度,象棋软件向用户提供界面,用户可以在棋盘上点击和移动棋子。程序的后台代码,需要相应的记录用户的操作,同步更新数据。
棋谱的本质
一盘棋,是由初始局面和后续招法形成的。局面(board)和招法(movelist)这两个术语构成了象棋软件的核心内容。只有处理好这两项内容,才能做出合格的软件。
局面
局面是指棋盘上有哪些棋子,这些棋子在什么位置。描述局面主要有如下三种方式:
FEN字符串
FEN字符串采用字母与数字结合的方法,把棋盘上10×9=90个交叉点的棋子进行描述,具体方法是用字母rnbakcp分别代表黑方的车马象士将炮卒,用RNBAKCP分别代表红方的车马相仕帅炮兵。从棋盘左上角从左到右、自上而下,遇到连续的空格,用空格数量代替。换行的时候用斜杠分开,例如:
r2akabr1/9/1cn1b2cn/p3p1p1p/2p6/6P2/P1P1P3P/1CN1C1N2/9/R1BAKABR1 w
上述FEN用来描述下面这个局面,r2akabr1表示 黑车 两个空格 士 将 士 象 黑车 1个空格。以此类推
需要注意,FEN字符串后面有一个字母w或者b,用于描述当前局面该哪一方走棋,如果红方走棋,结尾是w。否则是b
FEN字符串至关重要,采用一行字符串就描述整个棋盘。在各个象棋软件之间复制粘贴局面非常方便,而且,云库以及引擎也只认识FEN字符串。
加空的FEN字符串
所谓加空的,是指把FEN字符串中的数字,用连续的空格换掉。我习惯用小写字母o表示空格。例如上述FEN字符串加空以后:
rooakabro/ooooooooo/ocnoboocn/pooopopop/oopoooooo/ooooooPoo/PoPoPoooP/oCNoCoNoo/ooooooooo/RoBAKABRo
加空的目的在于,把FEN字符串的长度凑够99个(90个交叉点+9个斜杠),这样方便利用循环转换为数组。
二维数组
象棋软件的程序后台采用二维数组作为局面的数据结构,非常合适,因为二维数组在形式上最接近真实的棋盘。
我喜欢这样声明Dim Matrix(1 To 10, 1 To 9) As String
一维表示10行,二维表示9列。上述FEN字符串对应的二维数组是:
如果在VBA的本地窗口查看二维数组:
招法
招法,指的是红方或黑方走了一步棋,一个招法必然对二维数组的元素进行修改。
如左图所示,假设红方车二进七吃黑炮,形成右图:
这样就产生了一个招法,这个招法需要对二维数组Matrix进行如下元素修改:
Matrix(x2,y2) = Matrix(x1,y1)
Matrix(x1,y1) = "o"
其中,x2,y2是棋子行走终点的横纵坐标,x1,y1是起点的横纵坐标。
以上两行,是著名的“象棋公式”,任何一招棋,都这样的。
*需要注意,对于一盘棋,局面数总比招法数多1,因为初始局面没有招法。
中文棋谱
中文棋谱,采用4个字描述一个招法,这种做法指出了发生行走的棋子的名称,但是缺点是起点、终点的坐标不明确,程序设计的时候很不方便。必须转换为具体的行列数才能处理。
东萍movelist
东萍象棋是目前最强大的网络象棋数据库,采用binit描述初始局面,采用movelist描述招法列表。
movelist用4个数字表示招法,具体是x1y1x2y2这种格式。把棋盘左上角的位置定为(0,0)。
例如从全局开始,红方黑方先后走了:
炮二平五 象7进5 马二进三 士4进5
形成如下局面:
东萍象棋的movelist则记为:7747604279673041
云库或引擎的moves
云库是一个能够计算招法的网站,用户只需要把FEN字符串传递给网站,云库就能返回当前局面最佳招法是什么。对于开局阶段,云库还可以返回多个可选招法。
云库或者引擎,把棋盘的左下角定为(a, 0),采用一个字母一个数字的方式描述棋子的位置。 给出的招法是两个字母两个数字,例如上述局面,b0c2表示马八进七,
i0h0表示车一平二。下面是一些可选招法。
引擎,是位于磁盘上的一个可以计算招法的可执行文件,与云库类似,用户把FEN字符串传递进来,就可以给出最佳招法。
综上所述,movelist和moves都是坐标表示法,可以相互转换,写代码的时候非常容易。
象棋软件开发的拦路虎
我相信,很多象棋爱好者或者编程爱好者都曾尝试过编写象棋软件。但是绝大多数人半途而废,完整地开发一个象棋软件的人寥寥无几。究其原因,是因为存在如下三大难题难以解决。
行棋规则判断
象棋软件,提供给用户的是一个棋盘,以及用控件制作的一些棋子。用户点击棋子的时候,能够移动到哪儿,不能移动到哪儿,必须加以限制。否则导致马走田字、车炮可以斜着走等情况。
也就是说,在用户试图走一步棋的时候,软件应该判断一下是否为合理招法。
局面计算
局面计算属于人工智能,自己编写算法难度很大。目前最方便的方式就是调用云库,或者调用引擎。
棋谱格式转换
象棋软件的另一个重要功能就是能够保存、打开棋谱。然而,象棋棋谱文件格式非常多,主流的有pgn、东萍棋谱等。程序开发的时候必然需要解释每个棋谱的初始局面是什么,招法列表是什么。中文棋谱、movelist、moves三者之间的转换是必要的。
使用象棋函数库
象棋函数库(ChessFunctions)解决了如上3个难题。开发人员只需要在工程中添加该引用,就可以在代码中调用相应的函数,来轻松开发。
ChessFunctions的构成
ChessFunctions包含如下5个类:
- Clscdb:国际象棋云库的功能
- Clschessdb:中国象棋云库的功能
- ClsChineseChess:中国象棋规则、棋谱转换等
- ClsInternationalChess:国际象棋规则
- ClsEngine:引擎方面的功能,中国象棋国际象棋通用
ChessFunctions的用法
ChessFunctions支持32位的Office VBA,以及目标平台是x86的C#程序等。下面演示VBA中使用ChessFunctions的方法。
- 注册dll
管理员身份启动cmd命令提示符窗口,输入:
regsvr32 xxx\ChessFunctions.dll
按下回车进行注册。xxx是具体路径
- 添加引用
在VBA工程中添加引用。浏览ChessFunctions.dll
- 调用函数
Private chessdb As ChessFunctions.Clschessdb Sub Test() Dim m As String Set chessdb = New ChessFunctions.Clschessdb '必须实例化 m = chessdb.bestmove(FEN:="3ak1P2/4a4/4b4/C8/2b6/9/9/9/9/4K4 w - - 0 1") Debug.Print m End Sub
上述代码调用了Clschessdb这个类中的bestmove函数,也就是让云库计算最佳招法。最后,m的打印结果是 a6e6(炮九平五)。
继续修改代码:
Sub Test()
Dim a() As String
Set chessdb = New ChessFunctions.Clschessdb '必须实例化
a = chessdb.queryall(FEN:="3ak1P2/4a4/4b4/C8/2b6/9/9/9/9/4K4 w - - 0 1") 'queryall用于计算所有招法,返回数组。
Debug.Print Join(a, vbNewLine)
End Sub
打印结果是:
根据score可以看出,红方只有走a6e6(炮九平五)或者走a6a9(炮九进三)才能赢,其余走法都是和棋。
其余类库的调用示例,请参考“VBA用户窗体中国象棋.xlsm”文件Test模块里面的代码。
类 | 函数名 | 功能 |
---|---|---|
Clscdb | bestmove | 返回国际象棋指定局面下的最佳招法 |
queryall | 返回国际象棋指定局面下的全部招法 | |
querypv | 返回国际象棋指定局面下的思考细节 | |
queryscore | 返回国际象棋指定局面下的分数 | |
validation | 返回国际象棋指定局面是否合理 | |
Clschessdb | bestmove | 返回中国象棋指定局面下的最佳招法 |
queryall | 返回中国象棋指定局面下的全部招法 | |
querypv | 返回中国象棋指定局面下的思考细节 | |
queryrule | 返回中国象棋指定局面是否犯规、和棋 | |
queryscore | 返回中国象棋指定局面下的分数 | |
validation | 返回中国象棋指定局面是否合理 | |
ClsChineseChess | Array2FEN | 二维数组转FEN字符串 |
binit2FEN | 东萍binit转FEN字符串 | |
DisplayBoard | 显示文本棋盘 | |
FEN2Array | FEN字符串转二维数组 | |
FEN2binit | FEN字符串转东萍binit | |
Fens2movelist | 多个FEN字符串转东萍movelist | |
getMovelistString | 根据movelist计算出中文棋谱 | |
GetUBB | 返回指定url的东萍UBB | |
Movable | 判断指定局面下某个招法是否可走 | |
movelist2FENs | 根据movelist计算出多个连续的FEN字符串 | |
movelist2moves | movelist转moves | |
movelist2Qipu | movelist转中文棋谱 | |
moves2movelist | moves转movelist | |
Qipu2movelist | 中文棋谱转movelist | |
SaveUBB | 将指定的UBB上传到东萍网站 | |
加空 | FEN字符串中的数字用o替换 | |
去空 | 把字符串中的o替换为数字 | |
ClsEngine | bestmove | 返回国际象棋/中国象棋指定局面下的最佳招法 |
info | 返回国际象棋/中国象棋指定局面下的全部招法 | |
QuitEngine | 退出引擎 | |
StartEngine | 启动引擎 | |
ClsInternationalChess | Array2FEN | 二维数组转FEN字符串 |
DisplayBoard | 返回文本格式的棋盘 | |
FEN2Array | FEN字符串转二维数组 | |
Movable | 判断国际象棋指定局面下某个招法是否可走 | |
moves2FENs | 根据moves计算出后续FEN字符串 | |
加空 | FEN字符串中的数字用o替换 | |
去空 | 把字符串中的o替换为数字 |
欢迎大家在评论区留言,如果要下载ChessFunctions,QQ群: