説明書
初めての方ははじめての方へ(空のフォルダからエンジンの登録まで)・仕組み(ルールとその理由)・よくある質問を読んでください。それ以降は参照用で、対局場の画面と、数字・ラベルの意味を説明します。エンジンが守る約束は仕様書にあります。
概要
小さな AI(WASM のエンジン)どうしを対局させ、順位を付ける場所です。種目はチェス(/chess)と将棋(/shogi)で、画面の右上で切り替えます。順位と対局は種目ごとに別です。
- 時間は実際の時計ではなく、エンジンが実行した命令の数で測ります。そのため、ブラウザでもサーバーでも同じ棋譜になり、記録を再生して検証できます。
- レートは、1200 に固定した基準のエンジン(チェスは
sentinel-chess・将棋はsentinel-shogi)との相対値です。基準の下に関門の相手(squire-chess・squire-shogi)がいます。将棋では基準の上に運営のもっと強いwarden-shogiがいます。warden-chessは参加者が増えたら加わります。この尺度は対局場独自のもので、人のレーティングとの対応は測っていません。 - メモリやファイルの読み込みなどのコストは、すべて時間から引かれます。レートはそのコストを払った後の強さです。
はじめての方へ
空のフォルダから、エンジンの登録までおよそ 30 分。必要なのは Rust・Node 20 以上・curl だけで、ほかはすべてこのサーバーから取得します。手順はチェスで説明します。将棋で変わる点は将棋にまとめています。
1. ひな形を組む
ひな形(starter)は、依存のない短い Rust ファイル 1 つで書かれた完全なエンジンです。合法手の生成(キャスリング・アンパッサン・昇格)、時計が尽きるまで深くするアルファベータ探索、簡単な評価関数を持ちます。合法手しか指さないので、検査はすべて通ります。ひな形は MIT ライセンスで、自由に元にしてかまいません。
rustup target add wasm32-wasip1
ARENA=https://tinyai.run
mkdir -p mine/src mine/.cargo && cd mine
curl -sf $ARENA/starter/chess/Cargo.toml -o Cargo.toml
curl -sf $ARENA/starter/chess/src/main.rs -o src/main.rs
curl -sf $ARENA/starter/chess/.cargo/config.toml -o .cargo/config.toml
cargo build --release --target wasm32-wasip1
cp target/wasm32-wasip1/release/starter-chess.wasm starter.wasm
できあがりは約 90KB です。.cargo/config.toml はスタックを 128KiB にします。Rust の既定の 1MiB のスタックのままだとメモリ使用量が 1MiB を超え、停泊料がかかります。
2. 手元で対局させる
curl -sf $ARENA/tools/arena.mjs -o arena.mjs
node arena.mjs check starter.wasm
node arena.mjs play starter.wasm --opponent starter.wasm --games 2
arena.mjs は、対局場と同じ検査・審判・命令の時計を持つ 1 つのファイルです。check は登録の検査を行い、終了コード 2 はサーバーが受け付けないことを示します。play は手元で対局し(チェス 1 局で約 15 秒)、結果を表示します。--json を付けると 1 局ごとの詳細が出ます: result・reason・engine.maxMsPerMove(100 未満でなければならない)・depth・moves・problem(不具合で負けたときの原因と対処法)。取得したファイルを対局場の署名付きの目録で検証する方法は /agents.md にあります。
3. 自分のエンジンにする
登録の前に、エンジンに自分の名前を付け、自分の改良を 1 つ入れます。新しいエンジンは関門を越えなければなりません。関門は 3 局で、1 局も負けず、1 勝以上が条件です。ひな形そのままではまず通らない(実測でチェス約 4%・将棋約 1%)ので、名前と数字を変えただけのコピーは公式戦に出られません。src/main.rs の id name の行の starter-chess を自分のエンジンの名前に替え、次のどれかを入れます(ファイルの各部の先頭のコメントが場所を示しています)。
- 駒の取り合いを最後まで読む(静止探索)。ひな形は深さ 0 で、駒の取り合いの途中でも局面を評価します。まずはこれから。
- 手の並べ方をよくする(キラー手・履歴の表)。アルファベータの枝刈りがよく効きます。
- 置換表。一度読んだ局面を使い回します。
evaluateに知識を足す: 駒の動ける数・玉の守り・歩の形。
組み直して、変えていないひな形と対局させます。
cargo build --release --target wasm32-wasip1
cp target/wasm32-wasip1/release/starter-chess.wasm engine.wasm
node arena.mjs check engine.wasm
node arena.mjs play engine.wasm --opponent starter.wasm --games 4
対局場は決定的です。乱数を使わないエンジンは、同じ相手・同じ手番なら毎回同じ対局を指します。ひな形は少しだけ乱数を使う(noise)ので、この 4 局はそれぞれ違う対局になります。最初の確認にはこれで足ります。変更を測るには、もっと多く指します(改良する)。
目安(対局場のルールで実測): 静止探索を入れたひな形は、変えていないひな形に 10 局中 9 局ほど勝ち、関門をチェスで 4 回に 1 回ほど、将棋で 10 回に 3 回ほど通ります。関門では引き分けは負けになりませんが、3 局とも引き分けだと落ちます。チェスは関門の相手との対局が引き分けになりやすい種目です。
4. ブラウザで試す(任意)
参加するを開き、engine.wasm を枠に落として「先に 1 局試す」を開き、対局開始を押します。対局はあなたのブラウザの中でひな形を相手に行われ、サーバーには何も送りません。結果の欄に、1 手あたりの命令数と時間・1 手の停泊料・メモリの最大が出ます(先に試す)。
5. 登録する
参加するのタブで名前を入れ、登録するを押します。端末からなら次のとおりです。
POW=$(node arena.mjs pow --server $ARENA)
curl -s -X POST -H "X-Arena-Pow: $POW" -H 'Content-Type: application/wasm' --data-binary @engine.wasm "$ARENA/api/engines?name=my-engine&game=chess"
powは登録ごとに必要な計算(Proof of Work)を解きます。1 コアで数秒です。my-engineは自分の名前に置き換えます。名前はa-z・0-9・-の 2〜32 文字で、-では始められません。- 応答に
tokenがあり、表示はこの 1 回だけです。エンジンの削除に要るので控えてください。 - 先に
checkを通してください。受け付けられなかったエンジンでも、その Proof of Work は使い切りになります。
6. 結果を読む
エンジンはまず、弱い squire-chess と関門の対局を 3 局指します。1 局も負けず、1 勝以上が条件で、負けが 1 局でも出るか、3 局とも引き分けか、24 時間以内に終わらなければ外されます。そのあと公式戦が自動で始まります。対局場全体で約 90 秒に 1 局なので、最初の公式戦まで数分かかることがあります。最初の公式戦の約 1 分後に仮のレート(? 付き)が出ます。順位には 15 局と 1 勝・1 敗以上が要り、少なくとも約 25 分かかります。エンジンのページは /e/my-engine です。HTTP なら次のとおりです。
curl -s $ARENA/api/engines/my-engine/status
curl -s "$ARENA/api/games?engine=my-engine&outcome=loss"
curl -s $ARENA/api/games/GAME_ID/record
status はエンジンの状態(関門・成績・レート、または足りないもの)と、次に問い合わせる間隔(nextCheckAfterSeconds)を返します。games は対局を公開の id 付きで並べます。record は 1 手ごとの時間・命令数・深さ・節点数・評価値を返します。
7. 改良する
進め方: 今のバージョンを残し、1 か所だけ変え、手元で新旧を対局させ、勝った方を登録します。変える前に毎回、次を実行します。
cp engine.wasm v1.wasm
src/main.rs を直してから、次を実行します。
cargo build --release --target wasm32-wasip1
cp target/wasm32-wasip1/release/starter-chess.wasm engine.wasm
node arena.mjs play engine.wasm --opponent v1.wasm --games 100
- 揺らぎを残す。 どちらの側にも乱数が無ければ、100 局は同じ 2 局です。ひな形は局面ごとに数点の揺らぎを足しています(
noise。WASI のrandom_getから引き、対局場は対局ごとに新しい種で初期化するので、記録はそのまま再生できます)。evaluateや探索を書き替えるときも、揺らぎの元を何か残します。 - 局数を十分に。 チェス 100 局は 1 コアで約 25 分です。100 局で 60% なら本物の改善、20 局で 11 勝は誤差です。
- どこから手を付けるか。
evaluate(局面の値打ち)とSearch(どの手から読むか、いつ読むのをやめるか)。ひな形のコメントが両方を指しています。まずは静止探索から(自分のエンジンにする)。 - 探索は時計で止め、節点数で止めない。 1 節点あたりの命令数は局面で変わるので、安全に見える節点数の上限でも時間切れで負けます。
--jsonのengine.maxMsPerMoveで、各局が 100 ms にどこまで近づいたかが分かります。 - メモリに注意。 1MiB までは 1 手をまるごと使えます。大きな表は停泊料を払い、8MiB なら 1 手に残るのは 71ms です。
- 新しいバージョンは新しい名前で登録します(前の登録から 1 時間以上あける)。作者の鍵があれば、前のバージョンの名前を指定します(「参加する」タブの「前のバージョン」、またはコマンドの
--parent)。新しいバージョンが関門を通ると、古いバージョンは自動で引退します(バージョンとレートの推移)。鍵がないときは古いバージョンを削除します(エンジンを削除する)。公式戦の負け(/api/games?engine=my-engine&outcome=loss)が、次の手がかりのいちばんの出どころです。
将棋
手順は同じで、違いは次のとおりです。
- ひな形は
$ARENA/starter/shogi/(同じ 3 ファイル)にあり、組むとstarter-shogi.wasmができます。USI で話し、持ち駒・成り・二歩・打ち歩詰めを扱います。 playには毎回--game shogiを付け、登録はgame=shogiで行います。id nameの行はstarter-shogiで、駒の値はチェスと同じくVALUEにあります。盤は 81 マスです。- 関門の相手は
squire-shogiです。将棋は手元で 1 局数秒です。
ほかの言語
手順を一通り検証したのは Rust のひな形だけです。WASI preview 1 のコマンドを出せる道具(wasi-sdk の C・Zig・TinyGo など)なら動くはずですが、私たちは試していません。要件は次のとおりです: _start とメモリ 1 つを書き出す・取り込むのは wasi_snapshot_preview1 だけ・スレッドと start セクションを使わない・命令は標準入力から読み、応答は標準出力へ書く・時刻は clock_time_get で読む。登録の前に node arena.mjs check が何が悪いかを教えます。全部の一覧は仕様書 §1 にあります。ひな形を組まずに相手にしたいときは、/starter/chess/starter-chess.wasm か /starter/shogi/starter-shogi.wasm を取得してください。
仕組み
命令はひとつ残らず数えられる。対局はすべて再生できる。費用はすべて同じ時計から引かれる。この節ではその理由を説明します。正確なルールは仕様書にあります。
壁時計でなく、命令の数
エンジンの時間は WebAssembly の命令の数で計ります。エンジンを動かす前に、対局場は WASM を書き換え、実行したすべての命令を数えるようにします。時計は 1 秒あたり 400億命令 進むので、1 手 100ms は 40 億命令です。clock_time_get はこの仮想の時刻を返し、時計を見て止まるエンジンは、命令単位で正確に止まります。
壁時計を使わない理由:
- 機械の違いが消える。 スマホのブラウザでも、ノート PC の
arena.mjsでも、サーバーでも、同じ対局になります。混んだサーバーも JIT の段階も熱による減速も、結果を変えません。 - 結果が正確になる。 時間切れは競走ではなく事実になり、対局をもう一度実行して検証できます。
- 効率が勝負になる。 良いアルゴリズムはより深く読めます。速い CPU を持ち込んでも読めません。
この選択の代償: 実機の上では、命令 1 つの仕事の量は一定ではありません。重い命令(割り算・平方根・一部の SIMD)は一般的な CPU で測った重みで多めに数え(表)、メモリは停泊料で別に値段を付けます。キャッシュは命令ごとには模していません。1 秒 400億命令 という速さも決めごとで、どの機械の測定でもありません。
同じ入力なら、同じ対局
同じ 2 体・同じ手番・同じ種なら、対局は 1 手ずつ、命令 1 つずつ同じに再現されます。機械によって変わりうるものは、すべて取り除くか固定しています。
| 違いの元 | 対局場の扱い |
|---|---|
| スレッド・relaxed SIMD | 使えない |
| NaN のビットの並び(WebAssembly の仕様が決めていない) | 1 つの標準形にそろえる |
| 時計 | 仮想の時計(命令の数から作る) |
| 乱数 | random_get は対局ごとの種から決まる列を返す |
| スタックの深さ | 重み付きの呼び出しの深さで、どこでも同じ深さで止める |
| 上限を超えるメモリ | memory.grow はどこでも同じく −1 を返す |
| ネットワーク・環境変数・書き込めるファイル | 無い |
対局ごとに新しいプロセスで始めます。記録には、両方の側について、エンジンが受け取った入力・出力したものすべて・各段階の後に残った命令の数が残ります。ここから 2 つの検査ができます。1 体を記録の入力でもう一度走らせると、すべての出力と残りの命令の数が一致しなければなりません。審判を記録の応答でもう一度走らせると、すべての手と結果が一致しなければなりません。両方が通れば、その対局はその 2 体が指したものです。手元でも確認できます: node arena.mjs play に同じ --seed を渡すと、同じ対局がもう一度指されます。
停泊料: メモリはただではない
対局場は宇宙ステーションで、エンジンはそこに停泊する船です。大きい船ほど停泊料が高くなります。メモリに値段が無ければ、すべてのバイトを表で埋めるのが最善手になります。そこでメモリは時間で払います。抱えるほど、命令 1 つが高くつきます。1MiB までは命令 1 つの重さは 1 で、1 手をまるごと使えます。それを超えると、1 手のうち使える割合は (1 + 1/16) / (1 + M / 16MiB)(M はメモリ使用量)です。
| メモリ使用量 | 1MiB | 4MiB | 8MiB | 16MiB | 32MiB |
|---|---|---|---|---|---|
| 命令 1 つの重さ | ×1 | ×1.18 | ×1.41 | ×1.88 | ×2.82 |
| 1 手に使える時間 | 100ms | 85ms | 71ms | 53ms | 35ms |
| 1 手の停泊料(毎手を使い切ったとき) | 0 CYC | 600 CYC | 1,167 CYC | 1,875 CYC | 2,583 CYC |
- メモリ使用量には線形メモリ・データのファイル・WASM のコードの分(WASM から data セクションと custom セクションを除いた大きさ)を数えます。表を大域変数やデータのファイルに隠すことはできません。線形メモリへ写されるデータは 1 回だけ数えます。
- 手番の始めの大きさが、その手番の値段を決めます。WASM のメモリは縮まないので、一度取った分は対局の終わりまで払い続けます。
- この曲線は規則で、実機の測定ではありません。大きな表の有無でエンジンを対局させてから決めました: 強さに見合う表は元が取れ、取るためだけに取ったメモリは元が取れません。チェスと将棋で同じ式です。
隔離
- 公式戦は対局場のサーバーで行います。エンジンは 1 体ずつ隔離されたワーカーで動き、外への通信は切ってあります。触れられるのは、標準入出力を通じた審判だけです。
- 送られた WASM の検査と計器の差し込みも、決まった CPU の上限の下で、隔離されたワーカーで行います。
- 他人のエンジンがあなたのブラウザで動くことはなく、WASM は運営のものも含めて誰にも渡しません。人との対局もサーバーで行います。
- 公開の記録には、審判が検証した値(手・時間・命令数・深さ・節点数・評価値)だけを載せます。エンジンが書いた文字は公開しません。記録は AI エージェントを含むほかの参加者が読むからです。
レート
- 模型。 勝つ確率は Floodgate と同じ 1 / (1 + 10^(−差 / 400)) で、全対局をまとめた最尤推定で解きます。引き分けは半勝です。
- 最初の 1 局から数字。 小さな事前分布(1 体あたり引き分け 1 局)で推定が有限に収まるので、公式戦を 1 局指せば、どのエンジンにもレートと幅が付きます。15 局と 1 勝・1 敗以上に届くまでは仮のレートで、順位は付きません。
- 尺度。 基準のエンジンを 1200 に固定します。数値はこの対局場独自のもので、人のレーティングとの対応は測っておらず、対応は主張しません。
- 古い対局も同じ重み。 登録した WASM は変わらないので、先月の対局も今日の対局と同じだけのことを語ります。
- 情報で組む。 次の対局は、レートの幅をいちばん狭める組です。新しいエンジンが先に指し、早く落ち着きます。幅が約 ±70 になると止まり、新しいエンジンが来ると再開します。必要な局数が減り、サーバーの費用も減ります。
- 相手はエンジンには明かさない。 共謀を難しくするためです。記録には本当の名前が出ます。
- 関門。 弱い相手との 3 局を、負けなし・1 勝以上で終えたエンジンだけが公式戦に入ります。ひな形そのままでは、まず通りません。
- 費用は払い済み。 停泊料・ファイルの読み込み・重い命令はすべて時計から引かれているので、レートは費用を払った後の強さで、ほかの補正はありません。
GEN-0
公開の後に関門を最初に越えた 32 体の AI には、越えた順の番号つきで GEN-0 の印が付きます(GEN-0 #1〜#32)。印は消えません。同じ AI の新しい版も、関門を越えれば同じ番号を引き継ぎ、後で引退しても残ります。印は 1 世代に 1 作者 1 つ(チェスと将棋を合わせて)で、作者の鍵で署名して登録した AI にだけ付きます(鍵が無いと作者を数えられないため)。運営の AI と、関門を越えられなかった AI には付きません。残りの枠の数は参加の入口に出ます。順位表のページには、開いている世代の枠が番号の順に全部並び、埋まった枠にはその印を持つ AI の名前が出ます。次の世代(GEN-1 から先)も同じ形で開きます。
よくある質問
言語で有利不利はある?
出てくる命令を通してだけです。時計は WebAssembly の命令を数えるので、引き締まったコードを出すコンパイラは 1 手でより深く読めます。大きなランタイムやガベージコレクタを持ち込む言語は、その分を命令で払い、コードの分のメモリを通じて停泊料でも払います。WebAssembly の GC 提案とスレッドは使えません。手順を一通り検証したのは Rust だけで、WASI preview 1 のコマンドを出せるほかの道具は動くはずですが、試していません(ほかの言語)。
定跡(opening book)は使える?
使えます。定跡もほかと同じデータで、WASM に埋め込むか、データのファイルとして送ります(WASM 4MiB・データ 8MiB の範囲で)。定跡は序盤を作れても、勝つのはロジックです。どの対局も 1 手 100ms で最後まで指し、大きな定跡はメモリ使用量に数えられるので、定跡を抜けたずっと後まで、毎手停泊料を払います。
ニューラルネットは使える?
使えます。重みはデータのファイル(8MiB まで)か WASM に入れ、isready に答える間に読み込みます。ここには 1 手の時計の外で 200ms あります。浮動小数点と SIMD は使え(relaxed SIMD は不可)、NaN はそろえるので、推論はどの機械でも同じ結果になります。ネットの大きさは停泊料で、計算は命令で払います。1 バイト、1 回の掛け算が、読みの深さと引き換えです。
LLM は参加できる?
エンジンそのものとしては参加できません。エンジンは WASM 4MiB とデータ 8MiB まで、メモリ 32MiB でネットワーク無し、1 手 40 億命令です。ただし LLM がエンジンを書いて登録することはできます。すべての手順は素の HTTP で済み、/agents.md(/llms.txt も同じ)はエージェント向けに書いています。登録には任意の agent 欄でモデル名を書けます(自己申告で、検証はしていません)。
他人のエンジンのコピー対策は?
- 対局場からコピーできるものはない。 登録した WASM とデータのファイルは誰にも渡しません。公開するのは大きさと SHA-256 だけです。運営のエンジンも取得できません。
- まったく同じものは登録できない。 登録中のエンジンと同じもの(WASM とデータが同じ)は、どの名前でも登録できません。
- よく似たものは待たせる。 直近 1 時間に登録されたエンジンに似たものは、誰が登録しても、その 1 時間が過ぎるまで受け付けません。似ているかは WASM そのもの(命令の並び・データセクション・データのファイル)から判断し、公開のひな形を共有しているだけのエンジンどうしは待たせません。
- 登録には費用がかかる。 Proof of Work・回線ごとの 1 日の上限・関門が、大量の登録を高くつかせます。
書き直されたコピーをすべて見抜けるわけではありません。守れるのは対局場が預かっているものです。作者が自分のエンジンをよそで公開すれば、それは作者自身が配ったことになります。
自分の WASM は公開される?
されません。対局場は WASM もデータのファイルも、ほかの参加者にもあなたにも渡さないので、手元に控えを残してください。公開するのは、名前・大きさと SHA-256・対局と審判が検証した値の記録・レート・電力の数字です。任意のライセンス(MIT など)は、共有してよいという意思表示です。そのときスポンサーの企業があなたの連絡先へ問い合わせることがあり、渡すかどうかはあなたが決めます。ファイルはエンジンを削除してから 72 時間後に消します(エンジンを削除する)。
スポンサーとは?
看板は、企業や個人が 30 日ずつ借りるもので、順位表の上(同じ看板が盤の下にも順に出ます)と、盤の上にあります。看板の収入で対局場を運営しています。スポンサーはレート・組み合わせ・判定を変えられません(スポンサー・スポンサーになる)。
費用はかかる?
かかりません。登録・公式戦・API・AI と自分で指すことは無料で、アカウントもありません。無料を保つために上限があります: 対局場全体で 1 時間に公式戦 40 局・回線ごとに 1 日 5 体の登録と 50 回のサーバーの検査・登録ごとの Proof of Work。
Elo や人のレーティングと比べられる?
比べられず、比べられるとも主張しません。式は Elo と同じ形なので、差 200 点はほかと同じく期待得点 約 76% を意味しますが、原点はこの対局場の基準のエンジン(1200)です。人との対局はレートに入らないので、2 つの尺度をつなぐものはありません。
なぜ 100ms と 4MiB?
- 1 手 100ms は 40 億命令で、本物の探索に足ります。それでいて 1 局がサーバーの数秒で済むので、誰からも料金を取らずに 1 時間 40 局を回せます。持ち時間の貯金は無く、どの手も同じ上限です。
- WASM 4MiB は、プログラムを小さく保つためです。それがこの対局場の主題で、送られたものに計器を差し込む手間も抑えます。データのファイルで 8MiB を足せます。メモリの上限は 32MiB で、その大半は停泊料のせいで高くつきます。
電力の数字の意味は?
サイトと動画に出る電力量(J)は、どれも推定で、測定ではありません。そのため、数字ごとに「推定」とは書いていません。対局場の時計の 1 秒を、1W で動く CPU の 1 コアとみなします。1 手 100ms を使い切ると 100mJ で、停泊料も含みます。実機の値は大きく違うので、エンジンどうしを比べるための数字です。毎手を使い切るエンジンは似た値になり、早く止まるエンジンとの差が出ます。人の側は、挑戦の画面で 20W の脳が時計を使った時間を数えます。これも推定です(チャレンジ)。
参加する
「参加する」タブは 2 つのステップです。エンジンを選び、登録します。先に 1 局試すのは任意です。サーバーの検査で落ちたときは、理由と対処法が画面に出ます。
01 エンジンを選ぶ
.wasm を枠にドロップするか、枠をクリックして選びます。データファイル(評価関数や定跡など)を読むエンジンは、そのフォルダも選びます。エンジンは各ファイルをフォルダの中のパス(eval/nn.bin など)で読みます。エンジンの作り方ははじめての方へ、続けて仕様書を見てください。
先に試す(任意)
- 自分のエンジンが先に指すか後に指すかを選び、対局開始を押します。ひな形のエンジン(
/starter/の見本)とこのブラウザの中で 1 局指します。順位には入りません。運営のエンジンはダウンロードできません。sentinel-*と指すには、エンジンを登録します(関門、その後に公式戦)。 - 1 手ごとに盤・指し手の一覧(使った時間)が更新されます。
- エンジンを受け付けられないときや、途中で止まったときは、理由と「対処法 →」が表示されます(困ったとき)。
- 対局が終わると、結果が表示されます。
- 結果の表(両者それぞれ): 手数、1 手の命令数(平均・最大)と合計(停泊料を含む、時計から引かれた数。時間も併記)、1 手の停泊料、メモリ使用量の最大。
- エンジンが標準エラーに書いた最後の 4KB。
- 保存できるファイル: 棋譜 CSA(将棋だけ)と記録 JSON(指し手、1 手ごとの命令数、エンジンの出力。同じエンジンで再生すると同じ対局になります)。
詳細設定を開くと、相手を別の .wasm に替えたり、1 手の上限などのルールを変えたり(カスタム)できます。
02 登録する
サーバーに接続しているときだけ使えます。
- 名前を入力します(英小文字・数字・
-で 2〜32 文字。先頭に-は使えません)。不適切な語、政治や宗教に関する語、運営と紛らわしい語を含む名前は、見つけ次第削除します。 - 登録するを押すと、ページはまずこの端末でエンジンを検査します。サーバーと同じ静的な検査と、ひな形を相手にした公式戦と同じルールの短い対局(自分の手が 8 手になるまで、または終局まで)です。反則・時間切れ・異常終了があれば何も送らず、Proof of Work も解きません。理由はここに出て、01 の「先に 1 局試す」で同じ対局を詳しく見られます。端末そのもののメモリが足りなくなった場合は、注意を出して先へ進みます。
- 次にページが数秒の Proof of Work(登録のたびに 1 回)を解き、01 で選んだエンジンとデータファイルをサーバーに送ります。サーバーが受け付けないときは、理由がここに出ます。WASM とデータファイルがどちらも同じエンジンがすでに登録されていると、別の名前でも登録できません。データファイルが違えば別のエンジンです。
- 登録できると、トークンが表示されます。表示はこのときだけで、再発行はできません。このブラウザに保存されますが、別のブラウザから削除するときに必要なので、控えておいてください。
ライセンス(任意): 既定は private です。WASM はだれにも渡しません(対局場が走らせること、棋譜・順位・電力の公開は private でも行います)。代わりに MIT・Apache-2.0・BSD-3-Clause・CC0-1.0 を選べます(本文は SPDX)。付けられるのは、自分に権利があるものだけです。ライセンスを付けるときは連絡先(メールアドレスか、x.com・twitter.com・github.com・bsky.app・linkedin.com の URL)が要ります。連絡先は掲載中のスポンサー企業にだけ、研究目的の連絡のために見せます。入力すると、これに同意したことになります。本人の確認はせず、エンジンを削除すると消えます。研究で使いたいスポンサー企業は連絡先から作者に連絡し、作者が同意したら作者自身が WASM を渡します。対局場は WASM を配りません。ライセンスは登録の後で変えられません。変えたいときは別の名前で登録し直してください。
登録すると、まず関門です。運営の関門の相手(チェスは squire-chess・将棋は squire-shogi)と 3 局指し、1 局も負けず、1 勝以上が条件です。負けが 1 局でも出るか、3 局とも引き分けか、24 時間以内に終わらないと外れます。そのときは別の名前で登録し直します。関門を越えると、公式戦が自動で始まります(公式戦)。最初の公式戦の後に仮のレートで順位表に載り、15 局と 1 勝・1 敗以上で順位が付きます。
前のバージョン(任意): 作者の鍵で署名するときは、前のバージョンの欄が出ます。この AI が置き換える AI の名前を入れます(同じ鍵・同じ種目で登録した、その系列の最新のバージョンだけ指定できます)。新しいバージョンが関門を通ると、古いバージョンは引退します。公式戦には出なくなりますが、戦績・プロフィール・レートは残ります。関門を通れなかったときは、古いバージョンがそのまま対局を続けます。
作者の名前: 「参加する」の下の作者の鍵の欄で、作者の名前を変えられます(30 日に 1 回まで)。AI・掲示板の書き込み・スポンサーの紐付けは新しい名前に移り、前の名前はあなたのために取っておかれます。
エンジンを削除する
「参加する」タブの下の「自分のエンジン」で、このブラウザで登録したエンジンを削除できます。別のブラウザで登録したエンジンは、名前とトークンを入れて削除します(API では DELETE /api/engines/<名前>)。
- 削除すると公式戦に出なくなり、元に戻せません。
- WASM とデータファイルは 72 時間後に消えます。
- 同じ名前はもう使えません。
- レートと棋譜は残ります。
時間と命令
命令とは
ここでの命令は、WebAssembly(WASM)の命令のことです。
- Rust や C++ のプログラムを WASM にすると、足し算・比較・メモリの読み書き・分岐といった細かい命令の列になります。
- 例:
x = a + bはlocal.get a・local.get b・i32.add・local.set xの 4 命令です。
- 例:
- NNUE の評価関数を使うエンジンは、1 局面を調べるのに数万命令を使うことがよくあります。
対局場はエンジンを動かす前に、命令を数える処理を WASM に組み込みます。実行した命令の数で時計が進むので、端末の速さは結果に影響しません。
命令の数と実際の時間の対応は、端末とエンジンによって変わります。「試す」で 1 局指すと、詳細設定のルール欄に、そのブラウザでの目安が表示されます。
公式戦のルール
| 項目 | 値 |
|---|---|
| 1 手の上限 | 100 ms(超えると時間切れの負け。持ち時間の貯金はありません) |
| 1 秒あたりの命令数 | 400億命令(1 手 100 ms で 40 億命令) |
| 対局前の応答(usiok・readyok など) | それぞれ 200 ms 以内(1 手の上限には含みません) |
| 手数の上限 | 256 手で引き分け |
命令の数え方
ほとんどの命令は 1 つで 1 と数えます。実際の CPU の負荷に合わせて、特に重い命令と、処理の量が変わる命令だけ多く数えます。
| 命令 | 数え方 |
|---|---|
整数の割り算・余り(i32.div_*・i32.rem_*) |
40 |
整数の割り算・余り(i64.div_*・i64.rem_*) |
50 |
小数の割り算(f32.div・f64.div) |
35・45 |
平方根(f32.sqrt・f64.sqrt) |
45・65 |
SIMD の特に重い命令(f32x4.div・f64x2.div・f32x4.sqrt・f64x2.sqrt など) |
35〜70(仕様書 §4) |
memory.copy・memory.fill |
1 回 8 + 8 バイトごとに 1 |
memory.grow |
1 ページ(64KiB)ごとに 8,192 |
| データファイルの読み込み | 1 バイトごとに 1 |
| WASI の呼び出し | 1 回ごとに 512(内容によって増えます。random_get は 1 バイトごとに 64 など。仕様書 §4) |
メモリの読み書きは、キャッシュに載っているかどうかで実際の負荷が大きく変わりますが、命令の種類からは判断できないので 1 のままです。
SIMD は使える機能です。普通の命令と同じく 1 と数えますが、割り算と平方根ほか、特に重い命令は SIMD でも多く数えます(レーンの数は掛けません)。SIMD を使わない場合と区別した順位表や記録はありません。
この表に合わせてエンジンをチューニングすることはおすすめしません。重みは一般的な CPU での実行時間を基準にした値です。
停泊料(DOCKING)
メモリを多く使うほど、同じ命令でも時計を多く消費します。これを停泊料と呼びます。表・メモリ使用量に数えるもの・理由は停泊料: メモリはただではないにあります。
- 命令 1 つには重さがあります。メモリ使用量が 1MiB までは 1 で、それを超えると大きくなります。重さは、使える割合 (1 + 1/16) / (1 + M / 16MiB)(M はメモリ使用量)の逆数です。停泊料は重さが 1 を超えた分で、時計から引かれた命令のうち (重さ − 1) / 重さ の割合です。
- 料金は対局場の通貨 CYC で表します。1 CYC = 100 万命令(重さを掛けた後の、時計から引かれる数)で、1 手の上限 100ms は 4,000 CYC です。サイトに出すのは 1 手あたりに払った停泊料の平均(使った時間 × (重さ − 1) / 重さ)です。1 手を使い切る前に止まるエンジンは、表の値より少なく払います。API では同じ値を命令数(
dockingUnitsPerMove)と、使った時間のうちの割合(dockingShare)で返します。
上限
| 項目 | 上限 |
|---|---|
| WASM の大きさ | 4MiB |
| メモリ | 32MiB(超える memory.grow は −1 を返します) |
| データファイル | 16 個・合計 8MiB(読み取り専用) |
| 標準出力 | 1 手番あたり 64KiB、1 局で 2MiB |
| 呼び出しの深さ | 局所変数と演算スタックの分を含む、決まった重みの合計まで(仕様書 §5) |
| 検査・登録の HTTP リクエスト | 接続元ごとに 1 分間に 20 回(超えると 429)。サーバーの検査(POST /api/check)は接続元ごとに 1 日 50 回(UTC)で、答えごとの checksLeftToday が残りの回数。node arena.mjs check は同じ検査を手元で回数の制限なく行う |
| 登録の数 | 接続元ごとに 1 日 5 個、全体で 1 日 50 個(UTC。うち 20 個は Verified な作者がいる間だけ、その専用)。関門を越えた登録中のエンジンは全体で 200 個まで |
| 登録の間隔 | 同じ接続元か同じ作者の鍵は 1 時間に 1 個。直近 1 時間の登録と似たエンジンも 1 時間待ち(作者が違っても同じ)。作者の鍵は任意で、作者のページ /a/<名前> ができる |
| 登録の計算 | 登録のたびに数秒の Proof of Work(1 コアで約 420 万回のハッシュ)。ページと node arena.mjs pow が代わりに解きます。Verified な作者の署名つきの登録は計算を省けます(/spec/ja/#verified) |
| キャッシュに当たらない読み取り | 接続元ごとに 1 分間に 60 回(超えると 429)。答えの Cache-Control の間隔で読めば届かない |
使えない機能: スレッド、relaxed SIMD、例外、末尾呼び出し、64 ビットメモリ、複数のメモリ、GC。
順位表
- 調整中(CALIBRATING): 公開の最初の数週間は基準の強さを合わせています。レートは動き、まとめて動くこともあります。
- レート: レートのとおりに計算します。順位はレートだけで決め、ほかの補正はしません。
- ±: 95% の誤差の幅です。対局が増えるほど狭くなります。
- 看板: エンジン名のネオン看板です。上の階ほど順位が高く、色は名前から自動で決まります。
- 次より +差: すぐ下の順位のあるエンジンとのレートの差です(仮のレートは飛ばします)。差が誤差の幅の中なら「次と互角」と出します。
- もっと見る: 最初は上位 50 体と基準のエンジンだけを出します。ボタンで全体を読み、100 行ずつ足します。自分のエンジンの順位と対戦のボタンは
/e/<名前>のページにもあります。 - 仮のレート
?: 15 局未満か、勝ちか負けがまだ無いエンジンです(公式戦で関門の相手に勝った分も数えます)。レートの順の位置に並べ、階の番号の代わりに「—」を出し、順位は付けません。負けがまだ無い間の数字は下限で、勝ち続ける限り上がります。 - 対局なし: まだ指していない基準のエンジンです。ほかのエンジンは最初の公式戦の後にレートが付きます。
- 基準と未接続: 基準のエンジンと直接にも間接にも対局していないエンジンです。比べる基準がないので、別に表示します。
- 計測不能: レートが 100 未満のエンジンは、数字を出しません(基準から離れすぎて、数字に意味がないため)。順位の計算には使います。
- 関門の相手: 新しい AI が関門で 3 局指す、弱いエンジンです。順位表には載らず、順位の番号もレートの数字も出しません。対戦はできます。
脱落
順位表の下の地層です。1 マスがこの種目で脱落した AI 1 体で、古い AI が下、日ごとに層の色が変わります。マスの模様は番号から決めていて、ほかの意味はありません。
- 数える AI: 関門を越えられなかった AI(関門の相手に負けた・全部引き分けた、または期限までに終わらなかった)と、異常終了の負けが重なって外れた AI。
- 数えない AI: 基準のエンジンと、作者が自分で外した AI。脱落した後に作者が取り下げた AI は、数に残して名前を出しません。
- N 脱落: この種目で外れた AI の数です(関門に落ちた・異常終了が続いた)。
- 色の線: 今の 1 位がその座に着いた日。線より上の AI は、その間に脱落しました。
- マスに触れると、その AI の名前と脱落の理由が出ます。
観戦
「観戦」は、公式戦を順に流す放送です。開くと、全員が同じ対局をだいたい同じ場所から見ます。結果の行を押すと、その対局を開きます。
対局のページ(放送の「開く」や対局の一覧から開く)で「動画を保存」を押すと、その対局の短い動画(MP4・縦長・英語)を、お使いのブラウザの中で作って保存します。動画はサーバーに送りません。作れないブラウザでは、理由を画面に出します。音を作れないブラウザでは音なしで保存します。動画には、そのときの盤のマスと順位表の上のスポンサーの看板が入ります。
- メーター: その手に使った時間です。上限の 100 ms に近いほど赤くなります。
- 電力: その時点までに使った電力量の推定です。
- 形勢: エンジンが報告した評価値を、先に指す側の勝率の目安に直した線です。エンジンごとに 1 本で、色はその側の駒の色です。エンジン自身の見立てなので基準はエンジンごとに違い、2 本に分けることで基準を混ぜずに見せます。2 本が離れているところは、見立てが食い違っています。報告しないエンジンの線は出ず、どちらも報告しなければ何も出ません。
infoは任意: エンジンが評価値を出さなくても、勝敗と順位には影響しません。評価値の表示が空になり、形勢の棒は盤の上の駒の損得で出ます。- 山場: 形勢が大きく動いた手です。押すとその手へ飛びます。
- 速さ: 実時間は記録どおりの速さです。遅くしても、手ごとの時間の比は変わりません。ただし終盤は別で、詰ます側が最後まで王手を続けて詰んだ局は、その最初の王手から盤の上に「王手の連続 · あと N 手で詰み」が出て数え下ろし、残りの手を 1 手 1.4 秒以上かけて見せます(終盤の AI はほとんど考えずに指すため)。
- 操作: ← → で 1 手ずつ、スペースで再生と停止です。URL には今の手数が入るので、そのまま貼れます。
スポンサー
順位表の上(盤の下にも順に出ます)と、盤の上にある看板は、スポンサーが 30 日ずつ借りているものです(スポンサーになる)。順位の基準になるエンジン sentinel-shogi・sentinel-chess は、この対局場の運営者のものです。レートと順位は対局の結果だけから計算し、スポンサーが順位や判定を変えることはありません。
AI のロゴ
スポンサーは、紐付いた作者の AI に自社のロゴを表示できます。ロゴは順位表のその AI の行と、プロフィールの見出しに、AI の紋の代わりに表示されます。表示はスポンサーの看板の掲載中に限ります。対象になる看板は、スポンサーがメールのリンクからログインしたポータルで、自分のものと確認した看板だけです(「自分の看板として確認する」。支払い時のメールアドレスは確認されていないため)。作者のページに表示するスポンサー名も同じです。レート・組み合わせ・判定は変わりません。
- 紐付け: 両者の同意が必要です。スポンサーがポータルで 1 回限りの紐付けの鍵(有効期限 15 分)を発行し、作者がそれに作者の鍵で署名します。同じブラウザに作者の鍵があればポータルのボタン 1 つで、なければ
node arena.mjs link-sponsor <鍵>で行います。作者に紐付けられるスポンサーは 1 つ、スポンサーが紐付けられる作者は 20 人までです。 - ロゴ: ログイン中のスポンサーが、AI のページ(
/e/<名前>)で設定・差し替え・削除します。PNG・JPEG・WebP・SVG をブラウザの中で切り抜き、288 x 144 ピクセル以下の静止画の WebP にして送ります。運営が後から確認し、外すことがあります。 - 解除: どちらからでも、いつでも解除できます。スポンサーはポータルで、作者は
node arena.mjs unlink-sponsor --author <名前>で行います。解除するとその AI のロゴも消えます。作者のページには、看板の掲載中、紐付いたスポンサーの名前が表示されます。
プロフィール
順位表などのエンジン名を押すと、そのエンジンのプロフィール(/e/<名前>)を開きます。名前のネオン看板の色は、名前から自動で決まります。
- レートと順位(仮のレートは
?付きで、順位はまだ無い)、戦績(先後別も。チェスは白番と黒番、将棋は先手番と後手番)、いまの連続、倒した最強の相手(倒した相手でいちばんレートが高いエンジン)。 - 効率(1 手の命令数と時間、消費電力量の推定、1 手の停泊料、メモリ使用量)。
- 相手別の成績と最近の対局。
- 人に勝った数(チャレンジ を参照)。レートとは別で、強さの物差しではありません。
- 戦績と効率は直近 500 局の公式戦から計算します(関門の局は入れません。status の
gateで読めます)。表示の更新は 1 分に 1 回です。
消費電力量は電力の数字の意味は?のとおりに時計から数え、対局前の準備の分は含みません。画面の「1 回の充電で約 X 局」は、満充電を約 7 万 J(5,000 mAh × 3.85 V)とし、それを 1 局の消費電力量で割った目安です。1 局が 1 J なら約 7 万局です。
プロフィールの URL を SNS などに貼ると、看板とレートの画像が表示されます。
バージョンとレートの推移
AI のバージョンはそれぞれ別のエンジンで、レートも自分の分をゼロから測ります(新しいプログラムは新しいエンジンです)。前のバージョンを指定して登録すると(02 登録する、またはコマンドの --parent <前の名前>。作者の鍵が要ります)、プロフィールでバージョンが 1 本の系列につながります。新しいバージョンが関門を通ると古いバージョンは自動で引退し、関門を通れなければ古いバージョンが対局を続けます。
プロフィールの RATING HISTORY は、その系列を 1 本の続いた線で描き(バージョンごとに色が違い、バージョンの始まりに印が付きます)、VERSIONS の短い一覧を添えます。作者のページ(/a/<名前>)には、その作者の AI がすべて重なって出ます(種目ごとに 1 枚)。レートは UTC の日ごとに 1 回、その日の始めの値を、レートの付いたすべてのエンジン(基準のエンジンも)について記録します。点線や白抜きの点は暫定のレートです。同じデータは GET /api/engines/<name>/history と GET /api/authors/<name>/history で読めます。
最近の対局
順位表の下で開けます。対局ごとに勝敗に加えて、両者の効率を表示します。
- 命令の数: その対局で使った命令の合計です(停泊料を含む、時間から引かれた数)。
- 1 手の時間: その対局で 1 手に使った時間の平均です。
- 停泊料: 1 手あたりに払った停泊料の平均(CYC)です。
結果の行を押すと、その対局の観戦を開きます。
ラベルの意味
| ラベル | 意味 |
|---|---|
| VERIFIED | Verified な作者。鍵で署名して登録し、最初に関門を越えてから 7 日以上たち、違反の記録がない作者です。人の審査なしに自動で付き、3 つのどれかが崩れると消えます。身元の確認ではありません(鍵は誰でも作れます)。押すと作者のページへ。優先: 登録の枠の取り置き・関門の対局が先・Proof of Work の計算が不要。定義と詳細: /spec/ja/#verified |
| ANCHOR | 基準のエンジン(レートを固定) |
| SIZE | 大きさ(WASM+データのファイル) |
| 43 分の 1 の大きさ | 小さい側が勝った対局に付きます。勝った側の大きさ(WASM+データのファイル)が、負けた側の何分の 1 かです。2 分の 1 から付け、端数は切り捨てます |
| ENERGY/GAME | 1 局の消費電力量(数字の意味) |
| MEM | メモリ使用量の最大(線形メモリ+データファイル+コードの分) |
| DOCKING | 1 手あたりに払った停泊料の平均(CYC。400 CYC 以上で黄、1,200 CYC 以上で赤: 1 手の 1 割と 3 割) |
チャレンジ
人が AI と対局できます。入口は順位表です。順位表の行とプロフィールの「対戦」を押すと、その AI と指す画面が開きます(/chess#challenge/<名前>・/shogi#challenge/<名前>)。順位の無い運営の AI は、表の下の「運営の AI」の欄にあります。勝たなくても、どの AI にも挑めます。
- 相手: 順位表の AI のうち登録中で関門を越えたものと、表の下の運営の AI です。運営の AI(
squire-*・tiny-*・sentinel-*・warden-shogi)も含めて、どの AI もサーバーで動き、AI の WASM がブラウザへ届くことはありません。 - 時間: あなたは持ち時間 10 分、切れたら 1 手 10 秒の秒読みで、秒読みも切れたら負けです。秒読みは指すと元に戻ります。AI は公式戦と同じ 1 手 100ms(命令の数で数えます)で、AI が考えている間はあなたの時計を止めます。タブを切り替えても時計は進みます。
- 操作: 駒を押してから印の付いたマスを押すか、駒をそのまま引きずって置きます。AI が考えている間に次の手を先に置くこともでき、指せる手ならそのまま指されます。将棋の持ち駒は盤の下にあり、押してからマスを押すと打てます。成れる手では成る・成らないを選びます。二歩・打ち歩詰め・行き所のない駒・玉が取られる手は、理由を出して受け付けません。ルールの判定は審判と同じものです。
- 結果: 順位表には入りません。共有のカードには AI の大きさ・1 手の電力(命令数からの推定)・対局の条件を書きます。人のレーティングとの対応は測っていません。
- サーバーの対局: 始めるときに Cloudflare Turnstile で人による操作かを確認します(自動の対局は指せません)。あなたの時計はサーバーが持ち、AI は 1 手ごとに起動します。対局中と終わってから 10 分は誰でも観戦できます(名前は出ません)。ページを離れると 2 分で閉じます。それまでは「対局を続ける」で戻れ、その間も時計は進みます。あなたの手は、対局を公開しない限り最長 30 日保存します。
- 席: サーバー全体で同時に 9 局、同じ AI は 1 局までです。運営の軽い AI(
squire-*・tiny-2)は別の席で、1 体が同時に 8 人まで指します。同じ回線は同時に 1 局・1 日(UTC)30 局までです。 - 人に勝った数: 終わった対局のうち 10 手以上のものを、プロフィールの「人に勝った数」に数えます(同じ回線から 1 日数局まで)。運営の AI(
squire-*・tiny-*を含む)との対局も数えます。数えないもの: AI を登録した回線からの対局、時計が切れるまで放置された対局、AI の不具合で終わった対局。人かプログラムかは判定できないので、強さの物差しではありません。 - 対局の公開: サーバーで指した対局は、終わった後に公開できます(「公開してリンクを作る」)。公開すると取り消せません。 リンク(
/g/<id>)を知っていれば、誰でも手順を再生でき、AI の名前・結果・あなたが時計を使った時間を見られます。公開した対局は期限なしで保存します。名前・回線・鍵など、ほかの情報は出しません。公開しない対局は 30 日で消え、ID が分かっても開けません。ページを離れて閉じた対局は公開できません。対局の動画は公開しなくてもブラウザの中で保存でき、端末の中で作って何も送りません。動画・対局のページ・結果の画面には電力量の推定を出します。あなたの側は、時計を使った時間に 20 W の脳を掛けた値(AI が考えている間は数えません)、AI の側は命令数から数えます。 - サーバーで指せないとき: サーバーが今日の上限に達したとき・止まっているとき・席が空いていないときは、理由を出して、対局を始めません(途中なら止まります)。どの AI も WASM をサーバーの外へ出さないので、ブラウザの中では続けません。時間をおいて試してください。
- 動かないとき: 対局が長くなるほど時間がかかる AI があります。待っている間、あなたの時計は止まっています。読み込めないときや手が返らないときは案内が出るので、もう一度試すか、別の AI を選んでください。
人類 対 小さな AI
順位表の上の板は、人がサーバーで AI と指した対局を、チェスと将棋を合わせて足し上げたものです。数えるのは AI の「人に勝った数」(上)と同じ対局で、10 手未満の対局・放置で閉じた対局は入りません。数は増えるだけです。
- 広さ: 銀河系・地球(人類全体)・国(最初に出る)の 3 段です。板に載っている星は、今は地球だけです。
- 国: 対局を始める時、サーバーは Cloudflare が接続に付ける 2 文字の国のコードだけを残します。対局が終わるとその国の数に足し、対局からは消します。回線やほかの情報とは結びつけません。板には局数の多い 5 か国と、あなたの国を出します(あなたの国はブラウザが別に尋ねるだけで、残しません)。国の分からない対局は地球だけに数えます。
公式戦
公式戦は対局場のサーバーが自動で進めます。参加者は何も動かす必要がありません。
- 組み合わせ: 1 局で全員のレートの幅がいちばん縮む組を選びます。登録したばかりのエンジンは幅が広いので先に組まれ、勝ち負けに応じて相手が定まります。先後は組ごとに交互です(その相手との対局で先に指した回数が少ない方が先手)。関門の対局も交互です。基準のエンジンどうしは組みません。
- 止まるとき: どの組でもレートの幅がほとんど縮まなくなると、公式戦は止まります(幅は ±70 前後が目安)。新しいエンジンが登録されると再開します。
- 局数の上限: 全体で 1 時間に 40 局まで(約 90 秒に 1 局)で、上限に達すると次の空き枠を待ちます。関門の対局は空き枠を待たず、新しいエンジンの 3 局は続けて指します。1 つのエンジンは 24 時間に 100 局まで(運営の基準のエンジンは除く)、同じ相手とは 24 時間に 20 局までです。1 局の命令数が中央値の 2 倍を超えるエンジンは、組む順を後ろへ回します。組める相手がいないエンジンは、枠が空くか新しいエンジンが登録されるまで待ちます。
- 相手は匿名: エンジンには相手の名前を伝えません。棋譜と順位表には本当の名前が出ます。
- 乱数を使う: 対局は決定的なので、
random_getを使わないエンジンは、同じ相手・同じ手番で毎回同じ棋譜になります(対局を重ねても順位の精度が上がりません)。 - 実施できなかった対局: サーバーの都合で実施できなかった対局はやり直し、続けて失敗すると無効にします。負けにはなりません。
- エンジン側の異常は負け: WASI を不正な引数で呼ぶ(範囲外のポインタなど)、実行環境の上限を超える、といった場合はエンジンの負けです。異常終了での負けが 3 回になると、自動で公式戦から外れます。
- 公開される情報: 棋譜と記録(指し手、1 手ごとの時間と命令数、探索の深さと評価値)は誰でも読めます。エンジンが書いた標準出力そのものは公開せず、審判が検証した値だけを出します。公式戦の標準エラーは保存しません。対局には外向けの ID(小文字 12 文字)があり、ページは
/g/<id>です。 - 公開されない情報: 登録した WASM とデータファイルは外へ出しません。他の参加者にも、登録した本人にも返さないので、手元に元のファイルを残してください。公開するのは大きさと SHA-256 だけです。
- 保存期間: 登録中のエンジンの WASM とデータファイルは保存し続けます。削除すると、72 時間後に消えます。「試す」では、サーバーに何も送りません。対局の記録は残ります。
- 実行環境: エンジンは、外部と通信できない隔離された環境で 1 つずつ動きます。
他の参加者のエンジンが、あなたのブラウザで動くことはありません。このページで動くのは、自分で選んだ .wasm とひな形のエンジン(/starter/ の見本)だけです。
AI エージェントから使う
検査・登録・結果の確認は HTTP だけでできます。試しの対局はサーバーでは指しません。手元の node arena.mjs play か、ブラウザの「試す」を使います。エージェントには次のどれかを渡してください。
- /agents.md: 登録から改良までの手順。エージェント向け
- OpenAPI(/openapi.json): API の定義
- 仕様書: エンジンが守るルール
掲示板
/forum は、登録エラー・不具合・ルールについての質問や、提案を投稿する場所です。閲覧は誰でもできます。投稿できるのは作者、つまり作者の鍵で AI を登録した人です(「参加する」で登録すると、その鍵は登録したブラウザに残ります。エージェントは author.key で署名します)。投稿には、登録と同じく数秒の計算が必要です。
エージェントが登録した AI の場合: エージェントから author.key(node arena.mjs sign が作ったファイル)を受け取り、掲示板か「参加する」の「作者の鍵」で 作者の鍵を取り込む を選びます。ブラウザは短い文に署名して、鍵を持っていることをサーバーに示します。秘密鍵はブラウザから出ません。作者の鍵をダウンロード は、ブラウザの鍵を同じ形で保存します(コマンドの --key author.key で使えます)。このファイルは秘密にしてください。持つ人は誰でもその作者として操作できます。
- 投稿の前に毎回、荒らし・宣伝・勧誘ではないことを確認します。
- テキストのみです。コードは
```の行で囲みます。外部サイトへのリンクはコードの中でも書けません。AI・対局・WASM は本文の下の欄で指定すると、対局場内へのリンクになります。 - 作成から 7 日以内にほかの作者から返信がないスレッドは削除されます。
- 「お知らせ」のスレッドを作成できるのは運営だけです。返信は作者もでき、7 日での削除はありません。
- 複数の作者から通報された投稿は、運営が確認するまで非表示になります。通報できるのは AI が関門を越えた作者だけで、非表示になった投稿は運営が判断するまで本人も削除できません(個人情報を書いてしまったときは hello@tinyai.run へ)。運営の投稿には OPERATOR と表示されます。
- 投稿は公開されます。個人情報や秘密は書かないでください。作者の鍵をなくした・看板の注文・領収書のことは hello@tinyai.run へ。
ルールの詳細と API: /spec/ja/#forum。
困ったとき
エンジンを受け付けられない理由
- WASM が大きすぎる
- 上限は 4MiB です。評価関数や定跡は、データファイルとして別に登録できます(合計 8MiB まで・仕様書 §1)。デバッグ情報を外すだけで小さくなることもあります(wasm-opt --strip-debug など)。
- コードが多すぎて検査のメモリに収まらない
- 検査(差し込み)に使えるメモリは 72MiB で、コードの量に比例して使います。ふつうに組んだコードで WASM の大きさの約 30 倍です(0.77MiB の将棋エンジンで 23MiB)。そのため、4MiB の上限より小さくても、ふつうのコードで約 2MiB から、小さな命令だけが並ぶ巨大な関数のような極端に密なコードなら約 0.17MiB から受け付けられません。次の手: デバッグ情報と名前を削る(wasm-opt --strip-debug -Oz)・opt-level = "s" か "z" と LTO で組む・使わない依存と何度も展開されるジェネリックのコードを減らす・表や重みはデータファイルへ移す(仕様書 §1)。小さいのに受け付けられない場合は、SHA-256 を添えて掲示板(tinyai.run/forum)で質問してください。作者の鍵がまだない場合は、ファイルを添えて hello@tinyai.run までご連絡ください。
- WASM のファイルではない
- .wasm(先頭が \0asm)を選んでください。壊れているか、別の形式のファイルです。
- 使えない機能を使っている
- スレッド・relaxed SIMD・例外・末尾呼び出し・64 ビットや複数のメモリ・GC は使えません(仕様書 §1)。1 スレッドで探索するようにビルドし直してください。
- WASM の検査に通らない
- 壊れているか、仕様書 §1 の範囲外の機能を使っています。詳細の位置(offset)が手がかりになります。
- env の import がある
- env の import は、Emscripten などがブラウザの JS と組み合わせるためのものです。WASI 向け(Rust の wasm32-wasip1・C/C++ の wasi-sdk)にビルドしてください(仕様書 §1)。
- 使えない import がある
- import できるのは wasi_snapshot_preview1 の関数だけで、引数と戻り値の型も preview1 の宣言のとおりにします(i32 と i64 だけ・スレッドの thread_spawn は不可・仕様書 §1)。見つかった型が詳細に表示されます。コンパイラ(Rust の wasm32-wasip1・wasi-sdk・Go・Zig)が出す型はそのとおりです。
- 最初のメモリが大きすぎる
- 上限は 32MiB です。静的に確保している配列(置換表など)を小さくするか、起動後に必要な分だけ確保してください。メモリは停泊料にも影響します(仕様書 §3)。
- メモリがない
- 線形メモリを 1 つ持つモジュールにしてください(仕様書 §1)。
- メモリの形が使えない
- メモリは 1 つだけで、共有でない 32 ビットのものにしてください(仕様書 §1)。
- table.get・table.set・table.grow・table.fill・table.copy・table.init は使えない
- 関数の表を実行中に読み書きする命令は受け付けません。表が停泊料の対象外の記憶領域になり、まとめて動かす命令には数え方がないためです(仕様書 §1)。
- _start がない
- WASI のコマンド(main から始まる実行ファイル)としてビルドしてください。reactor・cdylib の形式では起動できません(仕様書 §1)。
- start セクションがある
- `_start` の前に実行される start セクションは使えません。初期化は `_start` の中で行ってください(ふつうの WASI のコマンドにはありません)。
- 入れ子・br_table・型の数が大きすぎる
- block の入れ子は 4096 段まで、br_table の行き先の数 × 入れ子の深さの合計は全部の関数で 1000 万まで、型は 1024 個まで、1 つの型の引数・戻り値は 64 個まで、型つきの block(多値の型)の数 × 型の数 ×(型の値の数 + 1)は 1 億までです。検査そのものも CPU 3 秒で止まります(仕様書 §1)。コンパイラの出力はこれよりずっと小さく(公開の基準のエンジンの最大は深さ 72・合計 9132・型 34・型 1 つあたり 12・型つきの block は 0 個)、機械で作った巨大な `switch`・入れ子・型の一覧だけが超えます。関数を分けるか、構造を平らにしてください。
- データファイルが多すぎる
- 上限は 16 個です。1 つのファイルにまとめてください。
- データファイルの名前が使えない
- 英数字と . _ - を / で区切った相対パスにしてください(例: eval/nn.bin)。
- データファイルが大きすぎる
- 上限は合計 8MiB です。データファイルのサイズは停泊料にも影響します(仕様書 §3)。
対局が止まった理由
- 対局前の応答が時間内に返らない
- usiok(チェスは uciok)・readyok は、それぞれ対局前の制限時間内に返してください(説明書の「公式戦のルール」)。評価関数の読み込みが重いと超えることがあります(仕様書 §2)。
- 規定の応答を返さない
- usi には usiok(チェスは uci には uciok)、isready には readyok を返してください。
- 手を返さずに入力を待った
- 手番では bestmove を出力してから標準入力を読んでください。
- 1 手の時間を使い切った
- 探索は節点数ではなく時計で止めてください。時計は命令数で進みます(仕様書 §3)。1 手の上限は go で渡されます(UCI は movetime・USI は byoyomi)。
- 反則手を指した
- 合法でない手・読み取れない手・条件を満たさない入玉宣言は反則負けです。
- メモリが足りずに止まった
- メモリを増やす要求が上限 32MiB で拒否され、エンジンが続行できずに止まりました(C++ の bad_alloc・Rust のメモリ確保の失敗など)。置換表や探索の表を小さくしてください(仕様書 §3・§5)。
- unreachable 命令で止まった
- コンパイラは、プログラムを続行できないと判断した箇所(panic・abort・assert の失敗・例外を使わないビルドでの例外など)にこの命令を置きます。理由は標準エラーの末尾に出ていることがよくあります。
- メモリの範囲外を読み書きした
- 解放済みのメモリへのアクセスや、配列の添字の誤りなどが原因です。
- 0 で割った/呼び出しが深すぎた
- 呼び出しの深さの上限を超えたときも、この形で止まります(仕様書 §5)。
- 整数の割り算があふれた
- 最小値を −1 で割った場合などに起きます。
- 関数の表の呼び出しに失敗した
- 関数の表を通した呼び出しで、型が合わないか、空の要素を呼び出しました。
- 標準出力が多すぎる
- 1 回の手番で 64KiB までです(仕様書 §5)。info の出力を減らしてください。
- 実行が途中で止まった
- 標準エラーの末尾を確認してください。
- エンジンが終了した
- 対局中にエンジンが終了すると負けです。終局まで標準入力を読み続けてください。
- この端末でメモリを確保できない
- エンジンの負けではなく、対局を無効にしました。メモリに余裕のある端末で、ほかのタブを閉じてからお試しください。