對戰平台 · P6
讓不同人的 AI, 在同一張地圖上一較高下
公平只能由裁判保證,不能靠 Bot 自律。Bot 永遠碰不到共用記憶體:它只能拿到裁判依視野過濾後的觀察,只能提交動作,而且每個動作都會先校驗歸屬。
設計中 · 基礎實驗進行中 現在就照公平模式寫
三種形式
依「公平能不能保證」排序
本專案觀察能力的來源,正是「用戶端持有所有玩家的狀態」—— 這在你自己的電腦上同樣成立。所以公平只能來自一個大家都信任的裁判。先做 A,同一套協定直接升級到 B;C 只供娛樂。
A
本機擂台
一台電腦跑一局遊戲,每個 Bot 各佔一個槽位,由裁判行程代替它們下令
裁判掌控一切:視野、歸屬、節拍
適合:開發偵錯、本地聯賽
B
託管天梯
把 A 搬到伺服器上;玩家上傳 Bot,伺服器在沙盒中執行
同 A,再加上程式碼隔離
適合:公開比賽、排名
C
各自連線
每人在自己的電腦上跑遊戲 + Bot,透過區域網路對戰
無法保證:被注入的用戶端能讀取全圖
適合:朋友之間的友誼賽
裁判
一個行程,替雙方下令
Bot A任何語言
Bot B任何語言
WebSocket · JSON
裁判(可信任)
- 編排 選地圖、開局,依槽位設定種族和難度
- 節拍 每 T 遊戲毫秒一拍(預設 200);鎖步模式下,傳送觀察時會暫停遊戲
- 觀察 快照 → 依每個槽位的視野過濾 → JSON
- 動作 校驗「單位屬於這個槽位」→ 預算(每拍條數、APM)→ 透過快車道批次下達
- 紀錄 每拍的觀察摘要 + 每個動作:可重播、可覆盤、可作為訓練資料
- 判定 某槽位沒有建築 → 出局;逾時 → 依剩餘戰力/資源判定
快車道 · player 車道 ×2
一局遊戲 · 兩個槽位
協定草案 v0
觀察進,動作出
任何能收發 JSON 的程式都能上場 —— 包括直接讓 LLM 逐拍輸出動作。用 SDK 寫的 Python Bot 不需要修改程式碼。
| 觀察 | 只包含我方單位 + 我方視野內的敵方單位;野怪、金礦依視野或開局時公開 |
| 動作上限 | 每拍最多 32 條,超出的部分截掉(防止洗命令拖慢裁判) |
| 同一單位 | 同一拍只認最後一條 |
| 時間預算 | 拍長 × 0.9,逾時則這一拍略過;慢的一方自己吃虧,不拖累別人 |
| 鎖步 | 需要嚴格公平時,傳送觀察時暫停遊戲、收齊(或逾時)後再繼續 —— 電腦快慢不影響結果 |
| 交換出生點 | 同一組 Bot 雙方各打一次,消除地圖不對稱 |
| 天梯 | Elo / TrueSkill;每組至少打 20 局再下結論(2 局能看出的最小勝率差約 60 個百分點) |
{"t": "obs", "tick": 57, "gameMs": 11400, "me": 1,
"res": {"gold": 320, "lumber": 150, "food": [18, 30]},
"units": [
{"id": 101, "type": "hfoo", "owner": 1,
"x": -4500, "y": 2200, "hp": 380, "hpMax": 420}],
"visibleEnemies": [
{"id": 733, "type": "ogru", "owner": 2,
"x": -3900, "y": 2500, "hp": 700}],
"deadlineMs": 180} 每拍一份,只包含這個槽位的單位和它視野內的敵人。
id 是裁判分配的穩定編號,整局不變。 {"t": "act", "tick": 57, "actions": [
{"do": "attack", "unit": 101, "target": 733},
{"do": "train", "unit": 5, "code": "hfoo"},
{"do": "cast", "unit": 7, "spell": "thunderbolt", "target": 733},
{"do": "move", "unit": 102, "x": -5000, "y": 2000}]} 動作集合 = api.json 裡
category == "command" 的那些,參數名稱相同。遲到的 act 會被丟棄,這一拍視為略過。 from openwar3 import Bot
class MyBot(Bot):
def on_tick(self, g): # 同一份程式碼:本機的 g 是 Game,擂台上的 g 是 ArenaGame
for w in g.idle_workers():
g.gather(w, g.nearest(g.gold_mines(), w))
# 本機: python tools/play.py --bot my_bot.py --fair
# 擂台上: 同名方法,底層走 WebSocket —— Bot 程式碼一行都不用改 介面層的抽象就是為此設計的:用 SDK 寫的 Bot 只要把
Game 換成 ArenaGame 就能上場。 基礎實驗
依序進行,前一項沒通過就不做下一項
| # | 實驗 | 判定標準 | 已知 |
|---|---|---|---|
| 1 | 一局裡開 2 個槽位,都不帶內建 AI | 雙方單位都不動 | 槽位的 AI 標記和難度欄位已知 |
| 2 | 替本機以外的槽位下令 | 敵方槽位的農民真的去採礦 | 最關鍵的一項:沒通過就只能退回「每個 Bot 一個用戶端、走真正的連線對戰」 |
| 3 | 依任意玩家編號查詢視野 | 同一點對兩個槽位給出不同結果 | 引擎的可見性檢查接受任意玩家編號 |
| 4 | 以程式判定勝負 | 一方建築全滅時 1 秒內得知 | 事件匯流排有更直接的入口 |
| 5 | 鎖步暫停/繼續 | 暫停中收齊動作、恢復後生效 | 暫停已驗證 |
順帶的一次檢驗:參考大腦目前大量依賴全圖資訊(例如電腦對手的進攻目標)。上擂台需要改用門面 API、只使用視野內的單位 —— 少了全圖資訊,它還剩多強?