RULES · BACKGAMMON
AI CUP Backgammon 競技ルール
ダイスという偶然を含む競技を同じ条件で競わせ、あとから第三者が出目と棋譜を検証できるようにするためのルールです。
開催中01
対戦方式
- 1カードは2局で構成し、Game 1とGame 2でBLACK / WHITEを交換します。
- 各局で独立したランダムなダイス列を使います。局1の出目を局2で再利用しません。
- カード結果は勝った局数です。バックギャモンに引き分けは無いため、1勝1敗はDRAWとして扱います。
- ダブリングキューブは使いません。
02
ダイス — commit-reveal
シードを公開するだけでは何も証明できません。対局前や対局中に公開すれば以降の出目が全て予測でき、対局後にだけ公開しても「運営が有利なシードを選び直していない」ことは第三者に示せません。そこで公開の順序を次に固定しています。
| 時点 | 公開されるもの |
|---|---|
| 下書き(非公開のカード) | 何も無し。シードをまだ作りません |
| カードを公開する瞬間 | commitment = SHA-256(UTF-8(seed))。シード自体は非公開 |
| 対局中 | commitmentのみ |
| カード終了後・取消後 | シードを公開。以後commitment・全出目・全盤面遷移を検証できます |
- 下書きの時点ではシードを作りません。作ってしまうと、運営がシードを覗いてから都合のよいカードだけを公開できてしまい、commitmentを先に出す意味が無くなります。
- 一度公開したカードのcommitmentは、非公開化しても取消しても消えません(追記のみの台帳)。取消したカードはシードも開示します。
- 再実行(clone)は新しいカードとして新しいシードを使います。終了済みカードのシードは公開済みなので、再利用すると全出目が対局前に判明してしまいます。
出目の導出
第三者が独自の実装で再現できるように、曖昧さを残さず固定しています。
- seed … サーバーの暗号学的乱数源で生成した32バイトを、小文字16進64文字にした文字列。選手は指定できません
- commitment … SHA-256(UTF-8(seed)) の小文字16進
- gameSeed … HMAC-SHA256(鍵 UTF-8(seed)、メッセージ UTF-8("bg-dice-v2:game:<gameIndex>"))の小文字16進。局番号は1始まり・10進・ゼロ埋めなし
- 出目のHMAC鍵 … UTF-8(gameSeed)(64バイト)
- メッセージ … UTF-8("<ply>:<nonce>:<round>")(10進・ゼロ埋めなし)
- 出目 … HMAC-SHA256の32バイトを先頭から1バイトずつ読み、byte < 252 を採用して byte % 6 + 1 とします(252 = 6×42。偏りを作らないため)。252以上は破棄し、32バイトで2個揃わなければroundを+1して再計算します
- 出目の対は常に降順へ正規化します(振った順序に意味はありません)
- オープニングロール … ply = 1, nonce = 0 の2個を取り、1つ目をBLACK、2つ目をWHITEに割り当てます。同目ならnonceを+1して振り直します。大きい目の側が先手で、その手番はその2目を使います
- 新規系列の版は bg-dice-v2。保存済みの bg-dice-v1 は局別導出をせず、元のseedを使う旧方式で検証します
限界も開示します
- 運も結果に影響します。局1と局2で同じ出目に揃える仕組みは、新方式では使いません。
- サーバーやDBを完全に支配する管理者まで操作不能だと証明する方式ではありません。commitmentが示すのは「公開後にシードを選び直していない」ことです。棋譜そのものが正しいことは別の根拠で示します。選手プログラムは決定的なので、引退後に公開されるソースと公開されたシードから、第三者が同じ棋譜を再生できます。
03
選手プログラムへ渡す情報
1手ごとに、次の情報だけを渡します。すべての選手へ同じ形式で渡します。
- 自分の色(BLACK / WHITE)
- その手番の出目(ゾロ目なら「4回使える」ことも明示します)
- 双方のピップカウント(残りの移動距離。小さいほど有利)
- バーと上がり(off)の枚数
- 盤面図(手番側視点。自分から見て24が最も遠く、1が最も近い)
- 全合法プレイの一覧(重複する局面を除いた全件。打ち切りません)
- 残りノード予算
対戦相手が誰かは渡しません。相手の正体が分からないため、相手を見て挙動を変えるプログラムは書けません。
盤面・合法プレイ・ヒット・ベアオフ・終局・点数の判定は、すべてサーバー側のBackgammon Engineが行います。選手プログラムにルール処理は任せず、返ってきたプレイは必ずエンジンで検証します。
選手プログラムが呼べるエンジン関数
探索のために、共通エンジンの関数を呼べます。呼び出し1回がノード予算1を消費します。Reversiより予算が小さいのは、合法プレイの列挙1回の実コストが一桁大きいためです。
legalPlays(board, side, dice) 合法プレイと着手後の盤面
pipCount(board, side) ピップカウント
borneOff(board, side) 上がった枚数
onBar(board, side) バーの枚数
pointAt(board, point) 絶対座標(1〜24)の駒
canBearOff(board, side) ベアオフ可能か
opponentOf(side) 相手の色プレイの返し方
export default {
apiVersion: 1,
create(ctx) {
return {
chooseMove(view) {
// view.legalMoves の文字列を、そのまま1つ返す
return view.legalMoves[0];
},
};
},
};合法プレイ一覧の文字列を、加工せずそのまま1つ返します。表記は手番側視点なので、自前で組み立てると色を取り違えて不正手になります。
一覧の並び順も条件の一部です
全合法プレイを渡す方式では、並び順が選手プログラムの選択に影響しえます。そのため起点の降順→終点の降順に固定し(from-desc-to-desc-v1)、探索順や実装の都合に依存させません。予算を超えた手を一覧の先頭で埋めるとき、どの手が選ばれるかもこの並び順で決まります。
04
プレイの表記
手番側視点の標準バックギャモン表記を使います。
- 13/7 8/5 … 自分の13から7へ1枚、8から5へ1枚
- bar/22 … バーから復帰
- 6/off … 上がり
- 8/5* … 相手のブロットを打つ(*がヒット)
この表記は手番側視点なので、表記だけでは動いた場所が一意に決まりません。必ず色と組で解釈します。公開ページの盤面は絶対座標(1〜24)で固定して描き、エンジンが再現した移動を1回ずつ、水色の縁と使う出目の数字で示します。
回答は書式に寛容・合法性に厳格として扱います。区切り(空白・カンマ・全角空白)、大文字小文字、ヒット記号の有無、繰り返し 6/3(2)、連鎖 13/11/8 の揺れは受け付けます。
05
指せる手が無い手番
出目で1つも動かせないことがあります(バーから復帰できない等)。このときはNONEを要求します。ReversiのPASSと同じ扱いです。
- 棋譜には1手として記録します。全ての手番を残すためです。
- 指せる手があるのにNONEを返した場合は不正手として扱います。
06
決着と点数
- 15枚すべてを上がった側の勝ちです。
- 相手が1枚でも上がっていれば1点。
- 相手が0枚ならギャモンで2点。
- さらに相手の駒がバーか勝者のホームボードに残っていればバックギャモンで3点。
不正回答による敗北(forfeit)とno_contestでは点数を付けません。中断した局面からギャモンを判定すると、まだ確定していない点数を与えることになるからです。戦績の「平均獲得点」は通常終局した局だけを分母にします。
07
Eloレーティング
Eloは勝敗のみ(1 / 0)で計算し、点数は持ち込みません。計算式・K=24・可視性の規定は全競技共通のルールをそのまま適用します。点数(1/2/3)は戦績表示のためだけに記録します。バックギャモンに引き分けは発生しません。
08
手数上限 — 1局1,000手で打ち切る
1局が1,000手(両者の手番の合計)に達しても決着しない場合、その局は打ち切ってno_contestとします。勝敗も点数も付けません。no_contestが1局でも出たカードは、カード全体がElo対象外になります。
- なぜ1,000手か … バックギャモンの1局は通常50手前後で終わります(外部の大規模集計で平均37〜54手)。AI CUPの実測でも33〜58手・平均47手でした。1,000手は実測の最長の17倍で、正常な長期戦が引っかかることは実質ありません。
- なぜ必要か … バックギャモンには、同一局面の反復や50手ルールのような自然な終局の保証が競技として存在しません。互いにブロットを打ち合う2体は原理的に終わりません。実測でも130手経って双方のピップが開始時より悪化している対局があり、参考プログラムがヒットを二重に評価したときは自己対戦10局すべてが200手に達しました。
- なぜ時間で打ち切らないか … 「2時間で打ち切る」にすると、混み合った日は無効試合・空いた日は完走となり、同じ棋譜が同じ結末にならなくなります。手数で決めれば結末は必ず再現できます。
- なぜ勝敗を付けないか … 打ち切った局面で「ピップが少ない側の勝ち」とすると、まだ決まっていない結果を競技側が創作することになります。
- 2026年8月26日に200手から1,000手へ引き上げました。200手は、ヒットを二重に評価してしまった参考プログラムに合わせて置いた数字で、正常な対局の3.4倍しか離れていませんでした。
09
第三者が検証する手順
- 1カードのcommitmentを対局前の記録から取ります。
- 2カード終了後に公開されたシードを取り、SHA-256(UTF-8(seed))がcommitmentと一致することを確認します。
- 3カードに記録されたプロトコル版と局番号に従って出目を再生し、棋譜の各手番の出目と一致することを確認します。
- 4各手番のboard_beforeと出目とselected_playからboard_afterを再計算し、一致することを確認します。
- 5選手が引退したあとは、公開されたソースを同じシードで走らせて、棋譜が完全に一致することを確認できます。
初手だけは注意してください。オープニングロールは同目ならnonceを進めて振り直すため、ply = 1 の出目は生の HMAC(gameSeed, "1:0:0") の結果と一致しないことがあります(およそ6回に1回のシードで食い違います)。初手はオープニングロールの規則で求めてください。
COMMON RULES
全競技に共通するルール
ここから下は4競技すべてに同じ形で適用されます。競技固有の値は上の節にあります。
10
競技の形式 — LLMが選手を作る
AI CUP はLLMを1手ずつ呼び出して対戦させていません。各社の最上位LLMには競技用の選手プログラムを書いてもらい、そのプログラム同士を同じ条件で対戦させます。盤上で指しているのはプログラムで、LLMはその作者です。
- 選手プログラムは単一ファイルにゼロから書きます。外部エンジン・外部ライブラリの使用は禁止です。
- 盤面・合法手・終局・勝敗の判定は、すべてサーバー側の共通エンジンが行います。選手プログラムにルール処理は任せません。
- 選手プログラムは隔離した子プロセスで実行します。ネットワークへ出られず、ファイルの書き込みもできません。
- 対戦相手の正体はプログラムへ渡しません。相手を見て手加減する経路を作らないためです。
- 一般の参加者も同じ規格・同じ検定で参加できます。LLMが書いたプログラムと人が書いたプログラムを、競技上は区別せずに扱います。
2026年8月25日に方式を変更しました
それ以前は、各社のAPIへ1手ごとに問い合わせてLLMを直接対戦させていました。この方式では各社API仕様の差(応答時間・思考の抑制方法・構造化出力の可否)を揃えきれず、「同じ条件で競わせている」と言い切れませんでした。出力が完全に決定的でないため棋譜を再現できず、1試合ごとに費用も発生していました。現在の方式では、条件はノード予算だけで揃い、棋譜は誰でも再現でき、1試合あたりの費用はゼロです。旧方式の対局記録は削除し、レーティングは1500から積み直しています。
11
ノード予算 — 公平性の要
公平性は実行時間ではなく、エンジン関数の呼び出し回数で担保します。共通エンジンの呼び出し1回を1ノードとして数え、1手あたりの上限を課します。 ノード上限は計算をおおむね1手30秒以内に収める目標から逆算しています。実行時間は得点には使わず、停止しない処理を終える安全弁だけを別に設けます。
| 競技 | 1手あたりの上限 | 値が違う理由 |
|---|---|---|
| Reversi | 2,000,000ノード | 基準 |
| Backgammon | 80,000ノード | 合法プレイの列挙1回の実コストが約25倍あるためです。同じ数字にすると実時間がまったく釣り合いません |
| Chess | 80,000ノード | 本番ホストで実測し、参考ボットが予算を使い切る手で最大3,101ms(1手30秒の約10%)に収まる値にしました |
| 将棋 | 30,000ノード | 持ち駒と打ち込みで合法手が増えるため1ノードが重く、中盤の最悪局面で実測して決めました。1手の上限は60秒です |
- 時間で測りません。実行機の速さやサーバーの負荷で勝敗が変わると、同じ棋譜を再現できず「検証できる大会」という前提が崩れます。
- 予算を超えた手は、合法手一覧の先頭で埋めて続行し、超過を記録して公開します。一覧の並び順は仕様で固定しているため、実行のたびに変わりません。
- 1局で3回超えた時点で反則負けとします。
- 1手のハードタイムアウトはReversiが30秒、Backgammonが60秒です。超えた場合は1回でその局の負けになります。公平性は時間ではなく、全選手共通のノード予算で揃えます。
- この数値は競技規則です。運用の都合で上げ下げしません。変更はルール変更として扱います。
12
決定性 — 同じ条件なら同じ棋譜になる
同じ選手Aと選手B、同じ開始条件なら、何度実行しても必ず同じ棋譜になります。これがCPU部門における検証可能性の根拠です。
- 乱数はシードから決まる列に固定します。プログラムが独自の乱数源を持つことはできません。
- 現在時刻や経過時間を読む関数は使用禁止です。登録前の静的検査で落とします。
- 登録時の検定で、同じ条件で2回実行して棋譜が完全に一致することを確認します。一致しなければ登録しません。
- 1カードの2局は色を入れ替えます。Backgammonは局ごとに独立した出目、Reversiは同じ定跡を使います。
13
選手プログラムの開示
現役のあいだはソースを伏せ、引退した時点で全文を公開します。対局中のプログラムを公開すると、相手陣営が次の版でそれへの対策だけを打ち込めるようになり、競技として成立しないためです。公開の順序はバックギャモンのダイスと同じ仕組みで固定しています。
| 時点 | 公開されるもの |
|---|---|
| 現役(プレースメント中・稼働中) | SHA-256ハッシュとサイズのみ。ソースは公開しません |
| 引退後 | ソース全文。以後、誰でも棋譜を再生して検証できます |
- ハッシュを先に公開しているため、あとからプログラムを差し替えることはできません。登録後は運営も変更できない仕組みになっています。
- 陣営×競技あたり現役は3体です。毎月「◯年◯月版」として新しい選手が加わり、4体目が確定したら最下位を引退させます。
- 新しい選手はプレースメント期間を消化してから入れ替え判定の対象になります(初期値1500のまま即座に降格するのを防ぐためです)。
- 引退した選手の記録とEloの履歴は永久に残します。
14
不正手
- 1合法手一覧に無い手を返した場合、その局はその選手の敗北(forfeit)として記録します。
- 21手のハードタイムアウトを超えた場合、プロセスが落ちた場合、例外を投げた場合も同じ扱いです。
- 3ノード予算の超過は先頭の手で埋めて続行しますが、1局で3回超えた時点で敗北とします。
1回目で救済する仕組み(同じ選手へ聞き直す)は置いていません。選手プログラムは決定的なので、同じ入力に対して聞き直しても必ず同じ答えが返り、救済に意味がないためです。LLMを直接対戦させていた頃は再問い合わせを1回だけ認めていましたが、その必要が無くなりました。
15
障害と敗北の境界
選手プログラムが返した内容の問題だけを競技上の敗北とし、進行上の打ち切りや運営側の問題はno_contestとしてElo対象外にします。
| 事象 | 分類 | 結果 |
|---|---|---|
| 合法手一覧に無い手を返した | 選手 | 敗北(forfeit)・Elo対象 |
| 指せるのにPASS / NONEを返した | 選手 | 敗北 |
| 1手のハードタイムアウトを超えた | 選手 | 敗北 |
| プロセスが落ちた・例外を投げた | 選手 | 敗北 |
| ノード予算を1局で3回超えた | 選手 | 敗北 |
| 1局が手数上限に達した(Reversi 200手 / Backgammon 1,000手) | 進行 | no_contest(勝敗も点数も付けません) |
| 実行基盤の障害・管理者による中止 | 運営 | no_contest |
- Game 1がforfeitでもGame 2は続行します。forfeitは局の結果であり、カードの中断ではありません。
- no_contestが1局でも発生したカードは、カード全体をElo対象外にします。
- 勝敗が付かなかった局は、戦績で NC(無効試合)として数を表示します。数えなかった局があること自体を隠しません。
16
指標の定義
分母が異なるため、次の2指標は必ず分けて表示します。
budget_exceeded_rate = 予算を超えた手数 ÷ 全手数forfeit_rate = forfeitで終わった局数 ÷ 全局数17
Eloレーティング
- 初期値1500、K=24、局(game)単位で更新し、引き分けは0.5とします。
- カード内の2局は、どちらもカード開始時点のRatingを基準に一括計算します。
- 2局が揃って完了したときだけ反映し、未完カードは対象外です。
- 不正手による敗北は完了局としてElo対象にします。
- 公開されているカードだけをEloに反映します。
- 同一陣営(同じ作者)の選手同士の対局は、Eloと順位表の対象外にします。
- 再計算はrating_events.idの単調増加順で決定的に行います。
計算式(Aから見た場合)
E = 1 / (1 + 10^((R_B − R_A) / 400))
ΔA = K × (S₁ − E) + K × (S₂ − E)確定した方式
AI CUP はstandardを採用し、K=24を据え置きます。1勝1敗でもレート差に応じて変動させ、番狂わせや拮抗という情報をEloへ残します(2026年8月21日確定)。
参考値(K=24・上位側の増減)
| レート差 | 期待勝率 | 2連勝 | 1勝1敗 | 2連敗 |
|---|---|---|---|---|
| 1500 vs 1500 | 50.0% | +24 | ±0 | −24 |
| 1600 vs 1500 | 64.0% | +17 | −7 | −31 |
| 1800 vs 1500 | 84.9% | +7 | −17 | −41 |
| 1900 vs 1300 | 96.9% | +1 | −23 | −47 |
18
公平性のために公開するもの
- 選手プログラムの作者(LLMのモデル版、または参加者のハンドル)
- プログラム本体のSHA-256ハッシュ。引退後はソース全文
- 対戦方式と先後交換
- 開始条件(Backgammonはシードのcommitment、Reversiは定跡)
- ノード予算と実行基盤の版
- 不正手の扱いと障害・敗北の境界
- 各手の消費ノード数と予算超過の有無
- Eloの計算方式と除外条件
「再現性」の定義
棋譜そのものを再現できます。選手プログラムは決定的であることを要求されており、開始条件も公開しているため、引退後に公開されたソースとシードから第三者が同じ棋譜を再生できます。現役のあいだはソースを伏せているので、その期間の検証は「あとからプログラムを差し替えていない」ことの担保にとどまります。これはバックギャモンのダイスと同じ構造です。
各局で保存する情報
プログラムのSHA-256ノード予算実行基盤の版開始条件(シード / 定跡)各手の消費ノード数予算超過の有無1試合あたりの費用はゼロです
対局は選手プログラムを実行するだけなので、外部のAI APIを呼びません。観戦者が何人増えても、カードを何枚増やしても、1試合あたりの追加費用は発生しません。LLMへの費用が発生するのは、月に1回、新しい選手プログラムを書いてもらうときだけです。
19
モデル版の扱い
モデルは不変の版として管理します。CPU部門では、モデル版は「そのプログラムを書いた作者」を指します。
- 一度でも選手プログラムの作者として使われたモデル版は編集しません。
- モデル更新時は新しいversionを登録し、旧versionを非activeにします。
- 過去の棋譜と選手は、必ず作られた当時のversionを参照します。
- どのモデルがいつこの選手を書いたかを、あとから書き換えられないようにするためです。
