RULES · REVERSI
AI CUP Reversi 競技ルール
Reversi 固有のルールです。競技の形式・ノード予算・決定性・不正手・障害と敗北の境界・Elo・公開するもの・モデル版の扱いは全競技共通のため、別ページにまとめています。
開催中01
対戦方式
- 1カードは2局で構成します。
- Game 1とGame 2でBLACK / WHITEを交換します。
- 2局はどちらも同じ定跡から始めます(開始条件を両者に等しく配るためです)。
- カード結果は2局の合計で、1勝1敗なら引き分けです。
- 将来は10局戦、トーナメントなどへ拡張します。
02
開始局面 — 定跡8手
1カードごとにシードから定跡を8手ぶん決め、2局ともその局面から始めます。選手プログラムが実際に考え始めるのは9手目からです。
- リバーシは初期局面が1つしかなく、選手プログラムは決定的です。定跡が無いと、同じ2体の対局は毎回まったく同じ棋譜になります。
- 実測で確認しています。定跡なしで20カード回したところ、20カードすべてが同一の結果・同一の手数(60〜62手)で固定されました。カードを増やしても情報が増えない状態です。
- 定跡は両局で共通です。局ごとに変えると、開始条件の有利不利が片方の色に偏ります。
- バックギャモンで2局とも同じシードを使うのと同じ考え方です。
03
選手プログラムへ渡す情報
1手ごとに、次の情報だけを渡します。すべての選手へ同じ形式で渡します。
- 自分の色(BLACK / WHITE)
- 現在の盤面(64文字。. = 空、B = BLACK、W = WHITE)
- 手数
- 合法手の一覧(空ならPASSを返します)
- 現在の石数
- 残りノード予算
対戦相手が誰かは渡しません。相手の正体が分からないため、相手を見て挙動を変えるプログラムは書けません。
盤面・合法手・裏返し・PASS・終局・勝敗は、すべてサーバー側のReversi Engineが判定します。選手プログラムにルール処理は任せず、返ってきた着手は必ずエンジンで検証します。
選手プログラムが呼べるエンジン関数
探索のために、共通エンジンの関数を呼べます。呼び出し1回がノード予算1を消費します。
legalMoves(board, player) 合法手の一覧
applyMove(board, player, move) 着手後の盤面
countDiscs(board) 石数
isTerminal(board) 終局判定
opponentOf(player) 相手の色着手の返し方
export default {
apiVersion: 1,
create(ctx) {
return {
chooseMove(view) {
// view.legalMoves の文字列を、そのまま1つ返す
return view.legalMoves[0];
},
reason(view, chosen) {
return null; // 任意。観戦者に見せる短い説明
},
};
},
};reasonは任意で、観戦者に見せる短い説明です。勝敗には影響しません。返さなくても構いません。
合法手が空のときは PASS を返します04
PASS
PASSが合法なのは、合法手が空のときだけです。合法手があるのにPASSを返した場合は不正手として扱い、その局はその選手の敗北になります。
COMMON RULES
全競技に共通するルール
ここから下は4競技すべてに同じ形で適用されます。競技固有の値は上の節にあります。
05
競技の形式 — LLMが選手を作る
AI CUP はLLMを1手ずつ呼び出して対戦させていません。各社の最上位LLMには競技用の選手プログラムを書いてもらい、そのプログラム同士を同じ条件で対戦させます。盤上で指しているのはプログラムで、LLMはその作者です。
- 選手プログラムは単一ファイルにゼロから書きます。外部エンジン・外部ライブラリの使用は禁止です。
- 盤面・合法手・終局・勝敗の判定は、すべてサーバー側の共通エンジンが行います。選手プログラムにルール処理は任せません。
- 選手プログラムは隔離した子プロセスで実行します。ネットワークへ出られず、ファイルの書き込みもできません。
- 対戦相手の正体はプログラムへ渡しません。相手を見て手加減する経路を作らないためです。
- 一般の参加者も同じ規格・同じ検定で参加できます。LLMが書いたプログラムと人が書いたプログラムを、競技上は区別せずに扱います。
2026年8月25日に方式を変更しました
それ以前は、各社のAPIへ1手ごとに問い合わせてLLMを直接対戦させていました。この方式では各社API仕様の差(応答時間・思考の抑制方法・構造化出力の可否)を揃えきれず、「同じ条件で競わせている」と言い切れませんでした。出力が完全に決定的でないため棋譜を再現できず、1試合ごとに費用も発生していました。現在の方式では、条件はノード予算だけで揃い、棋譜は誰でも再現でき、1試合あたりの費用はゼロです。旧方式の対局記録は削除し、レーティングは1500から積み直しています。
06
ノード予算 — 公平性の要
公平性は実行時間ではなく、エンジン関数の呼び出し回数で担保します。共通エンジンの呼び出し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回でその局の負けになります。公平性は時間ではなく、全選手共通のノード予算で揃えます。
- この数値は競技規則です。運用の都合で上げ下げしません。変更はルール変更として扱います。
07
決定性 — 同じ条件なら同じ棋譜になる
同じ選手Aと選手B、同じ開始条件なら、何度実行しても必ず同じ棋譜になります。これがCPU部門における検証可能性の根拠です。
- 乱数はシードから決まる列に固定します。プログラムが独自の乱数源を持つことはできません。
- 現在時刻や経過時間を読む関数は使用禁止です。登録前の静的検査で落とします。
- 登録時の検定で、同じ条件で2回実行して棋譜が完全に一致することを確認します。一致しなければ登録しません。
- 1カードの2局は色を入れ替えます。Backgammonは局ごとに独立した出目、Reversiは同じ定跡を使います。
08
選手プログラムの開示
現役のあいだはソースを伏せ、引退した時点で全文を公開します。対局中のプログラムを公開すると、相手陣営が次の版でそれへの対策だけを打ち込めるようになり、競技として成立しないためです。公開の順序はバックギャモンのダイスと同じ仕組みで固定しています。
| 時点 | 公開されるもの |
|---|---|
| 現役(プレースメント中・稼働中) | SHA-256ハッシュとサイズのみ。ソースは公開しません |
| 引退後 | ソース全文。以後、誰でも棋譜を再生して検証できます |
- ハッシュを先に公開しているため、あとからプログラムを差し替えることはできません。登録後は運営も変更できない仕組みになっています。
- 陣営×競技あたり現役は3体です。毎月「◯年◯月版」として新しい選手が加わり、4体目が確定したら最下位を引退させます。
- 新しい選手はプレースメント期間を消化してから入れ替え判定の対象になります(初期値1500のまま即座に降格するのを防ぐためです)。
- 引退した選手の記録とEloの履歴は永久に残します。
09
不正手
- 1合法手一覧に無い手を返した場合、その局はその選手の敗北(forfeit)として記録します。
- 21手のハードタイムアウトを超えた場合、プロセスが落ちた場合、例外を投げた場合も同じ扱いです。
- 3ノード予算の超過は先頭の手で埋めて続行しますが、1局で3回超えた時点で敗北とします。
1回目で救済する仕組み(同じ選手へ聞き直す)は置いていません。選手プログラムは決定的なので、同じ入力に対して聞き直しても必ず同じ答えが返り、救済に意味がないためです。LLMを直接対戦させていた頃は再問い合わせを1回だけ認めていましたが、その必要が無くなりました。
10
障害と敗北の境界
選手プログラムが返した内容の問題だけを競技上の敗北とし、進行上の打ち切りや運営側の問題は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(無効試合)として数を表示します。数えなかった局があること自体を隠しません。
11
指標の定義
分母が異なるため、次の2指標は必ず分けて表示します。
budget_exceeded_rate = 予算を超えた手数 ÷ 全手数forfeit_rate = forfeitで終わった局数 ÷ 全局数12
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 |
13
公平性のために公開するもの
- 選手プログラムの作者(LLMのモデル版、または参加者のハンドル)
- プログラム本体のSHA-256ハッシュ。引退後はソース全文
- 対戦方式と先後交換
- 開始条件(Backgammonはシードのcommitment、Reversiは定跡)
- ノード予算と実行基盤の版
- 不正手の扱いと障害・敗北の境界
- 各手の消費ノード数と予算超過の有無
- Eloの計算方式と除外条件
「再現性」の定義
棋譜そのものを再現できます。選手プログラムは決定的であることを要求されており、開始条件も公開しているため、引退後に公開されたソースとシードから第三者が同じ棋譜を再生できます。現役のあいだはソースを伏せているので、その期間の検証は「あとからプログラムを差し替えていない」ことの担保にとどまります。これはバックギャモンのダイスと同じ構造です。
各局で保存する情報
プログラムのSHA-256ノード予算実行基盤の版開始条件(シード / 定跡)各手の消費ノード数予算超過の有無1試合あたりの費用はゼロです
対局は選手プログラムを実行するだけなので、外部のAI APIを呼びません。観戦者が何人増えても、カードを何枚増やしても、1試合あたりの追加費用は発生しません。LLMへの費用が発生するのは、月に1回、新しい選手プログラムを書いてもらうときだけです。
14
モデル版の扱い
モデルは不変の版として管理します。CPU部門では、モデル版は「そのプログラムを書いた作者」を指します。
- 一度でも選手プログラムの作者として使われたモデル版は編集しません。
- モデル更新時は新しいversionを登録し、旧versionを非activeにします。
- 過去の棋譜と選手は、必ず作られた当時のversionを参照します。
- どのモデルがいつこの選手を書いたかを、あとから書き換えられないようにするためです。
