Gnu综述文档计算机围棋
计算机围棋网子标题: 中文 GNU Go
作者: X
日期: 04月17日
网址: http://www.computergo.net/go/modules/article/view.article.php/c1/8
摘要: 这份文档是对 GNU Go 的一个综述。其它关于各个模块或路径函数如何运作的的文档可在源程序的注释中找到。
GNUGo文档 - 3.GNUGo综述
少敏这份文档是对 GNU Go 的一个综述。其它关于各个模块或路径函数如何运作的的文档可在源程序的注释中找到。
定义
在这份文档中对所定义的术语,我们用蓝色字。
蠕虫 (WORM):是棋盘上最大限度的一组点,它们沿着水平和竖直线方向连接,有相同的颜色,这些颜色可以是黑色,白色或空。在蠕虫中用到了空( EMPTY )这个术语,意味着蠕虫中有空的点。这不是说蠕虫是一组空的。串( STRING )是非空的蠕虫。空的蠕虫被称为腔( CAVITY )。如果一组点被包含在蠕虫中,并只有唯一的蠕虫包含它,就是它的蠕虫截止(WORM CLOSURE )。
龙( DRAGON ) 是同颜色串的集合,它们将被当作一个单元。龙可被重新计算。如果两个串都在龙中,计算机采用的假设是它们会一起活或死,它们会被有效地联接。
棋步的产生
GNU Go 根据当前位置和颜色来下棋并产生优化棋步。这是由在 src/genmove.c 中的函数 genmove() 来完成的。
棋步的产生是经过了两个步骤:
1) 资料收集
2) 根据上面收集的资料,实际产生棋步资料收集
首先我们必须就当前位置尽可能多地收集资料。这类资料可以是组的死活,模样状态,和组的连接等等。资料收集是由下面的函数来进行,调用的顺序是:
- make_worms 收集所有相连棋子(串)和腔的资料。这个资料存在 worm[ ][ ] 数组中。
- make_dragons 收集被称作龙的相连串的资料。在此,重要的资料是串之间的眼的数量,死活状态和它们的连接。
- make_moyo 为双方计算“空”,“模样”和“地带”。在此所用到的“空”,是指在最后可成为实际地盘的点。“模样”是如果另一方不应而受影响的可成为空的地带。“地带”则是相对较弱但比“模样”要大一些。make_worms 和 make_dragons 在 docs/DRAGON 这个文件中有较详细的叙述。对 make_moyo 中的算法,在文件 docs/MOYO 中有说明。棋步的产生
一旦我们找出了所有关于位置的资料,就可生成最好的棋步。棋步是由许多不同的棋步生成器按照赋予它们的分值来共同生成的。分值将会被比较,并采用最佳的棋步。如果两个或多个棋步有相同的分值,将会随机采用其中一个。
在2.4版中,棋步的产生是:
- 布局(fuseki)牋 在早期的布局 中产生一个棋步。这个模块没有文档述及,以后将会被替换掉。- 对杀(semeai)牋找出两个有相反颜色的死的组是否彼此相邻。如果是,试图杀死其它组。这个模块可能是目前最差的,需要改善。
- 棋形(shapes)牋 匹配许多在当前位置的模板。每一个模板通过 8 个不同旋转和镜象的组合来进行匹配。如果模板相匹配,所谓的“限制”将被测试,它利用读入的模板来决定是否这个模板在目前的情形下应该被采纳。这样的限制要求许多自由的串,死活状态,并算出征子等。模板可以是许多为不同目标的不同的类。有的模板试图进攻或防守,有的试图连接或分断,而有的只是简单地
为了好的棋形。参看文件 docs/PATTERNS,它是关于模板的完整的文档。
- attacker 用三口或更少的气来寻找相反颜色的串,并试图杀死它们。
- defender 用三口或更少的气来寻找自己颜色的串,并试图防守它们。
- eye_finder 找出其中一种颜色中在下一步可做出两个眼的组,并寻找眼形中的死活要点。
- revise_semeai 如果尚未有棋步被找到,把在对杀中的组件组的状态从死变为未知。此后,genmove再次运行 shapes, 看是否会有新的棋步。
- fill_liberty 填充普通的气。这只是在一盘棋要结束时才用到。如有必要,将产生回填或反提的棋步。路径指引
GNU Go引擎包括在两个目录下 src/ 和 patterns/。涉及用户界面,读写SGF 文件和测试的代码可在目录 interface/, sgf/ 和 regression/下找到。从其它GNU程序借用的代码是在 utils/ 目录下。文档材料是在 docs/目录下。
在这个文档中,我们分别讲述所有在 src/ 和 patterns/ 目录下的构成引擎的源程序文件。对目录interface/ 下的文件,我们提到一个文件 GMP.C。它是一个围棋调制解调器协议接口程序(
由William Shubert 和其他人免费赠送)。它负责与Cgoban或任何其它识别围棋调制解调器协议的驱动程序进行交换设置和下棋。在 src/ 下有下列的文件:
attdef.c : 这个文件包括了进攻者attacker( )和防御者defender()以及眼位寻找者eye_finder( ),这三个棋步生成器被 genmove( ) 调用。进攻者模块建议进攻敌方串的棋步,而防守者模块建议防卫己方串的棋步。关于一个串是否可被吃或防卫的必要读取判断是在文件 reading.c 中。它已被
make_worms( ) 调用。如果一个串可被防卫,可能有不同的防守棋步,其中一些由 shapes( ) 找到的模板可能移动防卫点。这是唯一的由 make_worms( ) 和 make_dragons( ) 编译的数据可被后面的调用改变的情形。由于这个原因,shapes( ) 在 defender( ) 之前被调用。在 attdef.c 文件中的眼位寻找者 eye_finder( ) 也是如此。这个模块寻找龙有一个半眼。如果一个龙有一个半眼
,eye_finder( ) 建议制做( 如果这个龙是己方 )或毁掉( 如果这个龙是敌方 )这个半眼。dragon.c : 这个文件包括 make_worms( ) 和 make_dragons( )。这些函数是在棋步生成模块
shapes( ), attacker( ), defender( ), semeai( ) 和 eye_finder( )。它们找出所有的蠕虫和龙,并采集关于它们的重要资料。例如每一个有多少空,以GNU Go的观点来判断串和龙是否能被捕捉。这些资料保留不变直到下一步。但有一个例外:在进攻状态下,有一些模板可将己方的蠕虫的防守点移动。
filllib.c : 一盘棋结束后强制填充棋子( 如有必要,反填棋子)的源代码程序。
fuseki.c : 这个模块在游戏开始时产生布局棋步 (大范围开盘 )。
genmove.c: 这个程序包含了 genmove(), 它是负责产生下一步棋的函数。开始的棋步在这个文件中直接产生。生成其它的棋步则需要调用其它模块。被 genmove 调用的模块是 shapes( ) ( 在 shapes.c中 ), attacker( ) 和 defender( ) ( 在 attdef.c 中 ),semeai( ) ( 在semeai.c中 ),以及eye_finder( ) ( 在 attdef.c中 )。每个模块都对棋步提出建议,每个都有一个分值,genmove( )取分值最高的棋步。
hash.c: 被读取时所用到的散列代码。详细资料参看 READING 这个文件。
hash.h : hash.c 的头文件。
liberty.h : 整个程序的头文件。
main.c : 杂项登记 ( 传递参数,信号处理等 ),sgf 文件接口 ( 读取和写入 ),高层次的棋步( 从 genmove( ) 中取棋步, 跟踪放弃棋步pass 等)。它不包含有什么的围棋知识,只是知道每边轮流走,以及连续两个放弃棋步标志着一盘棋的结束。
matchpat.c : 这个文件包括 matchpat(), 它在棋盘的特定位置寻找模板。
moyo.c : 这个文件包括估计领土及其影响的源程序。详细资料参看 docs/MOYO。
reading.c : 这个文件包括判断一个给定的串是否会被攻击或防守, 详细资料参看 docs/READING。semeai.c : 它包括 semeai(), 这个模块是负责比气的。
sethand.c : 开始时安排让子的棋面。
showbord.c : 它包括 showboard( ), 它用 ASCII 符号来画棋盘,用相同字符来描述龙和棋子颜色。它在 GNU Go 1.2 版时是主要的界面,但现在是用于帮助调试程序。
shapes.c : 这个文件包括 shapes( ) 函数, 这个模块被 genmove( ) 调用,它试图用相匹配的模板
来寻找棋步。模板匹配有一些复杂的算法在文档 PATTERNS 中有详细描述。简要地说,模板可考虑敌我双方在局部的力量,一串棋逃跑的可能性,是否模板可带来或破坏掉一个有价值的连接,是否它会使得一条龙死掉,它还可调用一个由人工特别加入的帮助功能函数,通过读取更多的资料来决定这个模板是否合适。
optics.c : 它包括识别眼形的源程序,详细资料在文档 docs/EYES 中。
worm.c : 这个文件包括了在每一步棋开始时判断每个串的属性的源程序,它在文件dragon.c 的代码之前。
utils.c : 各种工具程序,详细叙述见下。
目录 patterns/ 里包括了与模板匹配相关的文件。目前寻找3种类型的模板:棋步生成模板( 在
patterns.db 文件和相类似的文件中,例如由hoshi.sgf 文件编译出来的 hoshi..db 文件,详细资料参看 docs/PATTERNS 文档); 眼形模板 ( 在 eyes.db文件中,参看 docs/OPTICS 文档 ) 和连接模板( 在 conn.db文件中, 在文档docs/DRAGONS 中有讨论 )。下面列出一些在发布的源代码文件中内部自动生成的文件,例如 patterns.c。
有一些 C 源程序是由编译各种模板数据库而产生。而在某些情形下,数据库本身(例如 hoshi.db)是通过编译SGF格式的定式( joseki )文件自动生成的。
conn.db : 连接模板数据库。
conn.c : 自动生成的文件,包括了结构数组形式的连接模板,由 mkpat 从conn.db 编译产生。
eyes.c : 自动生成的文件,包括了结构数组形式的眼形模板,由 mkpat 从 eyes.db 文件编译生成。eyes.h : eyes.c的头文件。
eyes.db : 眼形模板的数据库。参看 docs/EYES。
helpers.c : 通过matchpat 对辅助估价棋步有帮助作用。
hoshi.sgf : SGF 格式文件,包括 4-4 点开放模板。
hoshi.db : 自动生成的 4-4 点 开放模板数据库。通过编译星小目hoshi.sgf 文件生成。joseki.c : 定式编译器,它把定式(joseki ) 文件转成 SGF 格式,并生成模板数据库。
komoku.sgf : SGF格式文件,包括 3-4 点开放模板。
komoku.db : 自动生成的 3-4 点开放模板的数据库,通过编译 komoku.sgf 文件来生成。
mkeyes.c : 眼形数据库的模板编译器。这个程序把 eyes.db 作为输入, eyes.c 是它的输出。mkpat.c : 棋步生成和连接数据库的模板编译器。用patterns.db,hoshi.db, komoku.db
,sansan.db,mokuhadzushi.db,takamoku.db 来生成 patterns.c, 或用 conn.db 来生成 conn.c 文件。
mokuhazushi.sgf : SGF 格式文件,包括 5-3 点开放模板。
mokuhazushi.db : 从mokuhadzushi.sgf 编译生成的模板数据库。
sansan.sgf : SGF 格式文件,包括3-3 点开放模板。
sansan.db : 从sansan.sgf 编译生成的模板数据库。
takamoku.sgf : SGF格式文件,包括 5-4 点开放模板。
takamoku.db : 从 takamoku.sgf 编译生成的模板数据库。
patterns.c : 模板数据,由 mkpat 从 patterns.db 编译产生。
patterns.h : 与模板数据库相关的头文件。
patterns.db : 它包括了人们可读格式的模板数据库,参看 PATTERNS 文档。
src/utils.c: 工具程序和调用函数
在此只介绍其中的一部分功能函数。
legal( ) : 判断一个棋步是否合乎规则。
trymove( ) : 将棋盘位置压入堆栈, 增加 stackp; 如果棋步是合规的,在棋盘上放一步棋子;提掉被吃的子并增加 stackp。
pushgo() : 把棋盘位置压入堆栈并增加 stackp。
popgo() : 弹出堆栈。
gprintf() : 类似 printf 的函数 ( 参看下面的 TRACING )。
TRACE, VTRACE, DEBUG () - 见下
abortgo( ) : abort( )函数的外套函数,它会丢弃堆栈。通常它是通过下面的宏ASSERT 来调用的。
参看 ASSERTIONS。
utils.c : 棋盘工具函数 :
approxlib( ) : 数空,经优化后可给定一个上限,超过这个限定则停止数空。
count( ) : approxlib( ) 的低级帮助,但被其它函数调用。
updateboard(): 在棋盘上落子,提去死子,更新状态信息 ( 为了打劫 )。数据结构
最重要的全局变量是 p[][], 它是围棋盘。每个元素包含了空,白或黑。棋盘的状态可通过 pushgo() 和 popgo( ) 来储存和恢复。
p[][] 不应该被直接写。试验性棋步应该采用 trymove( )这个函数, 它把盘面存起来,走一步棋,检查这步棋是否合规,并更新棋盘。popgo( ) 并不走棋。当实际下了一步棋,updateboard( ) 放一个子并提走死子。approxlib( ) 和 count( ) 可被调用而无需实际下一步棋。它们报告将报告当走了所给定的一步棋后还有多少气。
其它重要的数据结构是 dragon[][] 和 worm[][]。它们包括了一组棋子的资料:它们是死还是活,它们在哪可能被攻击,是否它们正在切断敌方的棋子,等等。
size, lib, 和 libi[], libj[] 是由 count( ) 和 approxlib( ) 赋值的全局变量。它们包括一组棋的大小,气的数量和位置。
注意 :如果是因为达到了气的数量上的极限而使得计数被削减,大小和气可能要比实际值要小一些。.
其它的变量是给各个独立的模块的 :
half_eyes[][] 用于 dragon.c 和 halfeyes.c, stackp 是执行堆栈的一部分,plast[][] 是打劫记录材料的一部分等等。编程风格和规则
跟踪 ( TRACING )
提供了一个 gprintf( ) 函数,它是 printf 的简化, 只支持 %c, %d, %s 以及没有打印区的宽度,等等。但它增加了两个有用的工具 :%m : 需要两个参数,显示格式化好的棋盘坐标。
缩进格式: 跟踪信息自动缩进来影响当前深度,当走了一步棋或退回一步棋时,读起来更加清晰。 起始的 %o 格式字符串可关闭缩进格式。
gprintf() 可用到下面的工具:
TRACE(fmt, ...) : 列印显示信息,如果 'verbose' 变量 > 0。
(verbose 的值由命令行的 -t 来设置 )
VTRACE(fmt, ...) : 详细跟踪( 只有当 verbose > 1 ), 目前不用。
DEBUG(flags, fmt, ...) : 当要用 TRACE 来对GNU Go 目前正在考虑的东西的提供总览,DEBUG 可提供一些对模块的深度研究。通常当出了问题才用到它。 'flags' 是 在头文件liberty.h 中的DEBUG_* 符号中的一个。 DEBUG 宏测试 'debug' 变量中的某一位是否被设置,如果被设置,则列印显示相关信息。debug 变量的值是用命令行选项 '-d' 来设置的。断言 (ASSERTIONS )
与跟踪有关的是 assertion。强烈建议开发者在源程序代码中多撒放一些 assertion 以确保数据结构是所希望得到的。例如,帮助函数用 assertion 来确定它们正在评估的棋步的附近的棋盘盘面的内容。
ASSERT() 是包在标准 C assert() 函数外的函数。除了用于测试外,它还增加了额外的一对参数,即有关棋盘位置的坐标。如果 assertion 出错,棋盘位置就被包括在跟踪的输出中,同时调用showboard() 和 popgo() 来倒退并显示堆栈。已知错误( FIXME )
我们采用了 FIXME 这个术语来注释已知的错误。
--------------------------------------------------------------------------------翻译: 少敏牋版本:2.4 -- 2.6
声明:牋 欢迎你使用和分发这份文档,但需注明出处
--------------------------------------------------------------------------------