- 桌面应用
【免费下载链接】Sabaki
An elegant Go board and SGF editor for a more civilized age.
Sabaki 是一款基于 Electron 的 SGF 编辑器与棋盘应用,而 docs/guides/engines.md 描述的核心能力是:把任何支持 GTP(Go Text Protocol)的围棋引擎进程接入 Sabaki,让你能离线与 AI 对弈、观看引擎自评分析,或让两个引擎自对弈。本文以该文档为主体,结合 src/modules/enginesyncer.js、src/modules/sabaki.js 等源码,讲清楚引擎如何配置、如何被 Sabaki 启动与同步、对弈与分析流程的底层实现,以及配套的调试手段。
一、GTP:Sabaki 与引擎之间的统一接口
Sabaki 本身不内置任何围棋 AI,它只做一件事:启动引擎进程,通过标准输入/输出(stdin/stdout)与之进行文本协议通信。因此:
- 只要一个引擎实现了 GTP 子集(
name、version、protocol_version、list_commands、play、genmove等命令),就能被 Sabaki 当作"对手"或"分析师"使用; - 引擎进程由 Sabaki 负责拉起和回收,无需手动在终端启动;
- 大部分引擎支持可选参数来调节能力(搜索深度、时间控制等),参数清单以引擎自身文档为准,在 Sabaki 里则填到引擎配置的
args字段中。
引擎进程的控制逻辑封装在@sabaki/gtp包中(package.json 中声明为"@sabaki/gtp": "^3.1.0"),Sabaki 侧的同步层 EngineSyncer 在此基础上实现状态跟踪与局面同步。
二、在偏好设置中配置引擎
在偏好设置抽屉的 "Engines" 页签下(src/components/drawers/PreferencesDrawer.js),每个引擎条目有 4 个字段,与源码中EngineItem渲染的输入框一一对应:
| 字段 | 含义 | 占位提示(源码原文) |
|---|---|---|
name | 引擎名称,用于在界面上区分多个引擎 | (Unnamed Engine) |
path | 引擎可执行文件路径 | Path (e.g., /path/to/engine or C:\path\to\engine.exe),旁边有 Browse 按钮用系统对话框选择 |
args | 传给引擎的可选启动参数 | Optional arguments (e.g., -param1 value1 -param2 value2) |
commands | 引擎启动后自动执行的初始 GTP 命令,多条用分号;分隔 | Initial commands (;-separated) |
配置保存在设置项engines.list(数组),见 src/setting.js。相关的引擎/GTP 默认配置还有:
// src/setting.js 'engines.list': [], 'engines.analyze_commands': ['analyze', 'kata-analyze', 'lz-analyze'], 'engines.gemove_analyze_commands': [ 'genmove_analyze', 'kata-genmove_analyze', 'lz-genmove_analyze', ], 'gtp.console_log_enabled': false, 'gtp.console_log_path': null, 'gtp.engine_quit_timeout': 3000, // 退出(quit)等待超时,毫秒 'gtp.move_delay': 300, // 引擎落子相关延迟 'board.analysis_interval': 50, // analyze 命令的更新间隔(厘秒)从源码结构看,引擎列表在偏好设置抽屉关闭时还会按名称做自然排序后写回engines.list(PreferencesDrawer.js),因此界面上引擎按名称有序展示。
三、常用引擎与启动参数速查
docs/guides/engines.md 给出的引擎清单及推荐启动参数如下(path指向引擎可执行文件,args填下表内容):
| 引擎 | 获取方式 | args(启动参数) | 支持分析 |
|---|---|---|---|
| Leela Zero | 下载适合自己系统的版本(提供二进制与源码),再获取网络权重文件(通常取"最佳网络") | --gtp -w path/to/weightsfile | 是 |
| KataGo | 从 Releases 下载对应系统、含预训练模型的版本 | gtp -model /path/to/model.txt.gz -config /path/to/gtp_example.cfg | 是 |
| GNU Go | Windows 有二进制;Linux / macOS 需自行编译源码;另有 OS X 10.4.3+ 的通用二进制 | --mode gtp | 否 |
| Pachi | Windows / Linux 有二进制,源码可编译 | 无(None) | 否 |
| Leela | 下载 "engine only (commandline/GTP engine)" 版本 | --gtp | 否 |
| AQ | 开源引擎 | 无(None) | 否 |
| Ray | 开源引擎 | 无(None) | 否 |
注意两点细节:
- KataGo 的参数首词是子命令
gtp,而 Leela Zero、GNU Go、Leela 用的是--gtp这类开关;漏掉它们会导致引擎不进入 GTP 模式,Sabaki 启动后无法完成握手。 - 文档中明确标注"supports analysis as well"的只有 Leela Zero 和 KataGo,这对应 Sabaki 的连续分析功能(见第六节),其余引擎仅能用于对弈。
四、引擎生命周期:启动、握手与局面同步
引擎被添加后并不会立刻运行。只有当界面需要某个引擎时(分配给黑/白方、开始分析等),Sabaki 才会调用 attachEngines 创建EngineSyncer实例并start()对应进程。
4.1 进程拉起
EngineSyncer 构造函数 中,path先按当前工作目录resolve,若存在则用绝对路径;args经argvsplit解析为参数数组,工作目录设为引擎文件所在目录:
// src/modules/enginesyncer.js(节选) let absolutePath = resolve(path) let executePath = existsSync(absolutePath) ? absolutePath : path let executeArgs = [...argvsplit(args)] this.controller = new Controller(executePath, executeArgs, { cwd: dirname(absolutePath), })这里有一个针对 Flatpak 沙箱的特殊处理:当环境变量FLATPAK_ID存在时,沙箱内无法直接执行宿主机的引擎二进制,Sabaki 会自动改走flatpak-spawn --host --directory=<引擎所在目录>来启动,并保留工作目录(enginesyncer.js)。这解释了"在 Flatpak 版 Sabaki 中配置引擎路径仍指向宿主机路径也能工作"这一现象。
4.2 启动握手
进程started事件触发后,Sabaki 并发发送name、version、protocol_version、list_commands四条命令,并把list_commands的返回缓存为this.commands——后续是否走genmove_analyze/analyze流程正是依据这个列表判断的;随后若commands配置字段非空,还会按;拆分、依次发送这些初始命令(enginesyncer.js)。
4.3 把 SGF 局面同步给引擎
对弈或分析前必须让引擎的棋盘与当前 SGF 节点一致。sync() 实现了三级递进的策略:
- 重放(Replay):从根节点到目标节点,依次把
B/W/AB/AW属性转成play B xx/play W xx命令;对于 handicap 节点,若引擎支持set_free_handicap命令则优先用一条该命令摆出贴角子(enginesyncer.js); - 增量重排(Incremental rearrangement):若重放结果与目标局面不一致(例如 SGF 中有"提子后补下"这类 GTP 无法精确复现的历史),则基于引擎已接收的历史命令重算棋盘,只对差异点补发
play; - 全量重排(Complete rearrangement):仍不一致时,按目标棋盘逐格重放所有棋子。
同步前还有两个硬性校验,失败会直接抛出带提示的错误(i18n 文案见 enginesyncer.js):
- GTP 引擎不支持无效局面(非法棋子位置);
- 棋盘尺寸最大只支持 19×19(坐标字母表
ABCDEFGHJKLMNOPQRSTUVWXYZ共 25 个字母,源码按字母表长度做上限校验)。
同步参数还包括从 SGF 根属性读取的komi(KM,默认 0)与boardsize(enginesyncer.js)。三级重排后仍无法复现目标局面时,会报错 "Current board arrangement can't be recreated on the GTP engine."。
4.4 退出与超时
stop()通过controller.stop(quitTimeout)退出进程,quitTimeout即设置项gtp.engine_quit_timeout(默认 3000ms,见 setting.js)。另外 sendAbort() 会在引擎忙碌时尽力发送protocol_version打断当前长耗时操作,供queueCommand在发新命令前调用。
五、与引擎对弈:人机对战与引擎互搏
5.1 把引擎分配给玩家
在 Info 抽屉(游戏信息面板)中可以为黑方、白方分别选择引擎;InfoDrawer.js 的保存逻辑会为尚未 attach 的引擎调用sabaki.attachEngines([engine]),并把 syncer id 写入状态blackEngineSyncerId/whiteEngineSyncerId。菜单(src/menu.js)中的 "Start Engine vs. Engine Game" 则调用startStopEngineGame。
5.2 生成一步棋:genmove 与 genmove_analyze
generateMove 是"让引擎走一步"的统一入口:
// src/modules/sabaki.js(节选) let commandName = setting.get('engines.gemove_analyze_commands') .find((x) => syncer.commands.includes(x)) || 'genmove'即:若引擎的list_commands中声明了genmove_analyze、kata-genmove_analyze、lz-genmove_analyze之一,就优先使用该命令,并附带间隔参数board.analysis_interval(默认 50 厘秒)——引擎在思考期间持续输出info行供界面刷新,最终以play <vertex>结束;否则退化为普通genmove <color>,一次性返回坐标。
引擎返回resign时,Sabaki 会写入 SGF 结果属性RE(形如W+Resign/B+Resign)并弹提示;返回pass时落"虚手"节点并播放 pass 音效(sabaki.js)。
5.3 引擎互搏(engine vs engine game)
startEngineGame 在没有已绑定引擎时默认取列表前两个引擎分别绑黑、白,然后循环执行"轮到谁就调用谁的generateMove"。终止条件有三类:
- 任一方
resign; - 连续 2 次 pass(
consecutivePasses >= 2); - 用户中途停止(
engineGameOngoing不再等于当前对局 id)。
仓库的端到端测试 e2e/engine.spec.js 完整覆盖了对战链路:attach/detach 引擎、响应genmove、人类 pass 触发引擎应招(对应 issue #857)、以及 bot-vs-bot 对局完整走完(测试中的假引擎走 3 手后 resign)。这些测试使用的假引擎实现在 test/engines/resignEngine.js——它用@sabaki/gtp的Engine类实现了boardsize、clear_board、komi、play、undo、genmove六个命令,是理解"一个最小可用 GTP 引擎长什么样"的现成范例:
// test/engines/resignEngine.js(节选) engine.command('genmove', (_, out) => { if (stop === 0) { out.send(stopword) // resign 或 pass } else { out.send(`${alpha[rand()]}${rand() + 1}`) // 随机落子 } }) engine.start()六、引擎分析集成:analyze 命令与热力图
对于支持分析命令的引擎(KataGo、Leela Zero),Sabaki 提供逐节点连续分析,并把结果画成棋盘热力图。对引擎开发者而言,协议细节完整记录在 docs/guides/engine-analysis-integration.md:
analyze <color> <interval>:从指定方视角分析,每interval厘秒输出形如info <keyvalue>... pv <vertex>... (info ... )...的一行;genmove_analyze <color> <interval>:生成一手棋并持续输出info行,最终用play <vertex>结束;- 必需键值对:
move(被分析的棋点)、visits(累计访问数)、winrate(整数时是百分比×100,如9543表示 95.43%;带小数点时是 0.0–1.0 的小数); - 可选键值对:
scoreLead(该方走这手后的预计平均领先目数); - 响应会一直输出,直到
stdin收到新的输入才终止。
Sabaki 侧的解析与匹配逻辑:
- 命令匹配:analyzeMove 按
engines.analyze_commands(默认analyze、kata-analyze、lz-analyze)顺序,取引擎list_commands中第一个存在的命令;若一个都没有,则提示 "None of the attached engines support analysis."(menu.js)。 - winrate 方言:EngineSyncer 中按命令名前缀决定格式——
kata开头(kata-analyze等)报告的是 0–1 浮点胜率,lz-analyze/analyze报告万分之一整数; - 结构化解析:parseAnalysis 把一条
info ... info ...行拆成多个 variation,每个含vertex、visits、winrate(经 normalizeWinrate 归一化到 0–100)、scoreLead与pv变化序列,并刻意过滤掉截断/畸形片段以保证健壮性; - 热力图呈现:getAnalysisHeatMapCell 为每个落点计算叠加强度(
strength正比于visits × winrate)与标签文本,标签按board.analysis_type显示胜率百分比或scoreLead,并支持board.analysis_value_type切换绝对值/相对最优手的差值(此时最优手显示为 0)。更新频率由board.analysis_interval(默认 50ms)控制。
分析期间导航 SGF 节点时,若局面历史发生变化,treePosition会被置空并重新同步引擎(enginesyncer.js),保证热力图始终对应当前节点。
七、调试与验证:GTP 日志和现成的测试
7.1 GTP 控制台日志
偏好设置 Engines 页签顶部提供 "Enable GTP logging to directory" 开关与目录选择(对应gtp.console_log_enabled/gtp.console_log_path)。日志写入由 src/modules/gtplogger.js 实现:
- 每条记录带毫秒级时间戳,并标注方向:
(in)(stdin)、(out)(stdout)、(err)(stderr)、(meta),格式为<引擎名> <方向> : <消息>(gtplogger.js); - 日志文件命名为
sabaki_<时间戳>_<pid>.log,每次重新 attach 引擎会滚动到新文件(rotate()); - 若启用了日志但目录无效或不可写,Sabaki 会弹警告框要求修正或关闭该选项(gtplogger.js),且偏好设置抽屉关闭时若仍有引擎在运行会强制校验路径。
排查"引擎不响应/不认命令"问题时,打开此日志即可看到 Sabaki 与引擎之间的全部原始报文。
7.2 端到端自测
仓库内置了可运行的 Playwright 用例验证引擎链路,关键文件:
- e2e/engine.spec.js:attach/启动、clean detach、
genmove响应、人类 pass 触发引擎应招、bot-vs-bot 完整对局、加载 SGF 后局面同步; - e2e/helpers.js 中的
attachAndWaitForEngines/detachAndWait封装了测试用的挂接与清理; - test/engines/resignEngine.js 与 test/engines/replayEngine.js:两个不依赖外部模型的最小 GTP 引擎,分别演示"随机落子后 resign"和"按脚本重放"两类行为。
小结
回顾整条链路:在 Preferences → Engines 中登记{name, path, args, commands}→ 界面触发时attachEngines拉起进程并完成 GTP 握手 →EngineSyncer.sync三级重排把 SGF 局面灌入引擎 →generateMove对弈或analyze连续分析 → GTP 日志留痕、e2e 用例验证。只要引擎实现 GTP 基本命令集即可对弈,若再按 engine-analysis-integration.md 实现analyze/genmove_analyze输出约定格式的info行,就能无缝接入 Sabaki 的热力图分析功能。
- 桌面应用
【免费下载链接】Sabaki
An elegant Go board and SGF editor for a more civilized age.
相关推荐
【免费下载】 LizzieYzy - 围棋引擎图形界面
LizzieYzy 围棋引擎图形界面 项目基础介绍和主要编程语言 LizzieYzy 是一个基于 Lizzie 修改的围棋引擎图形界面,主要使用 Java 语言
桌面应用AI 应用围棋AI分析工具:LizzieYzy多引擎图形界面全攻略
围棋AI分析工具:LizzieYzy多引擎图形界面全攻略 LizzieYzy是一款基于Java开发的围棋AI分析工具,通过直观的多引擎图形界面为围棋爱好者提供专
桌面应用AI 应用围棋AI分析工具LizzieYzy:多引擎图形界面全面解析
围棋AI分析工具LizzieYzy:多引擎图形界面全面解析 LizzieYzy是一款专业的围棋AI分析工具,通过直观的多引擎图形界面为围棋爱好者提供深度棋谱分析
桌面应用AI 应用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考