中国象棋电脑应用规范(四) 中国象棋通用引擎协议
更新时间:2012-12-4、浏览次数:
- 3.0版较2.3版改进的内容有:
- 建议取消option反馈中的repetition和drawmoves选项,将selectivity选项改成randomness,增加promotion选项。
- 2.3版较2.2版改进的内容有:
- 建议采用“毫秒”作为唯一的时间单位,参阅option反馈中的usemillisec选项。
- 以后UCCI还会不定期地更新,并继续保持对早期版本的兼容。UCCI界面和引擎设计者可访问以下资源,来获得最新的UCCI版本:
- http://www.xqbase.com/protocol/cchess_ucci.htm
- 二、通讯方法
- 不管是Windows还是UNIX平台,能被界面调用的引擎都必须是编译过的可执行文件,它跟界面之间通过“标准输入”和“标准输出”(即C/C++语言中的stdin和stdout)通道来通讯。如果引擎从Windows平台移植到UNIX平台,那么需要重新编译源代码(管道操作的程序也需要作适当修改),或使用跨平台接口。
- 作为界面的设计,要启动一个引擎,Windows平台下可用CreateProcess()函数,UNIX平台下可用fork()和exec()函数,然后重定向到一个输入管道和一个输出管道,具体操作可参阅WinBoard/XBoard源程序的StartChildProcess()函数,或参阅中国象棋引擎ElephantEye源程序的<pipe.cpp>模块。
- 作为引擎的设计,通讯比界面略为简单(只需要对stdin和stdout操作),只在检查stdin是否有输入时较为麻烦,具体操作可参阅Crafty源程序的<utility.c>模块的CheckInput()函数,或参阅中国象棋引擎ElephantEye源程序的<pipe.cpp>模块。
- 通常,界面向引擎发送的信息称为“指令”,而引擎向界面发送的信息称为“反馈”。在UCCI中,不管是指令还是反馈,都是以“行”为单位的,即每条指令和反馈都必须以“回车”(即C/C++语言中的'\n')结束。
- 注意:引擎用缓冲方式发出反馈(即C/C++语言中直接将字符串写入stdout),那么每输出一行都必须用fflush()语句刷新缓冲区。
- 三、引擎的状态
- UCCI引擎在启动后,有三种状态。
- (1) 引导状态。
- 引擎启动时,即进入引导状态。此时引擎只是等待和捕捉界面的输入,而界面必须用ucci指令让引擎进入接收其他UCCI指令的空闲状态(稍后会提到)。当然,引擎也可以保留使用其他协议的权利,例如引擎允许第一条有效指令是cxboard,这样引擎就转而进入CXBoard状态。
- 收到ucci只后,引擎要完成一系列初始化工作,以输出ucciok的反馈作为初始化结束的标志,进入空闲状态。如果引导状态下UCCI引擎收到其他指令,则可以退出。
- (2) 空闲状态。
- 该状态下引擎没有思考(即几乎不占用CPU资源),而只是等待和捕捉界面的输入(和引导状态类似),接收这样几类指令:A. 设置引擎选项(setoption指令),B. 设置引擎的内置局面(即让引擎思考的局面)及其禁止着法(position和banmoves指令),C. 让引擎思考(go指令),D. 退出(quit指令)。
- (3) 思考状态。
- 引擎收到go指令后,即进入思考状态,以输出bestmove或nobestmove的反馈作为思考状态结束的标志(回到空闲状态)。该状态下引擎将满负荷运转(CPU资源占用率接近100%),但仍旧需要捕捉界面的输入(只有在批处理模式下不会捕捉界面的输入),接收两类指令:A. 中止思考(stop指令),B. 改变思考方式(ponderhit指令)。
- go指令只决定了引擎将按照什么思考方式来思考(即限定思考的深度,或限定思考的局面个数,或限定思考的时间),而思考的局面则必须通过前面输入的position指令来告诉引擎。
- 其他注意事项有:
- (1) 引擎只有在接收到go指令后才开始思考。即便引擎支持后台思考,在输出着法(反馈bestmove)后也不会自动进行,而是要由界面发送go ponder指令,让引擎以后台思考方式进行思考。
- (2) bestmove的反馈并不改变引擎的内置局面,如果界面让引擎走棋,就必须读取bestmove反馈的着法,并在界面的局面上走完这一步(当然,界面也可以走别的着法),再由position指令把新的局面告诉引擎。
- (3) 如果对局是计时的,那么每次思考时都必须用go指令设定时钟,引擎仅仅根据时钟来决定分配多少时间来思考,回到空闲状态后时钟就失效了,必须由界面扣去引擎思考的时间(从发送go指令起到收到bestmove反馈结束),在下次发送go指令时把新的时钟告诉引擎。
- (4) 启用“批处理”模式时,引擎在思考状态下就不接收指令。批处理模式适合用重定向方式调试引擎,例如一个输入文件含有以下指令集:
- http://www.xqbase.com/protocol/cchess_ucci.htm
-
- 1: ucci
- 2: setoption batch true
- 3: position fen <fen_1>
- 4: go depth 10
- 5: position fen <fen_2>
- 6: go depth 10
- 7: quit
- 1: ucci
-
- 第4行以后引擎即进入思考状态,由于处于批处理模式,引擎反馈bestmove后回到空闲状态,才会继续接收以后的指令。如果没有第2行的启用批处理模式,那么第4行以后的指令都将在思考状态接收,而对于思考状态,这些指令都是无效的。
- (5) 如果界面搞错了引擎的状态,在引擎的思考状态向界面发送quit指令,那么引擎最好能终止思考并立即退出,以避免界面无休止地等待引擎的退出。
- (6) 如果界面搞错了引擎的状态,在引擎的空闲状态向引擎发送stop指令,那么引擎最好能反馈一个nobestmove,以避免界面无休止地等待引擎的反馈。
- 四、着法和棋盘的表示
- 界面告诉引擎哪些着法是禁手(banmoves指令),或者引擎回答界面应该走哪个着法(bestmove反馈),这样的着法都用4个字符(简化的ICCS格式,参阅《中国象棋电脑应用规范(二):着法表示》一文)表示,即ICCS格式去掉中间的横线,并改成小写,例如h2e2。
- 界面用position指令把局面告诉引擎时,应该使用FEN串(写法参阅《中国象棋电脑应用规范(三):FEN文件格式》一文)。但是对局中会遇到循环局面,引擎也必须考虑其对策,因此FEN串并不能完全反映局面信息,必须使用FEN串(当前局面前第一个不吃子的局面)和后续着法相结合的方法表示局面。例如,开局以后走了以下4步:
- 第4行以后引擎即进入思考状态,由于处于批处理模式,引擎反馈bestmove后回到空闲状态,才会继续接收以后的指令。如果没有第2行的启用批处理模式,那么第4行以后的指令都将在思考状态接收,而对于思考状态,这些指令都是无效的。
-
1. 炮二平五 炮8平5 2. 炮五进四 士4进5
- 如果把这4步棋涉及的5个局面都告诉引擎,那么指令依次是:
-
- 1: position fen rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w - - 0 1
- 2: position fen rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w - - 0 1 moves h2e2
- 3: position fen rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w - - 0 1 moves h2e2 h7e7
- 4: position fen rnbakabnr/9/1c2c4/p1p1C1p1p/9/9/P1P1P1P1P/1C7/9/RNBAKABNR b - - 0 2
- 5: position fen rnbakabnr/9/1c2c4/p1p1C1p1p/9/9/P1P1P1P1P/1C7/9/RNBAKABNR b - - 0 2 moves d9e8
- 1: position fen rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w - - 0 1
-
- 其中第4行更换了FEN串,因为该局面前一个着法是吃子着法。
- 其中第4行更换了FEN串,因为该局面前一个着法是吃子着法。