ポケモンカード AI Battle Challenge(対戦映像を見よう)

Linux

前回、ブログで環境構築をしました。

できます。いまの ~/pokemon-ai/agents/v1v2 をそのまま使って、記事と同じ「カード画像付きリプレイ」方式を作りましょう。

記事の流れは、cg.game で対戦 → visualize_data() でリプレイJSONを生成 → visualizer.html から HEROZ のVisualizerへ渡す、という流れです。

1. フォルダを作る

まずMacのターミナルで実行してください。

cd ~/pokemon-ai

mkdir -p decks simulations replays

cp -R agents/v1 decks/v1
cp -R agents/v2 decks/v2

cp -R agents/v1/cg simulations/cg

こうなればOKです。

pokemon-ai/
├── agents/
│   ├── v1/
│   └── v2/
│
├── decks/
│   ├── v1/
│   │   ├── main.py
│   │   ├── deck.csv
│   │   └── cg/
│   └── v2/
│       ├── main.py
│       ├── deck.csv
│       └── cg/
│
├── simulations/
│   └── cg/
│
└── replays/

記事でも、decks/<名前>/main.py + deck.csv と、simulations/cg を置く構成になっています。

確認します。

find decks simulations -maxdepth 2 -type f | sort

2. run_battle.py を作る

VS Codeで

~/pokemon-ai/simulations/run_battle.py

を新規作成してください。

以下を貼り付けます。

import importlib.util
import json
import os
import sys
from datetime import datetime
from pathlib import Path

from cg.game import (
    battle_start,
    battle_finish,
    battle_select,
    visualize_data,
)

ROOT = Path(__file__).resolve().parents[1]
DECKS_DIR = ROOT / "decks"
REPLAYS_DIR = ROOT / "replays"


def load_deck(name):
    path = DECKS_DIR / name / "deck.csv"

    deck = []

    with open(path, "r", encoding="utf-8-sig") as f:
        for line in f:
            value = line.strip().split(",")[0]

            if value.isdigit():
                deck.append(int(value))

    if len(deck) != 60:
        raise ValueError(
            f"{name}: deck.csv が60枚ではありません "
            f"({len(deck)}枚)"
        )

    return deck


def load_agent(name):
    agent_dir = DECKS_DIR / name
    main_path = agent_dir / "main.py"

    # main.py から cg をimportできるようにする
    if str(agent_dir) not in sys.path:
        sys.path.insert(0, str(agent_dir))

    spec = importlib.util.spec_from_file_location(
        f"{name}_main",
        main_path,
    )

    module = importlib.util.module_from_spec(spec)

    old_cwd = os.getcwd()

    try:
        # main.py が deck.csv を相対パスで読むため
        os.chdir(agent_dir)
        spec.loader.exec_module(module)
    finally:
        os.chdir(old_cwd)

    return module.agent


def main():
    player1_name = "v1"
    player2_name = "v2"

    deck1 = load_deck(player1_name)
    deck2 = load_deck(player2_name)

    agent1 = load_agent(player1_name)
    agent2 = load_agent(player2_name)

    print(f"Player 1 : {player1_name}")
    print(f"Player 2 : {player2_name}")
    print("Battle start...")

    obs, _ = battle_start(deck1, deck2)

    try:
        while True:

            result = obs["current"]["result"]

            if result >= 0:
                break

            player = obs["current"]["yourIndex"]

            if player == 0:
                action = agent1(obs)
            else:
                action = agent2(obs)

            # battle_selectへ不要なので削除
            obs.pop("search_begin_input", None)

            obs = battle_select(action)

        print()
        print("Battle finished.")

        result = obs["current"]["result"]

        if result == 0:
            print("Winner: v1")
        elif result == 1:
            print("Winner: v2")
        else:
            print("Draw")

        # リプレイデータ取得
        replay = json.loads(visualize_data())

        REPLAYS_DIR.mkdir(exist_ok=True)

        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")

        replay_path = (
            REPLAYS_DIR /
            f"{timestamp}_{player1_name}_vs_{player2_name}.json"
        )

        with open(
            replay_path,
            "w",
            encoding="utf-8",
        ) as f:
            json.dump(
                replay,
                f,
                ensure_ascii=False,
            )

        print()
        print(f"Replay saved:")
        print(replay_path)

    finally:
        battle_finish()


