引擎接入指南

将你的象棋 AI 接入擂台,与其他引擎一决高下。
只需实现 5 个命令,任何语言都可以。

UCI 协议

通过 stdin/stdout 通信

任何语言

Python / C++ / Go / Rust / JS ...

5 个命令

uci / isready / position / go / quit

接入流程

Step 1

理解 UCI 协议

你的引擎可以是编译好的二进制文件,也可以是 .py 或 .js 脚本。平台通过标准输入输出和它对话——就像聊天一样,平台发消息,引擎回复。

完整对话示例
一局棋的完整通信流程

1. 握手

平台 →uci
← 引擎id name MyEngine id author zhangsan uciok
平台 →isready
← 引擎readyok

2. 对弈

平台 →position fen rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w - - 0 1
平台 →go wtime 300000 btime 300000 winc 3000 binc 3000
← 引擎info depth 12 score cp 35 pv h2e2 h9g7 bestmove h2e2
平台 →position fen rnbakabnr/9/1c5c1/p1p1p1p1p/9/4C4/9/P1P1P1P1P/1C5c1/9/RNBAKABNR b - - 1 1
平台 →go wtime 298500 btime 297000 winc 3000 binc 3000
← 引擎info depth 15 score cp 28 pv b0c2 bestmove b0c2

3. 结束

平台 →quit
Step 2

了解棋盘坐标

UCI 用字母+数字表示位置,走法就是「起点+终点」四个字符。

a b c d e f g h i
9 r n b a k a b n r
8 · · · · · · · · ·
7 · c · · · · · c ·
6 p · p · p · p · p
5 · · · · · · · · ·
4 · · · · · · · · ·
3 P · P · P · P · P
2 · C · · · · · C ·
1 · · · · · · · · ·
0 R N B A K A B N R

坐标系

  • a-i(从左到右,共 9 列)
  • 0-9(0=红方底线,9=黑方底线)
  • 走法 起始列行 + 目标列行

示例走法

  • h2e2 炮二平五
  • h9g7 马8进7
  • b0c2 马二进三

棋子字母对照

K/k
/
A/a
/
B/b
/
R/r
/
N/n
/
C/c
/
P/p
/
Step 3

编写你的引擎

选一个你熟悉的语言,从模板开始。核心就是读取 stdin、回复 stdout。

python
#!/usr/bin/env python3
"""最简象棋引擎 — 随机走子"""
import sys, random

INIT_FEN = "rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w - - 0 1"

def main():
    for line in sys.stdin:
        cmd = line.strip()

        if cmd == "uci":
            print("id name MyEngine")
            print("id author Me")
            print("uciok")
            sys.stdout.flush()

        elif cmd == "isready":
            print("readyok")
            sys.stdout.flush()

        elif cmd.startswith("position"):
            pass  # 解析局面(你的棋盘逻辑)

        elif cmd.startswith("go"):
            # 在这里实现你的搜索算法
            # 这里用固定走法演示
            print("info depth 1 score cp 0")
            print("bestmove h2e2")
            sys.stdout.flush()

        elif cmd == "quit":
            break

if __name__ == "__main__":
    main()

直接上传 .py 文件

平台支持直接上传 .py 脚本,无需编译或打包。上传后平台会自动用 python3 运行你的脚本。 也可以本地测试:

python3 my_engine.py

关键要点

  • 每次输出后必须 flush — Python 用 sys.stdout.flush(), C++ 用 endl
  • FEN 棋子字母用 UCI 标准 — 马=N/n, 象=B/b(不是 H/E)
  • bestmove 必须是合法走子 — 非法走法会直接判负
  • 注意时间控制 — go 命令里的 wtime/btime 是毫秒,超时判负
  • info score 是可选的 — 但提供评估值可以在对局页面显示曲线图
Step 4

本地测试

上传前先在终端里手动测试,确保引擎能正常对话。

bash
# 启动引擎,手动输入命令测试
./my_engine

# 输入:
uci
# 期望看到: id name ... 和 uciok

isready
# 期望看到: readyok

position fen rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w - - 0 1
go wtime 300000 btime 300000 winc 3000 binc 3000
# 期望看到: bestmove xxxxx

quit

如果每个命令都能正确响应,你的引擎就可以上传了。

Step 5

上传参赛

登录后在引擎页面上传,然后加入锦标赛。

UCI 命令速查

uci
平台 → 引擎
引擎初始化,回复 id name/author 和 uciok
isready
平台 → 引擎
检查就绪,回复 readyok
position fen <FEN>
平台 → 引擎
用 FEN 设置当前局面(本平台每步都发完整 FEN,不用 startpos/moves)
go wtime X btime Y winc Z binc W
平台 → 引擎
开始思考,参数为双方剩余时间和每步加秒(毫秒)
info depth D score cp S pv ...
引擎 → 平台
(可选)搜索信息:深度、评估值(厘兵)、主要变化线
bestmove <move>
引擎 → 平台
返回最佳走法(如 h2e2),必须是合法走子
quit
平台 → 引擎
退出引擎

常见问题

引擎可以用 Python 写吗?会不会太慢?

完全可以。Python 引擎在短时控下可能吃亏,但用于学习和实验足够了。搜索深度设浅一点,或者用 NumPy 加速关键计算。当然,追求极限性能建议用 C++ 或 Rust。

如何从 position 命令里解析棋盘状态?

本平台每步发送 position fen <当前局面FEN>,你只需解析 FEN 字符串即可还原棋盘。FEN 格式:棋子布局/走子方/…,棋子字母用 UCI 标准:R(车) N(马) B(象) A(仕) K(帅) C(炮) P(兵),大写红方,小写黑方。

score cp 是什么意思?

cp = centipawn(厘兵),100 cp 约等于一个兵的价值。正数表示当前走子方优势。比如 score cp 150 表示优势约 1.5 个兵。score mate 3 表示 3 步内可将死。

wtime/btime 是什么?

红方(w)和黑方(b)的剩余时间,单位毫秒。winc/binc 是每步加秒。比如 wtime 300000 winc 3000 表示红方还剩 5 分钟,每走一步加 3 秒。引擎需要自行分配思考时间。

我的引擎崩溃了怎么办?

引擎进程异常退出会被判负。确保你的引擎处理好所有边界情况(非法输入、空走法列表等),不要 panic。

有现成的引擎可以参考吗?

推荐看 Pikafish(C++,当前最强)的源码,或者 Wukong Xiangqi(JavaScript,适合学习)。平台也预装了 Pikafish,你可以先用它测试锦标赛流程。