国际象棋通用引擎协议
 
象棋百科全书网 (webmaster@xqbase)
20049月初稿,20062月修订
 
一、UCI协议的特点
 
  UCI协议,全称是国际象棋通用引擎协议(Universal Chess Interface,直译作通用象棋接口)。它是开放的象棋引擎协议,所谓开放的引擎协议,指的是:
  (1) 协议内容是公开的,并且可以免费使用;
  (2) 你可以根据该协议自己编写象棋引擎,凡是支持该协议的界面,都可以使用你编写的引擎;
  (3) 你可以根据该协议自己编写象棋界面,凡是支持该协议的引擎,都可以被你编写的界面调用。
  UCI协议的前身是象棋引擎SOSShredder使用的引擎协议,在他们的作者Rudolf HuberStefan Meyer-Kahlen对该协议的改进下,20001128UCI协议问世了。
 
  UCI协议具有以下特点:
  (1) 引擎程序是可执行文件,它同界面程序之间通过标准输入标准输出(C语言中的stdinstdout)来通讯。
  (2) 输入和输出是以行方式来完成的,界面发给引擎的每条指令都必须以回车(C语言中的'\n')结束,界面接收引擎的反馈也一样。
  注:引擎不能跨平台使用,如果引擎从一个平台(Windows)移植到另一平台(Unix),需要重新编译源代码,或使用跨平台接口。引擎的平台通常由三类:
  A. DOS平台,但是由于DOS平台过于陈旧,现在很难到这样的引擎;
  B. Windows平台,需要在Windows下用Console方式编译引擎源代码,WinBoard只能使用这类引擎;
  C. Unix/Linux平台;需要在UnixLinux下编译源代码(也用Console方式)XBoard能够使用Linux的引擎。
  (3) 引擎启动时,必须用uci指令让引擎进入UCI协议状态。当然,引擎也可以保留不使用UCI协议的权利,只要它接受的第一条有效指令允许不是uci。例如,很多UCI引擎允许第一条有效指令是xboard,这样引擎就转而进入WinBoard协议状态。
  (4) 无论引擎是否在思考,都必须随时接收指令,这样界面程序就可以随时中断引擎的工作或改变引擎的思考方式了。每条指令都以特定的关键字开头,关键字和参数之间必须用空格隔开,这样可以简化引擎识别指令的过程。
  (5) 界面必须随时接收引擎的反馈信息,每条反馈信息也都以特定的关键字开头(空格后面才是信息的实质内容),这样可以让界面更方便地识别每一条反馈信息。
  (6) 引擎在搜索一个局面前,先要让界面把局面的位置告诉引擎,作为内置局面
  (7) 引擎必须接收到"go"指令后才开始思考(搜索)
  (8) 如果对局是计时的,那么每次思考时都必须设定时钟,引擎仅仅根据时钟来决定思考策略,时钟的改变需要界面来完成;
  (9) 当引擎完成一个局面的搜索,得到一步最佳着法后,并不改变内置局面,只是把这个着法反馈给界面,界面来完成这一步(当然,界面也可以让引擎走别的着法),再把走完这一步后的局面告诉引擎;
  (10) 开局库通常由界面来指定给引擎,即通常引擎是不自带开局库的,当然引擎也可以自带开局库,此时界面可以让引擎根据引擎自己的开局库来完成开局的某步。
  以上10个特点中,前5点和WinBoard协议是类似的,而后5WinBoard协议和UCI协议则完全相反,因此WinBoard协议和UCI协议的指令也截然不同。
 
二、走棋格式
 
  UCI协议用的走棋格式是长代数格式,即走动子的起始位置和到达位置,这里有几点需要注意:
  (1) 不要标明到达记号吃子记号将军记号以及其他评注记号,例如第一步走e4,则记作e2e4,而不是e2-e4
  (2) 不要标明所走的子,例如走Nf6,则记作g8f6,而不是Ng8f6
  (3) 王车易位时只标明王的路线,例如走O-O,则记作e1g1
  (4) 兵升变时在最后注明只用一个字母注明升变的子,例如走e8=Q,则记作e7e8q
 
三、输入和输出协议
 
  输入协议就是界面向引擎发送指令的协议,协议内容通常由一系列指令集组成(用红表示),输出协议则规定了引擎反馈给界面的信息,以及这些信息具体的含义(用蓝表示)
 
1. uci
  这是引擎启动后,界面需要给引擎发送的第一条指令,通知引擎现在使用的是UCI协议。
 
