0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Slay the Spire 2のゲーム状態をLLMに渡してAI軍師を作った話

0
Last updated at Posted at 2026-06-07

はじめに

Slay the Spire 2を遊びながら、ふと思いました。

「これ、AIに手札や敵の情報を渡したら、どんな判断をするんだろう?」

ローグライクカードゲームは、毎ターン状況が変わります。
手札、エナジー、敵の行動、HP、デッキ、レリック、ポーション、イベント選択肢など、判断材料が非常に多いです。

そこで今回は、Slay the Spire 2のプレイ状況をAIに渡して、次の行動を相談できるアプリケーションを作ってみました。

ゲーム状態の取得には、Slay the Spire 2向けのModである STS2MCP を利用しています。

STS2MCP は、ゲーム内の状態をローカルAPI経由で取得したり、外部ツールからゲームに対して操作を送ったりできるModです。
さらにMCPサーバーとしても利用できるため、Claude DesktopやClaude CodeのようなMCP対応クライアントからゲーム状態を扱うこともできます。

今回作ったアプリでは、STS2MCPを「ゲーム状態を取得するための基盤」として使い、その上に以下のような仕組みを実装しました。

  • 現在のゲーム状態を取得する
  • 戦闘・イベント・カード選択・休憩所など、場面ごとにプロンプトを切り替える
  • AIが「次に何をすべきか」を配信向けにわかりやすく返す
  • OBSのテキスト表示や読み上げと連携する
  • 必要に応じてホットキーで再問い合わせできる

この記事では、STS2MCPを使ってゲーム状態を取得し、それをLLMに渡して「AI軍師」として配信に組み込むまでの流れをまとめます。

作ったもの

作ったのは、Slay the Spire 2のプレイをサポートする「AI軍師」アプリです。

プレイヤーがゲームを進めると、アプリ側で現在の状況を取得し、AIに問い合わせます。
AIはその状況をもとに、以下のような助言を返します。

  • このターンに使うべきカード
  • 攻撃と防御の優先度
  • イベント選択肢のおすすめ
  • 取得すべきカード
  • 休憩所で回復するか、強化するか
  • 今後のデッキ方針

ゲーム配信で使うことも想定しているため、回答は長すぎず、視聴者にもわかりやすい形に整えています。

例としては、以下のようなイメージです。

【軍師】
作戦: まずは被ダメージを抑えつつ、次ターン以降の火力につなげる。
対象: 防御カードを優先し、余ったエナジーで攻撃。
理由: 敵の攻撃が重いため、ここでHPを削られすぎると後半が厳しくなる。

STS2MCPについて

今回のアプリでは、Slay the Spire 2のゲーム状態を取得するために STS2MCP を利用しています。

STS2MCPは、Slay the Spire 2のゲーム内状態を外部ツールから扱えるようにするModです。

主に以下のような情報を取得できます。

  • 現在の状態
  • 戦闘中のプレイヤー情報
  • 手札
  • 敵の情報
  • イベント情報
  • 選択肢
  • レリック
  • ポーション
  • デッキ情報

また、外部ツールから操作を送ることもできるため、単なる状態取得だけでなく、AIエージェントによる自動プレイにも応用できる構成になっています。

今回のアプリでは、いきなり完全自動プレイを目指すのではなく、まずは「AIが判断し、人間が操作する」形にしました。

つまり、STS2MCPを使ってゲーム状態を取得し、その状態をAIに渡して、AIから助言をもらう構成です。

Slay the Spire 2
  ↓
STS2MCP
  ↓
ローカルAPI
  ↓
Pythonアプリ
  ↓
LLM
  ↓
AIの助言
  ↓
OBS表示 / 読み上げ

個人的には、ここがかなり面白いポイントでした。

STS2MCPによって、ゲームの状態を「人間が画面を見て判断する情報」から「プログラムが扱える構造化データ」に変換できます。

そのため、LLMに対しても、

「今こういう状況です。次に何をすべきですか?」

とかなり具体的に聞けるようになります。

全体構成

ざっくりした構成は以下です。

