1 GTP协议
GNU GO 3.0引入了一个新接口——围棋文本协议, 英文缩写:GTP,其目的是建立一个比GMP(Go Modem Protocol)协议的ascii 接口更合适于双机通信、更简单、更有效、更灵活的接口。
该协议有两种版本。GNU GO 3.0 和3.2使用了版本1,GNU GO 3.4及以后的版本使用协议版本2。规格定义在http:http://www.lysator.liu.se/~gunnar/gtp
GNU GO3.4 参考实现了GTP 版本2,除了多数共同的命令也对这个协议进行了私有扩展。
GTP有很多用途。对GNU GO来说,第一个用途是回归测试(20回归测试),其次是利用GTP与NNGS围棋服务器连接,同自身或其它程序对弈进行自动测试。目前也有许多支持GTP的图形用户界面,用来桥接与NNGS类似的围棋服务器。
2 GTP方式启动GNUGO
以GTP 方式启动GNU GO, 只要用“–mode gtp” 参数启动GNUGO就可以。接着你不会得到提示或什么其它输出,但是GNU GO已经在默默地等待GTP命令。
一个GTP会话如下例:
virihaure 462% ./gnugo --mode gtp 1 boardsize 7 =1 2 clear_board =2 3 play black D5 =3 4 genmove white =4 C3 5 play black C3 ?5 illegal move 6 play black E3 =6 7 showboard =7 A B C D E F G 7 . . . . . . . 7 6 . . . . . . . 6 5 . . + X + . . 5 4 . . . + . . . 4 3 . . O . X . . 3 2 . . . . . . . 2 WHITE (O) has captured 0 stones 1 . . . . . . . 1 BLACK (X) has captured 0 stones A B C D E F G 8 quit =8
命令单行输入,用可选的数字标识起始,后跟命令名和它的参数。
命令成功时返回等号(=)开始,接着是命令的数字标识(如果有的话)和结果。例子中多数结果都是空字符串,只有命令4的返回白着手C3、命令7的返回当前棋盘局面图,其它所有结果是空串。返回串由两个连续的换行结束。
失败的命令由问号”?”代替等号,如命令5的返回。
该协议的详细规格在 http://www.lysator.liu.se/~gunnar/gtp / 。可用的所有命令在GNU GO中以命令list_commands列出。文档参见。
3 协议应用
GTP是非对称协议,包括控制端和引擎两方面。控制端发送命令,引擎响应之。 GNU GO实现了这个协议的引擎端。
随GNU GO源代码一起也发布几个实现了控制端的应用。其中最有趣的一些:
regression/regress.awk
回归测试脚本,该脚本向引擎发送GTP 命令设定和评估局面,然后分析引擎的回应。 关于GTP基于回归测试的更多信息参见回归一章(20回归测试)。
regression/regress.pl
回归测试的Perl脚本,与CGI 脚本” regression/regress.plx “一起生成回归测试的HTML文件。
regression/regress.pike
回归测试的Pike脚本。比 “ regress.awk “更丰富、更有效。
regression/view.pike
通过图形棋盘检查单个回归测试项的Pike脚本。提供了一个检查GNU GO内核的简便方法。
interface/gtp_examples/twogtp
使两个引擎互相对弈的Perl 脚本。这个脚本实际上为两个引擎设置了棋盘尺寸、让子数和贴目,然后在引擎之间来回传送着手。
interface/gtp_examples/twogtp-a
可与twogtp互换的另一Perl脚本。
interface/gtp_examples/twogtp.py
twogtp的Python实现脚本。比其Perl实现功能更多。
interface/gtp_examples/twogtp.pike
twogtp的pike实现脚本。比Python实现功能更多。
interface/gtp_examples/2ptkgo.pl
包括一个图形棋盘的twogtp 变体。
更多GTP 应用列表,包括桥接到围棋服务器和图形用户界面:http://www.lysator.liu.se/~gunnar/gtp / 。
4 Metamachine
GTP 的一个有趣的应用是让GNU GO作为权威,指导其它程序。另一个计算机程序可以请求GNU GO生成后续局面并进行评估。
Santa Cruz的加州大学的David Doshay用基于GNU GO开发的SlugGo并行引擎做过一个有趣的实验。详细描述在http://lists.gnu.org/archive/html/gnugo-devel/2004-08/msg00060.html 。
” Metamachine ” 实验是一个更为普通的尝试,采用GTP与被作为权威使用的GNU GO程序通信。原理如下:
- 使用GTP top_moves 命令请求GNU GO“权威”生成第一步着手。
- 尝试双方着手并对当前盘面评分。
- 选择评分较高局面作为引擎的着手。
该方案不会产生一个更强的引擎,但具有启发性,并且SlugGo实验展示了一个较为精致的方案,沿此路线可能会产生较强的引擎。
两种实现都随同GNU GO发布。都采用fork和pipe系统调用,因此需要一个类Unix环境。Metamachine 已在 GNU/Linux 之下测试。
注意:如果Metamachine 正常终止, GNU GO进程将被杀掉,但总会有出错的可能,所以运行完Metamachine后最好运行ps -A|grep gnugo或ps -aux|grep gnugo确认没有未终止的进程。(如果有, 就杀掉。)
4.1 独立的 Metamachine
“interface/gtp_examples/metamachine.c”是独立实现的Metamachine程序。用cc -o metamachine metamachine.c编译运行。它通过GTP与一个GNUGO进程沟通,并把GNUGO作为权威。
采用以下原理:
stdin pipe a
GTP client —-> Metamachine —–> GNU Go
<---- <----- stdout pipe b
大多数由client发布的命令通过Metamachine逐个传送给GNU GO。唯一例外是gg_genmove,该命令被截获并转发。Client并不知道这种情况,它只知道发出了一个gg_genmove 命令并收到了回应。因此Metamachine更像一个普通的GTP引擎。
用法:无参数给出标准的GTP行为。metamachine –debug将调试信息发送到stderr 。
4.2 GNU GO 作为Metamachine
另外,也可以使用配置选项 “–enable-metamachine”编译GNU GO 。这编译了包含Metamachine代码的文件oracle.c。除非运行GNU GO时使用了实时选项”–metamachine”,否则这对引擎没有影响。因此需要同时使用编译选项和实时选项获取Metamachine。
这个方法比独立程序好,因为可以使用GNU GO的工具。 例如这样可以用CGoban 或Ascii方式运行Metamachine。
增加命令行”-d0x1000000 “可以进行跟踪。在调试Metamachine时,危险在于编程中的一个小失误就可能导致通信进程和控制器挂起, 彼此都在等待对方的回应。如果这看来发生了,你可以把gdb放入运行过程,察看发生了什么,这很有用。
5 增加新GTP 命令
在GNU GO中GTP的实现分发三个文件,” interface/gtp.h “、” interface/gtp.c “和”interface/play_gtp.c “。前两个实现了一个小的辅助函数库,供其它程序使用。为了推广的需要,以最低的限制条件发放许可(参见A.3 The Go Text Protocol License 部分)。实际的GTP命令在”play_gtp.c”中实现,与引擎内核交互。
来看一个简单而相当典型的命令实现: gtp_countlib() (一个GNUGO的私有扩展命令):
static int gtp_countlib(char *s) { int i, j; if (!gtp_decode_coord(s, &i, &j)) return gtp_failure("invalid coordinate"); if (BOARD(i, j) == EMPTY) return gtp_failure("vertex must not be empty"); return gtp_success("%d", countlib(POS(i, j))); }
命令参数通过字符串s传递,在这里参数是一个棋盘点,故此调用”gtp.c”的gtp_decode_coord()读取。
一个正确格式化的回应应以”=“或”?”开始,接着是数字标识(如果传递了的话)和实际结果,最后是两个连续的换行符结束。正确地获取这种格式非常重要,因为对端的控制器依赖于它。当然结果本身不能包含两个连续的换行符,但可以用单个换行符分成多行。
假设要格式化的文本没用换行符结束,要生成正确格式化的回应,最容易的方法是使用函数gtp_failure() 和gtp_success()之一。
有时输出会过于复杂不适合使用gtp_success,如我们想打印棋盘点gtp_success()就不支持。这时只有回到构造,如gtp_genmove()
static int gtp_genmove(char *s) { [...] gtp_start_response(GTP_SUCCESS); gtp_print_vertex(i, j); return gtp_finish_response(); }
这里gtp_start_response()输出写等号和数字标识,gtp_finish_response()增加最后的两个换行符。下个例子来自gtp_list_commands()
static int gtp_list_commands(char *s) { int k; UNUSED(s); gtp_start_response(GTP_SUCCESS); for (k = 0; commands[k].name != NULL; k++) gtp_printf("%s\n", commands[k].name); gtp_printf("\n"); return GTP_OK; }
刚才说到,回应必须以两个换行符结束。这里我们只好自己来完成回应,因为在循环中最后一个命令已经输出了一个换行符。
为了增加一个新GTP 命令至GNU GO,需要在” play_gtp.c “中插入以下代码片断:
- 在第68行开始用DECLARE宏指令声明函数。
- 在第200行开始加入commands[]数组。
- 操作命令的代码实现。
“gtp.c”/”gtp.h”中有用的辅助函数:
- gtp_printf() 基本格式打印
- gtp_mprintf()棋盘点和棋子格式编码打印
- gtp_success()和gtp_failure() 简单回应
- gtp_start_response()和gtp_end_response() 较复杂的应答
- gtp_print_vertex() 和gtp_print_vertices() 打印一个和多个棋盘点
- gtp_decode_color()从命令参数中读出棋子
- gtp_decode_coord() 从命令参数中读出棋盘点
- gtp_decode_move()从命令参数中读出着手,即棋子加棋盘点
6 GTP 命令参考
本节列出GNU GO实现命令及其参考,每个命令入口包括以下的域:
- Function: 该命令的功能
- Arguments: 命令需要的其它信息,典型值包括none、vertex、integer等
- Fails: 导致命令失败的详情
- Returns: 在=和连续两个换行符间显示的内容,典型值包括nothing、a move coordinate、some status string等。
- Status: 该命令与标准GTP第2版的关系,如果没有关联则是GNUGO的私有扩展.
细节不再赘述,所列为所有命令(没有特别顺序):
Argument:
N-None
V-Vertex
I-Integer
F-Float
C-Color “black”, “white”, or “empty”
NH- number of handicap stones
LVH-list of vertices with handicap stones
LVH-list of vertices
F-FileName
MN-Move Number
M-move (color + V)
Fails:
N-Never
IL-Illegal
IC-Incorrcect
IV- invalid
IM- illegal move
BNE-board not empty
BOL-Board outside limit
FF-missing filename or failure to open or parse file
EV-empty vertex
OV-occupied vertex
NV-Not Available
SE-stack empty
Returns:
N-Nothing
DSstatus (“alive”, “critical”, “dead”, or “unknown”)
US unconditional status (“undecided”, “alive”, “dead”,”white_territory”, “black_territory”).
ES Status in the form of one of the strings “alive”, “dead”,”seki”, “white_territory”, “black_territory”, or “dame”
着手列表color move (one move per line)
white_influence (float)
black_influence (float)
white_strength (float)
black_strength (float)
white_attenuation (float)
black_attenuation (float)
white_permeability (float)
black_permeability (float)
territory_value (float)
influence_regions (int)
non_territory (int)
The encoding of influence_regions is as follows:
4 white stone
3 white territory
2 white moyo
1 white area
0 neutral
-1 black area
-2 black moyo
-3 black territory
-4 black stone
Worm data formatted like A19:
color black
size 10
effective_size 17.83
origin A19
liberties 8
liberties2 15
liberties3 10
liberties4 8
attack PASS
attack_code 0
lunch B19
defend PASS
defend_code 0
cutstone 2
cutstone2 0
genus 0
inessential 0
B19:
color white
.
.
.
inessential 0
指令表(共125条指令)
Name | Function | Arguments | Fails | Returns | Status |
---|---|---|---|---|---|
quit | 退出 | N | N | N | G2S |
protocol_version | 报告协议版本号. | N | N | 协议版本号 | G2S |
name | 报告程序名称. | N | N | 程序名称 | G2S |
version | 报告程序版本号. | N | N | 版本号 | G2S |
boardsize | 设置路数并清盘 | I | BOL | N | G2S |
equery_boardsiz | 询问当前棋盘路数 | N | N | 路数 | G2S |
clear_board | 清盘面. | N | N | N | G2S |
orientation | 设置方向并清盘 | I | IL | N | |
query_orientation | 查询当前方向 | N | N | 方向 | |
komi | 设置贴目 | F | IC | N | G2S |
get_komi | 取贴目数 | N | N | 贴目 | |
black | 给定节点落黑子 | V | IV/IM | N | OG1 |
playwhite | 给定节点落白子. | V | IV/IM | N | OG1 |
play | 给定节点给定落子 | C/V | IV/IM | N | G2S |
fixed_handicap | 设置固定位置让子 | NH | IV | LVH | G2S |
place_free_handicap | 设置自由位置让子 | NH | IV | LVH | G2S |
set_free_handicap | 放置自由位置让子 | LVH | BNE/IV | N | G2S |
get_handicap | 取让子数 | N | N | NH | |
loadsgf | 打开一个SGF文件至所给的手数或第一手 | F+MN/V/NV | FF | C | G2S |
color | 返回端点的子色 | V | IV | C | |
list_stones | 黑子或白子的端点列表 | C | IV | LV | |
countlib | 计算端点所在串的气数 | V | IV/EV | 气数 | |
findlib | 返回端点串的气点列表 | V | IV/EV | 节点列表 | |
accuratelib | 检查落子气点列表 | M | IV/OV | 节点列表 | |
accurate_approxlib | 检查落子气点列表 | M | IV/OV | 节点列表 | |
is_legal | 着手是否合法 | M | IV | 1/0 | |
all_legal | 所有合法着法节点列表 | C | IV | 节点列表 | |
captures | 返回提子数 | C | IV | 提子数 | |
last_move | 上一手的子色端点 | N | NV | M | |
move_history | 招法历史反序列表 | N | N | 着手列表 | |
trymove | 尝试落子 | M | IV/IM | N | |
tryko | 忽略劫争尝试落子 | M | IV/IM | ||
popgo | 取消trymove或tryko | N | SE | N | |
clear_cache | 清高速缓存 | N | N | N | |
attack | 试吃一串 | V | IV/EV | 攻击代码和评分 | |
attack_either | 试吃两串之一 | 2V | IV/EV | 攻击代码 | |
defend | 试防守一串 | V | IV/EV | 防守代码和评分 | |
ladder_attack | 试征吃一串 | V | IV/EV | 攻击代码 | |
increase_depths | 增加深度 | N | N | N | |
decrease_depths | 减少深度 | N | N | N | |
owl_attack | 试吃龙 | V | IV/EV | 攻击代码 | |
owl_defend | 试防守龙 | V | IV/EV | 防守代码 | |
owl_threaten_attack | 试两步吃龙 | V | IV/EV | 防守代码 | |
owl_threaten_defense | 试两步防守龙 | V | IV/EV | 防守代码 | |
owl_does_attack | 确定指定着法对指定的龙有攻击 | V,V | IV/EV | 攻击代码 | |
owl_does_defend | 确定指定着法对指定的龙有防守 | V,V | IV/EV | 防守代码 | |
owl_connection_defends | 确定指定着法连接指定的两条龙 | V,V | IV/EV | 防守代码 | |
defend_both | 试图防守两串 | 2V | IV/EV | 防守代码 | |
owl_substantial | 确定是否吃住一串给活龙 | V | IV/EV | 1/0 | |
analyze_semeai | 对杀分析 | D,D | IV/EV | 对杀防守、攻击结果、着手 | |
analyze_semeai_after_move | 下过一手后的对杀分析 | C,V,D,D | IV | 对杀防守、攻击结果、着手 | |
tactical_analyze_semeai | 不使用OWL的对杀分析 | D,D | IV/EV | 棋块状态 | |
connect | 试连接两串 | V, V | IV/EV | 联络结果 | |
disconnect | 试断开两串 | V, V | IV/EV | 分断结果 | |
break_in | 试以串破空 | V, Vs | IV/EV | 结果和评分 | |
block_off | 试对串守空 | V, Vs | IV/EV | 结果和评分 | |
eval_eye | 眼空间评价 | V | IV | 眼最大最小数 | |
dragon_status | 龙状态 | OV | IV/EV | DS、攻击、防守评分 | |
same_dragon | 确定两子属于同一条龙 | V, V | IV/EV | 1/0 | |
unconditional_status | 确定端点状态 | V | IV | US | |
combination_attack | 按给定子色寻找通过组合攻击吃住某些子的着法 | C | IV | 推荐着手 | |
combination_defend | 如给定子色能通过组合攻击吃住对方,列表对方对此攻击的防守着法 | C | IV | 推荐着手 | |
aa_confirm_safety | 运行atari_atari_confirm_safety() | M,OI | IM | 成功代码 | |
genmove_black | 产生并下出认为最好的黑着法 | N | N | 着手或 “PASS” | OG1 |
genmove_white | 产生并下出认为最好的白着法 | N | N | 着手或 “PASS” | OG1 |
genmove | 以给定子色产生并下出认为最好的着法 | C | IV | 着手或 “PASS” | G2S |
reg_genmove | 以给定子色产生并下出认为最好的着法 | C | IV | 着手或 “PASS” | G2S |
gg_genmove | 以给定子色产生并下出认为最好的着法 | C,OI | IV | 着手或 “PASS” | |
restricted_genmove | 只在给定的端点中选择,并以给定子色产生并下出认为最好的着法 | C,Vs | IV | 着手或 “PASS” | |
kgs-genmove_cleanup | 以给定子色产生并下出认为最好的着法,在对手死子未清除前不PASS | C | IV | 着手或 “PASS” | KGS |
level | 设置棋力 | Int | IC | N | |
undo | 悔一手 | N | IV | N | G2S |
gg-undo | 悔N手 | OI | IV | N | |
time_settings | 设时间 | I,I,I | IV | N | G2S |
time_left | 报告剩余时间 | C,C,I,I | IV | N | G2S |
final_score | 记谱完成的棋局 | OI | N | SGF评分 | G2S |
final_status | 报告下完棋局的端点最终状态 | V,OI | IV | ES | |
final_status_list | 按指定最终状态报告下完棋局的端点列表 | ES,OI | IV | 节点列表 | G2S |
estimate_score | 记录评比 | N | N | 评分上下限 | |
experimental_score | 重视下一手谁走的估计评分 | C | IV | 评分 | |
reset_life_node_counter | 重设活的节点计数 | N | N | N | |
get_life_node_counter | 取活的节点数 | N | N | 活节点数 | |
reset_owl_node_counter | 重设OWL节点计数 | N | N | N | |
get_owl_node_counter | 取OWL节点数 | N | N | Owl节点数 | |
reset_reading_node_counter | 重设计算节点数 | N | N | N | |
get_reading_node_counter | 取计算节点数 | N | N | 识别节点数 | |
reset_trymove_counter | 重设trymoves/trykos计数 | N | N | N | |
get_trymove_counter | 取trymoves/trykos计数 | N | N | trymoves/trykos数 | |
reset_connection_node_counter | 重设连接节点计数 | N | N | N | |
get_connection_node_counter | 取连接节点计数 | N | N | 联络节点数 | |
test_eyeshape | 为矛盾的评估测试眼形 | Vs | IV | 故障保护 | |
analyze_eyegraph | 对眼图计算眼值和要点 | S | IV | 眼值 | |
cputime | 以秒返回共用CPU时间 | N | N | 秒 | |
showboard | 向stdout写盘面 | N | N | N | G2S |
dump_stack | 向stderr转储堆栈 | N | N | N | |
move_influence | 落子后返回有关初始的影响函数信息 | M,Inf | N | 影响数据 | |
move_probabilities | 列出欲下的每着及概率,如前面没有genmove命令,则此命令结果无效 | N | N | 着手配对 | |
move_uncertainty | 返回着法的不确定成份 | N | N | 不确定位 | |
followup_influence | 返回一着后产生的影响信息 | M,Inf | N | 影响数据 | |
worm_data | 返回串数据结构中的信息 | OV | N | 棋串数据 | |
worm_stones | 列表串的子 | V | EV | 棋子列表 | |
worm_cutstone | 返回串数据结构中的cutstone域 | V | N | 分断子 | |
dragon_data | 返回龙数据结构中的信息 | OV | N | 棋块数据 | |
dragon_stones | 列表龙的子 | V | IV | 棋子列表 | |
eye_data | 返回眼数据结构中的信息 | C,V | N | 眼数据 | |
half_eye_data | 返回后手眼数据结构中的信息 | V | N | 后手眼数据 | |
start_sgftrace | 开始在内存中以SGF树存储计算期的招法 | N | N | N | |
finish_sgftrace | 完成存储着法的SGF树,并写入文件 | F | N | N | |
printsgf | 当前局面输出到SGF | F | MF | N | |
tune_move_ordering | 调谐局部计算的着法命令参数 | Is | IV | N | |
echo | 显示参数 | S | N | N | |
echo_err | 显示参数至stdout及stderr | S | N | N | |
help | 列表所支持的命令 | N | N | 命令列表 | G2S |
known_command | 报告一条命令是否支持 | CMD | N | “true” /”false” | G2S |
report_uncertainty | 从from owl_attack and owl_defend调谐不确定报告开或关 | “on” / “off” | IV | N | |
get_random_seed | 取随机种子 | N | N | 随机数 | |
set_random_seed | 设随机种子 | I | IV | N | |
is_surrounded | 确定龙是否被围 | V | IV/EV | 0/1/2 | |
does_surround | 确定一着是否能围住龙 | V,V | IV/EV | 1 | |
surround_map | 报告给定端点的龙的包围图 | V,V | IV/EV | 包围值 | |
set_search_diamond | 限制搜索,建立搜索菱形 | Pos | IV | N | |
reset_search_mask | 为限定搜索清盘面标志 | N | N | N | |
limit_search | 设置限定搜索全局变量 | Value | IV | N | |
set_search_limit | 为限定搜索标志一个端点 | Position | IV | N | |
draw_search_area | 画搜索区,写至stder | N | N | N |