if __name__ == "__main__":
    main()

ここで重要なのが、

visualize_data()

です。これがカード画像付きVisualizerが再生するためのリプレイ情報を生成します。記事でもこのデータをJSONにしてブラウザから再生しています。


3. まずV1 vs V2を実行する

これまでと同じDockerを使います。

cd ~/pokemon-ai

実行:

docker run --rm \
  --platform linux/amd64 \
  -v "$PWD":/work \
  -w /work/simulations \
  gcr.io/kaggle-images/python \
  python run_battle.py

成功すれば例えば、

Player 1 : v1
Player 2 : v2
Battle start...

Battle finished.
Winner: v2

Replay saved:
/work/replays/20260809_105500_v1_vs_v2.json

となります。

Mac側にも、

~/pokemon-ai/replays/

の中にJSONができます。

確認:

ls -lh ~/pokemon-ai/replays

4. visualizer.html を作る

次に、

~/pokemon-ai/simulations/visualizer.html

をVS Codeで作ります。

以下を貼り付けてください。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, initial-scale=1">

    <title>PTCG AI Replay</title>
</head>

<body>

<h2>Pokémon TCG AI Battle Replay</h2>

<p>リプレイJSONを選択してください。</p>

<input
    type="file"
    id="replayFile"
    accept=".json"
>

<script>

const fileInput =
    document.getElementById("replayFile");

fileInput.addEventListener("change", function () {

    const file = fileInput.files[0];

    if (!file) {
        return;
    }

    const reader = new FileReader();

    reader.onload = function () {

        const data = JSON.parse(reader.result);

        const hidden = document.createElement("input");

        hidden.type = "hidden";
        hidden.name = "json";

        /*
         Kaggle形式とローカル形式の両方に対応
        */
        if (data.steps) {
            hidden.value =
                JSON.stringify(
                    data.steps[0][0].visualize
                );
        } else {
            hidden.value =
                JSON.stringify(data);
        }

        const form =
            document.createElement("form");

        form.method = "POST";

        form.action =
            "https://ptcgvis.heroz.jp/Visualizer/Replay/0";

        form.target = "_blank";

        form.appendChild(hidden);

        document.body.appendChild(form);

        form.submit();
    };

    reader.readAsText(file);

});

</script>

</body>
</html>

このHTMLは、選択したJSONを読み込んでPTCG VisualizerへPOSTし、新しいタブでリプレイを開く役割です。記事でも同じ仕組みを使っています。

一点だけ注意すると、この操作では対戦リプレイJSONが ptcgvis.heroz.jp に送信されます。 自作AIの盤面履歴を外部サービスへ送信したくない場合は使わないでください。


5. Visualizerを開く

Macなら簡単です。

open ~/pokemon-ai/simulations/visualizer.html

ブラウザに、

Pokémon TCG AI Battle Replay

リプレイJSONを選択してください。

[ファイルを選択]

と表示されます。


6. JSONを選ぶ

「ファイルを選択」を押して、

pokemon-ai
  └ replays
      └ 20260809_105500_v1_vs_v2.json

を選びます。

すると新しいタブが開きます。
(ブラウザの設定によってはポップアップがブロックされるので、許可してあげる必要があります)

ここで記事に掲載されているような、実際のカード画像を使った対戦リプレイが表示されるはずです。記事でも visualizer.htmlvis.json 選択 → 別タブでリプレイ、という手順になっています。

実際の対戦動画

コメント

タイトルとURLをコピーしました