Slay the Spire 2
↓ 
STS2MCP
↓ 
ゲーム状態の取得 
↓ 
Pythonアプリ
↓ 
state_typeごとに処理を分岐
↓ 
場面ごとのプロンプト生成
↓ 
LLM API
↓ 
AIの助言
↓ 
OBS表示 / 読み上げ / ホットキー操作

アプリ側では、現在の状態を以下のような種類に分類しています。

  • 戦闘中
  • イベント中
  • カード選択
  • 休憩所
  • 報酬選択
  • その他の状態

状態によってAIに聞くべき内容が変わるため、単一のプロンプトですべて処理するのではなく、場面ごとにプロンプトを分ける方針にしました。

コード解説1: STS2MCPからゲーム状態を取得する

まずは、STS2MCPが公開しているローカルAPIから現在のゲーム状態を取得します。

実際のエンドポイント名は利用しているバージョンや構成によって変わる可能性がありますが、イメージとしては以下のような処理です。

import requests 
STS2MCP_BASE_URL = "http://127.0.0.1:8080" def fetch_game_state() -> dict: 
    response = requests.get( 
        f"{STS2MCP_BASE_URL}/state", 
        timeout=5, 
    ) 
    response.raise_for_status() 
    return response.json()

この処理で取得したJSONを、以降のAI判断の入力として使います。

ポイントは、画面キャプチャやOCRではなく、ゲーム状態を構造化データとして取得できるところです。

画面を画像としてAIに見せる方法もありますが、カード名、敵のHP、選択肢、イベント情報などをテキスト・JSONとして扱える方が、プロンプトに組み込みやすくなります。

コード解説2: state_typeで処理を分ける

STS2MCPから取得したゲーム状態には、現在の状態を表す情報が含まれます。

この状態をもとに、どのプロンプトを使うかを切り替えます。

def build_prompt(game_state: dict) -> str: 
    state_type = game_state.get("state_type") 
    
    if state_type == "combat": 
        return build_combat_prompt(game_state) 
    
    if state_type == "event": 
        return build_event_prompt(game_state) 
    
    if state_type == "card_reward": 
        return build_card_reward_prompt(game_state) 
    
    if state_type == "rest": 
        return build_rest_prompt(game_state) 
    
    return build_general_prompt(game_state)

戦闘中であれば「どのカードをどの順番で使うか」が重要になります。
イベント中であれば「どの選択肢を選ぶべきか」が重要になります。
カード報酬であれば「今のデッキ方針に合うカードはどれか」が重要になります。

単一のプロンプトですべてを処理するよりも、状況ごとにAIへ渡す観点を絞った方が、回答が安定しやすくなりました。

コード解説3: 戦闘用プロンプトを生成する

戦闘中は、手札・エナジー・敵の行動予定・HPなどをもとに判断してもらいます。

def build_combat_prompt(game_state: dict) -> str: 
    player = game_state.get("player", {}) 
    hand = game_state.get("hand", []) 
    enemies = game_state.get("enemies", []) 
    relics = game_state.get("relics", []) 
    potions = game_state.get("potions", []) 
    
    return f"""
あなたはSlay the Spire 2の攻略を支援するAI軍師です。 

現在の戦闘状況をもとに、次に取るべき行動を判断してください。 

# 判断方針
- まず生存を優先してください
- 敵の行動予定を考慮してください
- カードの使用順を明確にしてください
- 不明な情報は推測しすぎないでください
- 配信で読み上げるため、短くわかりやすく答えてください

# プレイヤー情報 
HP: {player.get("hp")}
ブロック: {player.get("block")} 
エナジー: {player.get("energy")} 

# 手札 
{format_cards(hand)} 

# 敵情報 
{format_enemies(enemies)} 

# レリック 
{format_relics(relics)} 

# ポーション {format_potions(potions)}

# 出力形式 
作戦: 
カード使用順: 
理由:
"""

AIに「自由に考えて」と投げるのではなく、判断方針と出力形式を指定しているところがポイントです。

特に配信で使う場合、AIの回答が長すぎるとテンポが悪くなります。