2. id {name <x> | author <x>}
  这是uci指令的反馈信息,显示引擎的版本号和作者。
 
3. option name <id> type <t> [default <x>] [min <x>] [max <x>] [var <x> [var <x> [...]]]
  也是uci指令的反馈信息,表示引擎所支持的选项,<id>指选项的名称(后面会介绍)<t>指选项的类型,可以是以下5种:
  (1) check,检查框,取值只能是truefalse
  (2) spin,旋钮,取值是整数,可以用minmax来限定范围;
  (3) combo,列表框,取值是由var来指定;
  (4) button,按钮,没有取值,仅仅用来触发某个事件;
  (5) string,字符串,取值可以是任何字符串。
  通常的UCI引擎支持以下选项:
  (1) Hash(spin),以MB为单位规定Hash表的大小;
  (2) NalimovPath(string),指定Nalimov残局库的路径,可以设置多个路径,用';'隔开;
  (3) NalimovCache(spin),以MB为单位规定Nalimov残局库的缓冲区;
  (4) Ponder(check),指定引擎是否后台思考(Ponder),设定该参数的目的仅仅是让引擎改变时间分配策略,后台思考仍然需要界面发出指令;
  (5) OwnBook(check),指定引擎是否要使用引擎自带的开局库;
setoption  (6) MultiPV(spin),引擎给出多少步最佳着法,Alpha-Beta搜索通常只给出一步,增加这个数值会降低引擎的运行效率,但扩大了界面对引擎提供着法的选择空间;
 
4. uciok
  这是uci指令的最后一条反馈信息,表示引擎已经进入用uci协议通讯的状态。
 
5. setoption name <id> [value <x>]
  设置引擎参数,这些参数必须是option反馈信息所列出的。
 
6. isready
  检测引擎是否处于就绪状态,如果引擎发送回readyok信息,则说明引擎已经就绪,可以界面可以向引擎发出其他指令。
 
7. readyok
  这是isready的反馈信息,仅仅表示引擎可以接收指令了。即使引擎在思考,接收到isready指令后也会返回readyok
 
8. position {fen <fenstring> | startpos } [moves <move1> .... <moven>]
  设置内置棋盘的局面,用fen来指定FEN格式串,或用startpos来指定起始局面,它等价于
fen rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
  一般来说,界面发送给引擎的<fenstring>是最近一次吃子或进兵后的局面(称为不可逆局面),该局面到当前局面的一系列着法则跟在moves后,目的是让引擎掌握重复检测的策略。FEN格式串的写法参阅《国际象棋译文苑》文摘——关于PGN和FEN记谱规范(下)一文。
 
9. go ...
  让引擎根据内置棋盘的设置和设定的搜索方式来思考,有以下搜索方式可供选择(可以多选,直接跟在go后面)
  (1) searchmoves <move1> .... <moven>,只让引擎在这几步中选择一步;
  (2) wtime <x>,白方剩余时间(单位是毫秒)
    btime <x>,黑方剩余时间;
    winc <x>,白方每步增加的时间(适用于Fischer)
    binc <x>,黑方每步增加的时间;
    movestogo <x>,还有多少回合进入下一时段(适用于时段制)
  这些选项用来设定时钟,它决定了引擎的思考时间;
  (3) ponder,让引擎进行后台思考(即对手在用时,引擎的时钟不起作用)
  (4) depth <x>,指定搜索深度;
  (5) nodes <x>,指定搜索的节点数(即分析的局面数,一般它和时间成正比)
  (6) mate <x>,在指定步数内只搜索杀棋;
  (7) movetime <x>,只花规定的时间搜索;
  (8) infinite,无限制搜索,直到杀棋。
 
10. info ...
  显示引擎思考信息,信息有以下内容(可以是很多信息,都跟在info后面)
  (1) depth <x>,当前搜索到的深度;
  (2) seldepth <x>,选择性搜索(不完全搜索)达到的深度,通常会跟在depth后面;
  (3) pv <move1> ... <moven>,已经搜索到的最佳路线;
  (4) multipv <num>,这只会出现在设定了MultiPV选项以后,紧跟在pv后面,说明它是最佳的路线中的第几条(排名第几)
  (5) time <x>,已经搜索的时间,它往往跟在pv后面;
  (6) score {pv <x> | mate <y>} [lowerbound | upperbound],引擎对当前局面的评价,pv <x>指当前局面的评分,单位是百分兵值mate <y>指在多少步之内会形成杀棋,lowerbound指该评价是最低估计(为白方估计)upperbound指该评价是最高估计(为黑方估计)