Nash Equilibrium Skill
SkillDev toolsNash equilibrium solver. Provides optimal mixed strategies for zero-sum matchups (Pokémon team selection, build matchups, rock-paper-scissors-style metas), selection optimization (pkdx select), and meta divergence analysis (pkdx meta-divergence). Use when asked questions like "optimal selection", "s
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Nash Equilibrium Skill skill
What this skill tells your AI
The instructions your AI receives, as published by pkdxtools/pkdx in .claude/skills/nash/SKILL.md and read by ahel’s review.
零和 2 人ゲームの混合戦略ナッシュ均衡ソルバーと、その上に構築された選出最適化・メタ乖離分析。
パス定義
SKILL_DIR=(このSKILL.mdが置かれたディレクトリ)
REPO_ROOT=$SKILL_DIR/../../../..
PKDX=$REPO_ROOT/bin/pkdx
VIZ=$REPO_ROOT/scripts/select_grid_viz.sh # pkdx select の進捗可視化
$VIZ は pkdx select --progress=json の stderr (JSON Lines) を受け取り、stdout が TTY なら 60×60 グリッドを live 描画、TTY 以外では phase 境界 + dp ノードサマリの数行ログに自動切替する。pkdx select を呼ぶときは原則として 2> >($VIZ) を付ける。Phase 2b では実行主体 (エージェント / ユーザー手動) を AskUserQuestion で選ばせる。
用語
| 用語 | 意味 |
|---|---|
| value | 行プレイヤーから見たゲーム値 (期待利得) |
| exploitability | 現在の戦略 σ に対する最良応答で得られる追加利得。零和で 0 なら σ は Nash 均衡 |
| support | 確率 > 0 の純戦略 index 集合 |
| TeamPayoffModel | 利得の作り方 (switching_game / screened_switching_game:<trials>:<seed>:<keep_top>)。turn_limit 既定は MC=5 / DP=5 (switching_game:<N> で個別上書き可) |
| BattleFormat | single = lead-aware 3 体選出 (60x60、6 × C(5,2) = 60 通りで先頭 (lead) を含む順序付きタプル) のみ対応 (double は現状未サポート) |
詳細はまず references/ を参照:
references/theory.md— 零和 LP / Simplex / Fictitious play / MWU の数式と根拠references/exploitability.md— exploitability / NashConv / KL / L1 の定義と使い分けreferences/payoff_semantics.md— SwitchingGame / ScreenedSwitchingGame の仕様と選択基準
Phase 0: 初期化
0-1: pkdx 存在確認
$PKDX nash --help >/dev/null 2>&1 && echo "OK" || echo "NOT_FOUND"
NOT_FOUND の場合は以下を案内してスキルを終了:
pkdx CLI が見つかりません。リポジトリルートで以下を実行:
./setup.sh
moon build --target native src/main
Phase 1: タスク選択 (AskUserQuestion)
| # | 質問 | header | オプション |
|---|---|---|---|
| 1 | 何を計算しますか? | 計算種別 | 既知の行列を解く (nash solve), 選出最適 (select), メタ乖離分析 (meta-divergence), 構築マッチアップ DOT グラフ (nash graph) |
選択に応じて Phase 2 以降に分岐。
Phase 2a: pkdx nash solve — 行列 / monocycle characters を解く
入力形式の決定
| # | 質問 | header | オプション |
|---|---|---|---|
| 1 | 入力の種類は? | 入力形式 | 行列を直接入力 (matrix), monocycle character (p, v) リスト (characters) |
matrix 形式: n×n の実数行列。対称・反対称を問わない。零和にしたい場合は A[j,i] = -A[i,j] を自前で設定するか、monocycle 形式を使う。
characters 形式: 各キャラに label (名前)、power (スカラー p)、v (2D ベクトル {x, y})。利得は A[i,j] = (pᵢ − pⱼ) + vᵢ × vⱼ で自動生成。
実行
cat <<'JSON' | $PKDX nash solve
{
"matrix": [[0, 1, -1], [-1, 0, 1], [1, -1, 0]],
"labels": ["R", "P", "S"]
}
JSON
または:
cat <<'JSON' | $PKDX nash solve
{
"characters": [
{"label": "A", "power": 0, "v": {"x": 2, "y": 0}},
{"label": "B", "power": 0, "v": {"x": -1, "y": 1.7}},
{"label": "C", "power": 0, "v": {"x": -1, "y": -1.7}}
]
}
JSON
出力 JSON:
{
"value": 0,
"row_strategy": [0.333, 0.333, 0.333],
"col_strategy": [0.333, 0.333, 0.333],
"exploitability": 0,
"support": {"row": [0, 1, 2], "col": [0, 1, 2]},
"labels": ["R", "P", "S"]
}
結果整形
## Nash 均衡結果
- **ゲーム値**: {value}
- **exploitability**: {exploitability} (< 1e-6 なら厳密解とみなしてよい)
### 行プレイヤーの混合戦略
| index | label | 確率 |
|---|---|---|
| 0 | {labels[0]} | {row_strategy[0]:.3f} |
...
### 列プレイヤーの混合戦略
(同上)
### support
- 行: {labels of support.row}
- 列: {labels of support.col}
Phase 2b: pkdx select — 選出最適化
入力の収集
team (6 体), opponent (6 体), format (single のみ対応), team_payoff_model を取得する。
データソース
box/teams/*.meta.json(推奨) — team-builder Phase 8 または Champions スクショ取り込みで生成される。.meta.jsonのmembers配列がそのまま combatant として使える (types[]+base_stats{}形式をpkdx selectが直接受け付ける)。- ユーザー直接入力 — 上記がない場合、ポケモン名・ステータス・技を対話で収集する。
.meta.json からの読み込み手順
# 1. 自チームの .meta.json を特定
ls box/teams/*.meta.json
# 2. members を team / opponent に詰め替えて select に渡す
# skill は .meta.json の "members" を "team" キーに、
# 相手の .meta.json の "members" を "opponent" キーに設定する。
# battle_format は "singles" → "single" に変換。
重要: .meta.json の members にはステータスが種族値 (base_stats) の場合と実数値 (hp/atk/...) の場合がある。Champions スクショ取り込み経由なら実数値が揃っているが、skill 手順で作成した場合は種族値のみの可能性がある。足りないデータ (実数値、priority、stat_effects 等) がある場合はユーザーに補完を促す。
モデル選択肢 (team_payoff_model フィールド)
"switching_game"(既定) — 交代込み extensive-form ゲーム木。DP turn_limit=5 既定 (先制技 / ランク補正技に対応)。長期戦評価が必要なら"switching_game:<N>"で turn_limit を上書き可"screened_switching_game:<trials>:<seed>:<keep_top>"— MC で選出行列を screening (rollout turn_limit=5)、下位を quantile cutoff で枝刈り、残存 sub-matrix だけ SwitchingGame DP (refine turn_limit=5 既定)。例:"screened_switching_game:1000:42:0.3"。パラメータを細かくチューニングしたいときだけ明示指定する
CLI 側の自動フォールバック: switching_game:<N> で N >= 5 のとき、pkdx select は内部で ScreenedSwitchingGame(trials=1000, seed=42, keep_top=0.3, refine_turn_limit=N) に自動昇格する。skill 側で screening をどう使うか判断する必要はなく、常に switching_game:<N> で turn_limit だけ指定すればよい。明示的に screened_switching_game:... を書いた場合はそのまま使われる。
詳細は references/payoff_semantics.md。
読みターン数の決定 (AskUserQuestion)
team_payoff_model 文字列を構築する直前に、ユーザーに「何ターン先まで読むか」を AskUserQuestion で必ず確認する。選択結果を switching_game:<N> / screened_switching_game:<trials>:<seed>:<keep_top>:<N> の <N> に埋め込む。
| # | 質問 | header | オプション |
|---|---|---|---|
| 1 | 何ターン先まで読みますか? | 読みの深さ | おまかせ(5ターン先まで・通常対戦向け), じっくり読む(10ターン先まで・積み展開も評価/時間長め), サクッと(3ターン先まで・パーティ調整中の素早い確認) |
ユーザー視点の言い換え(質問・選択肢に出す表現はこちら、内部で扱う turn_limit 値は次の対応表):
| ラベル | turn_limit | こう案内する |
|---|---|---|
| おまかせ(5ターン先まで) | 5 | 通常の対戦想定。ほとんどの構築・選出で十分な精度 |
| じっくり読む(10ターン先まで) | 10 | 積み技や全抜き展開、長期戦の見極めに。計算は数倍〜10 倍ほど時間がかかります |
| サクッと(3ターン先まで) | 3 | パーティを調整しながら大まかな選出傾向だけ早く確認したいとき |
ユーザーが「Other」で任意の正整数を入力した場合はそれを <N> に埋め込む。負値・0 は弾く。「ターン」を「先読み」「深さ」と言い換えても OK だが、turn_limit / DP などの内部用語はユーザー向け文面に出さないこと。
エンコード:
- 基本は
"switching_game:<N>"を組み立てるだけでよい。N >= 5のとき CLI が内部で screening 版に自動昇格するので、skill 側でscreened_switching_game:...を構築する必要はない - screening パラメータ (
trials/seed/keep_top) をユーザーが明示的に変更したい場合のみ"screened_switching_game:<trials>:<seed>:<keep_top>:<N>"を直接指定する
実行
1. 入力 JSON をファイルへ保存
実行主体に関わらず、入力 JSON はまず /tmp/pkdx_select_input.json に書き出す (ユーザー手動ルートでも同じファイルを参照させるため heredoc ではなくファイル経由に統一する)。技の priority / stat_effects は pkdx moves 出力をそのまま流せる。省略時はデフォルト (priority=0 / stat_effects=[]) 扱い。
cat > /tmp/pkdx_select_input.json <<'JSON'
{
"team": [
{"name":"P0","type1":"ノーマル","type2":"","hp":100,"atk":100,"def":80,"spa":80,"spd":80,"spe":100,
"ability":"","item":"","tera":"",
"moves":[{"name":"のしかかり","type":"ノーマル","category":"物理","power":85,"priority":0,"stat_effects":[]}]},
...
],
"opponent": [...],
"format": "single",
"stat_system": "champions",
"team_payoff_model": "switching_game:<N>"
}
JSON
<N> は直前の AskUserQuestion で得た値を埋める (おまかせ=5 / じっくり読む=10 / サクッと=3、Other 入力時はその正整数)。screened_switching_game を選んだ場合は "screened_switching_game:1000:42:0.3:<N>" のように 4 番目のフィールドとして同じ値を付ける。
2. 実行主体の決定 (AskUserQuestion)
| # | 質問 | header | オプション |
|---|---|---|---|
| 1 | 計算を誰が実行しますか? | 実行主体 | エージェントが実行(結果だけ受け取る), ターミナルで自分で実行(計算過程をグリッドで見たい) |
ユーザー視点の言い換え(質問・選択肢の文面はこちら、内部分岐は下記):
| ラベル | 挙動 | こう案内する |
|---|---|---|
| エージェントが実行 | skill が直接 Bash 実行 | サクッと結果だけ欲しいとき。進捗は [viz] phase ... done の数行ログのみ |
| ターミナルで自分で実行 | コマンドを提示してユーザーが別ターミナルで実行 | 計算過程を 60×60 グリッドで眺めたいとき。長めの計算で進捗を視覚的に追える |
3a. 「エージェントが実行」を選んだ場合
$PKDX select --parallel=auto --progress=json 2> >($VIZ) > /tmp/pkdx_select_result.json < /tmp/pkdx_select_input.json
cat /tmp/pkdx_select_result.json # ← 結果整形フェーズで使う
進捗フィードバックを止めたい場合: --progress=off (既定値) を明示するか、2> >($VIZ) を外す。長い --progress-every を渡せば dp ノードサンプル頻度を間引ける (例: --progress-every=5000)。
--parallel フラグ:
- 既定値
1は in-process 計算で、damage cache (box/cache/damage_cache.sqlite) の L2 を活用する。同じチーム / 相手で複数回連続呼ぶ場合はこちらの方が速い (ヒット率が高いと 2 回目以降が大幅短縮)。 autoはnproc()(Windows は 64 で clamp) でシャード並列実行する。turn_limit が大きい (5+) で初回計算かつ単発で結果を欲しい場合に最速。シャードでは damage cache (disk) を使わないため L2 ヒット率は下がるが、CPU を全コア使い切れる利得が遥かに大きい。- 明示的に整数を渡すこともできる (
--parallel=8等)。Windows 上ではMAXIMUM_WAIT_OBJECTS=64の制約があり、それを超える明示指定はエラーになる。 - 緊急時は
PKDX_NO_PARALLEL=1環境変数でauto指定を強制 1 に落とせる (テスト・デバッグ用 escape hatch)。
bit-exact parity は保たれているため、結果 JSON は --parallel 値に依存しない。
3b. 「ターミナルで自分で実行」を選んだ場合
-
ユーザーへコマンドを提示する。
<REPO_ROOT>はpwdで取得した実体パス (例:/Users/.../pkdx) に展開し、コードブロックでそのままコピペできる形で渡すこと:別ターミナルで以下を実行してください。完了したら次の選択肢で教えてください。 ```bash cd <REPO_ROOT> && cat /tmp/pkdx_select_input.json \ | bin/pkdx select --parallel=auto --progress=json 2> >(scripts/select_grid_viz.sh) \ > /tmp/pkdx_select_result.json ``` グリッドビジュアライザは並列パスでも動くが、子プロセスは `--progress=off` を強制するため細粒度の `cell_start` イベントは出ない。`PhaseStart` / `PhaseEnd` レベルの進捗だけ流れる。細粒度表示を見たい場合は `--parallel=1` を明示する (代わりに数倍遅くなる)。 -
提示後、AskUserQuestion で完了確認を取る:
# 質問 header オプション 1 実行は完了しましたか? 実行状況 完了したので結果を見せて, やっぱりエージェントに実行させる, キャンセル -
分岐:
- 完了したので結果を見せて:
/tmp/pkdx_select_result.jsonを Read で読み込み、結果整形フェーズへ進む。ファイル不在 / 空 /valueキー欠落のときはエラーを伝えて再実行 or フォールバックを促す - やっぱりエージェントに実行させる: 3a へフォールバック
- キャンセル: スキルを終了
- 完了したので結果を見せて:
出力:
{
"format": "single",
"value": 0.0,
"exploitability": 0.0,
"selections": [[0,1,2], [0,1,3], ..., [1,0,2], ...],
"selection_names": [["P0","P1","P2"], ...],
"opp_selections": [...],
"opp_selection_names": [...],
"row_strategy": [...],
"col_strategy": [...]
}
各 selection は [lead, b1, b2] の 順序付きタプルで、位置 0 が先頭選出 (lead)、後ろ 2 体は控え (昇順)。シングル 6v6 では 6 × C(5,2) = 60 通り列挙されるので row_strategy / col_strategy も長さ 60。同じメンバー集合でも先頭が違えば別エントリ扱いになる点に注意 (例: [0,1,2] と [1,0,2] は別物)。
結果整形
確率 > 1% の選出のみ表示。先頭の Pokémon は 太字で強調する:
## 選出分布 ({format})
- **期待勝率 (value)**: {value:.3f}
- **exploitability**: {exploitability:.6f}
### 採用すべき選出
| 確率 | 先頭 → 控え |
|---|---|
| {p:.1%} | **{names[0]}** → {names[1]}, {names[2]} |
...
### 相手の最適選出
(同上)
Phase 2c: pkdx meta-divergence — メタ乖離分析
入力の収集
usage: 各ポケモン/構築の使用率 (合計 1)matrix: 対応するマッチアップ行列labels: 名前
実行
cat <<'JSON' | $PKDX meta-divergence
{
"usage": [0.4, 0.3, 0.3],
"matrix": [[0, 1, -1], [-1, 0, 1], [1, -1, 0]],
"labels": ["R", "P", "S"]
}
JSON
出力:
{
"exploitability": 0.0,
"expected_value": 0.0,
"regrets": [0.0, 0.0, 0.0],
"over_used": [],
"under_used": [],
"labels": ["R", "P", "S"]
}
結果整形
## メタ乖離レポート
- **期待利得 σᵀAσ**: {expected_value:.3f}
- **exploitability**: {exploitability:.3f}
### 各要素の regret
| label | 使用率 | regret |
|---|---|---|
| {labels[i]} | {usage[i]:.1%} | {regrets[i]:+.3f} |
### 過剰使用 (over_used)
{names — 使用率 > 0 だが負の regret = 本来避けるべき}
### 過少使用 (under_used)
{names — 負の regret だが使用率 < ε = 本来選ぶべき}
Phase 2d: pkdx nash graph — DOT 可視化
3 種類の入力を受け付ける:
- matrix 形式: 既知の利得行列を直接渡す
- characters 形式: monocycle (p, v) リストから自動生成
- team + opponent 形式:
pkdx selectと同じ Combatant JSON。box/teams/*.meta.jsonのmembersをそのまま流せる
# matrix 形式
cat <<'JSON' | $PKDX nash graph --threshold 0.5
{"matrix": [[0, 1, -1], [-1, 0, 1], [1, -1, 0]], "labels": ["R", "P", "S"]}
JSON
# team + opponent 形式 (.meta.json 直接利用)
jq -n \
--slurpfile team box/teams/<自>.meta.json \
--slurpfile opp box/teams/<相手>.meta.json \
'{team: $team[0].members, opponent: $opp[0].members}' \
| $PKDX nash graph --threshold 0.2 > matchup.dot
dot -Tpng matchup.dot -o matchup.png
team + opponent 形式の詳細
- 入力フィールド:
team/opponent(必須、Combatant 配列)、stat_system(任意、既定"champions")、turn_limit(任意、既定1) - 行列サイズ:
(n + m) × (n + m)の零和拡張。上半[0..n)が自チーム、下半[n..n+m)が相手チーム。同陣営ブロックは可視化用ゼロ埋め - ノード ID:
team_<i>/opp_<j>の安定 ID +label="..."属性。両陣営に同名ポケモンが居ても DOT で衝突しない labelsフィールドは指定不可(メンバー名から自動生成)。明示するとエラーmatrix/charactersとの同時指定もエラー
turn_limit の使い分け
turn_limit | 評価方式 | コスト |
|---|---|---|
1 (既定) | 攻撃技の平均削り率差 (fast path) | 36セルで <1秒 |
>=2 | switching_game_winrate([a],[b],N) 1v1 DP | turn_limit に応じて秒〜数十秒 |
turn_limit を上げると積み技や交代評価が反映されるが、6×6=36 セルで全1v1 DP を解くため 5以上は本物の 6体構築では数十秒以上かかる。先に 1 で傾向を見てから必要なら上げる。
threshold で |A[i,j]| がその値以下のエッジを削除。大きな行列の可視化で有効。
エラーハンドリング
| 状況 | 対応 |
|---|---|
invalid JSON: ... | 入力 JSON の構文エラー。再入力を依頼 |
missing field: ... | 必須フィールド不足。仕様を再提示して再入力 |
both matrix and characters provided; pick one | どちらか一方を削除 |
matrix is not square: NxM | 正方行列に修正 |
usage does not sum to 1 (got X) | 使用率を正規化し直す |
game is infeasible / unbounded | 入力が退化 (LP が解けない)。対角/反対称性を確認 |
計算条件の注意
- stat_system:
pkdx selectは Champions SP 既定 ("stat_system": "champions")。トップレベル JSON の"stat_system"フィールドで"champions"(既定) /"standard"を切り替え可能。旧バージョン (SV 等) のデータを使う場合は"stat_system": "standard"を明示する。 - 天候・フィールド・ランク: 現バージョンは 0 固定。動的状態を含む選出最適化は将来対応。
- tera_type:
combatant.teraフィールドで指定可能。攻撃側 STAB のみに作用し、防御側タイプ書換は未実装。
Signals
- GitHub stars
- 54
- Forks
- 113
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
nash- Source
- github.com/pkdxtools/pkdx