そのため、以下のように出力形式を固定しています。

作戦:
カード使用順:
理由:

これにより、OBS表示もしやすく、読み上げにも使いやすくなりました。

コード解説4: イベント用プロンプトを生成する

イベント中は、戦闘とは判断基準が変わります。

必要なのはカードの使用順ではなく、選択肢ごとのリスクとリターンです。

def build_event_prompt(game_state: dict) -> str: 
    event = game_state.get("event", {}) 
    player = game_state.get("player", {}) 
    deck = game_state.get("deck", []) 
    
    return f""" 
あなたはSlay the Spire 2の攻略を支援するAI軍師です。 

現在のイベント内容を読み、どの選択肢を選ぶべきか判断してください。 

# 判断方針
- 現在HPとデッキ状況を考慮してください
- リスクとリターンを比較してください
- 長期的に強くなれる選択肢を評価してください
- 危険な選択肢を選ぶ場合は理由を説明してください
- 最終的なおすすめを1つに絞ってください
 
# プレイヤー情報 
HP: {player.get("hp")} 

# 現在のデッキ概要 
{format_deck_summary(deck)} 

# イベント名 
{event.get("event_name")} 

# イベント本文 
{event.get("body")} 

# 選択肢 
{format_event_options(event.get("options", []))} 

# 出力形式 
おすすめ: 
理由: 
注意点: 
"""

イベントでは、選択肢名だけを渡すとAIが判断しづらいことがありました。

例えば、選択肢のタイトルだけでは、それがレリック獲得なのか、HPを失うのか、カードを追加するのかがわかりません。

そのため、選択肢ごとの説明や効果も含めて渡すようにしました。

def format_event_options(options: list[dict]) -> str: 
    lines = [] 
    
    for option in options: 
        locked = "ロック中" if option.get("is_locked") else "選択可能" 
        
        lines.append( 
            f""" 
[{option.get("index")}] {option.get("title")} 
状態: {locked} 
説明: {option.get("description")} 
"""
        ) 
        
    return "\n".join(lines)

STS2MCPから取得できる構造化されたイベント情報があることで、選択肢の比較をAIに任せやすくなりました。

STS2MCPを使って感じたこと

STS2MCPを使うことで、ゲーム画面を人間が目視して判断するだけでなく、ゲーム状態を外部アプリから扱えるようになります。

これはかなり大きいです。

例えば、通常であればAIにゲーム状況を伝えるには、画面キャプチャを使ったり、手動で状況を書いたりする必要があります。

しかし、STS2MCPを使うと、手札、敵、イベント、選択肢などを構造化されたデータとして取得できます。

そのため、LLMに対してもかなり具体的に状況を渡せます。

今の手札はこれです。
敵はこの行動を予定しています。
プレイヤーのHPはこのくらいです。
選択肢はこの3つです。
この状況で一番良い行動を判断してください。

この形にできると、AIの回答もかなり安定します。

一方で、STS2MCPが取得してくれる情報をそのまま投げれば完璧、というわけではありませんでした。

AIに渡す前に、

  • どの情報が判断に必要か
  • どの情報は省略してよいか
  • 今が戦闘なのかイベントなのか
  • 最終的にどの形式で回答してほしいか

をアプリ側で整理する必要があります。

つまり、STS2MCPは「ゲーム状態を取得する層」であり、今回作ったアプリは「AIに判断させ、配信で使える形に変換する層」という位置づけです。

この役割分担にすると、かなり扱いやすくなりました。

OBS・読み上げとの連携

AIの回答は、OBS上に表示できるようにテキストファイルへ出力しています。

OBS側では、そのテキストファイルを読み込むことで、配信画面上にAIの助言を表示できます。

また、読み上げ用にVOICEVOXなどの音声合成と組み合わせることで、AIが実際に喋っているような演出も可能にしました。

ただし、読み上げ用の文章には少し整形が必要でした。

例えば、画面表示用には以下のような見出しがあると見やすいです。

作戦:
対象:
理由:

一方で、読み上げ時にはそのままだと不自然になることがあります。

そのため、読み上げ前には以下のような変換を入れています。

text = text.replace("作戦:", "作戦。")
text = text.replace("対象:", "対象。")
text = text.replace("理由:", "理由。")

細かい部分ですが、配信で使う場合はこうした調整がかなり効きます。

ハマったこと

AIの回答がすぐ上書きされる

OBSのテキストが更新されないように見える問題がありました。

調べてみると、ホットキーで問い合わせた回答自体は生成されているものの、その直後に次の自動処理が走り、表示内容が上書きされていました。

そのため、手動問い合わせ中は自動問い合わせを一時的に止める、または手動問い合わせ結果を優先表示する、といった制御が必要になりました。

イベント選択肢の解釈

イベントでは、選択肢の効果をAIが正しく理解できるかが重要でした。

選択肢名だけを渡すと、AIが効果を推測してしまうことがあります。

そのため、以下のような情報をなるべくセットで渡すようにしました。

  • 選択肢名
  • 説明
  • 効果
  • 選択可能かどうか
  • 獲得できるカードやレリック
  • HP変動
  • ロック状態

AIに判断してもらう場合でも、入力データの構造化はかなり重要だと感じました。

AIに全部任せると回答がブレる

LLMは柔軟に回答してくれますが、ゲーム攻略では一貫性も重要です。

そのため、以下のような制約を入れた方が安定しました。

  • まず現在の生存を優先する
  • リスクが高い選択肢は理由を明記する
  • カード選択では現在のデッキ方針に合うかを見る
  • 不確実な情報は断定しない
  • 最終的な推奨行動を1つに絞る

AIに自由に考えさせる部分と、アプリ側でルール化する部分のバランスが大事でした。

作ってみて感じたこと

ゲームとAIの相性はかなり良いと感じました。

特にSlay the Spireのようなカードゲームは、状況判断の連続です。
AIに現在の状態を渡すことで、「なぜそのカードを使うのか」「なぜその選択肢を選ぶのか」を言語化してくれます。

これは攻略支援としても面白いですが、配信コンテンツとしてもかなり相性が良いです。

プレイヤーがAIに相談しながら進めることで、視聴者も「AIはそう考えるのか」「いや、それは違うだろ」とツッコミながら見られます。

単なる自動プレイではなく、人間とAIが一緒に悩む形にできるのが面白いポイントでした。

今後やりたいこと

今後は、以下のような改善を考えています。

  • 過去の判断履歴をAIに渡す
  • デッキ方針を長期記憶として持たせる
  • ボスやエリートに向けた中長期戦略を考えさせる
  • AIの判断と実際の結果を比較する
  • 視聴者コメントをAIの判断材料に入れる
  • AIの人格をより配信向けに調整する
  • 回答の優先度や緊急度を出せるようにする
  • STS2MCPの操作APIも活用して、将来的には一部操作の自動化も試す

特に、単発の判断だけでなく「このランでは何を目指しているのか」をAIに持たせると、より軍師らしくなりそうです。

また、今回は「AIが判断して、人間が操作する」形にしましたが、STS2MCPは外部ツールから操作を送ることもできるため、将来的にはAIエージェントによる半自動プレイや検証にも広げられそうです。

まとめ

Slay the Spire 2のゲーム状態をAIに渡し、攻略方針を提案してもらうアプリを作りました。

実装してみると、単にLLM APIを呼ぶだけではなく、以下の点が重要でした。

  • ゲーム状態をAIが理解しやすい形に整理する
  • 場面ごとにプロンプトを切り替える
  • 配信で使いやすい短い回答に整える
  • OBSや読み上げと連携する
  • 自動問い合わせと手動問い合わせの競合を制御する

ゲームAIというと自動操作のイメージがありますが、今回のように「一緒に考えるAI」として組み込むだけでも、かなり面白い体験になります。

今後も、ゲーム配信とAIを組み合わせた実験を続けていきたいです!

最後に

実際の動きを確認したい方は、Youtubeに動画投稿しておりますので、気になる方はこちらをご覧ください!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?