「AI駆動」という考え方がおもしろかったので、AIに処理を完全に任せてボードゲームを作って遊んでみた。
AI駆動
AI駆動型のシステムとは、AIにシステムの制御を任せることで、柔軟で効率的なアプリ開発を実現する新しいアーキテクチャ。
代表的なのがMVAアーキテクチャで、MVCのコントローラの部分をAIに任せてしまうことで、開発が楽になる上、ユーザーから想定外の入力があっても柔軟に対応できるのが利点。
今回は若干AI駆動とは異なるかもだけど、AIを制御の中心に添えて、何でもできるボードゲームマスターを作ってみた。
構築
全体イメージは以下の通り。黄色いノードがAIに処理を任せている箇所なので、ほぼすべてのゲーム処理をAIに任せてみた。


今回プロンプトを練る時間があまりなかったので、LLMにはo1を使用。
GPT4oだとうまく動作しなかったけど、プロンプトをもっときちんと考えれば4oでも動くかも。
※特に判定処理がいまいちでループすることも有効な手を無効と判断することも多かった
手順1:ゲーム名の取得
まずはユーザーからゲーム名を取得する。


「ゲームしようぜ」をトリガーに、ユーザーにゲーム名を質問。応答全体を変数に入れる。


そのユーザーの質問の中からボードゲームの名前をプロンプトアクションで抽出。知らないボードゲーム名の場合や、ボードゲーム名が含まれない場合はこの時点で終了。


プロンプトはこんな感じ。
※ここは難しいタスクではないので4o-miniで。

※ここは難しいタスクではないので4o-miniで。

手順2:先手の確認
続いて先手を確認する。


選択式の質問で手番を聞いて、
※1対1のボードゲームのみ想定

※1対1のボードゲームのみ想定

変数「手番(turn)」を設定。


手順3:駒の定義、ボードゲームの初期状態生成、初期盤面描画
続いてボードゲームの初期状態の作成から、初期盤面の描画まで実施する。


まずは「ゲーム名」と「手番」から、駒の色やその所有者を、定義する。




あたなはボードゲーム「 game_name 」のゲームマスターです。 プレイヤー「 user 」「 AI 」が game_name を開始します。 それぞれのプレイヤーの駒の種類(色など)を定義してください。 先手は「 turn 」です。 # example 1 ## input ### ゲーム : オセロ ### プレイヤー : User, AI ### 先手 : User ## output [{"player":"User", "piece":"黒"}, {"player":"AI", "piece":"白"}] # example 2 ## input ### ゲーム : チェス ### プレイヤー : User, AI ### 先手 : AI ## output [{"player":"User", "piece":"白"}, {"player":"AI", "piece":"黒"}]
続いて、「ゲーム名」「駒の所有者」「手番」から、ボードゲームの初期状態をJSONで生成。




以下の条件で、ボードゲーム「 game_name 」の盤面の状況を、指定のJSONスキーマで出力して。 # 条件 ## 1. プレイヤーは「 user 」または「 AI 」とし、先手は「 first_player 」とする ## 2. 各プレイヤーの駒の種類は「 piece_owner 」の通りとする ## 3. 「オセロ」などボードのサイズが決まっていないボードゲームの場合、5分ほどで終わるボードのサイズにすること # JSON "board": { "height": int, // ボードのサイズ、[横, 縦](例:チェスは[8, 8]) "width": int, "grid": [ // ボードの状態を表現するグリッド { "position": "string", // ボード上の位置(例:チェスの「e2」、オセロの「d4」など) "piece": { // 駒の情報(駒がある場合のみ) "owner": "string", // 駒の所有者( user or AI ) "type": "string" // 駒の種類(例:「黒石」、「白石」など) } } ] }
最後に生成した初期状態を変数に保存し、その変数の値をもとに盤面を描画(HTMLで生成)させる。




描画した盤面は「メッセージの送信」でそのままユーザーに送信する。


手順4:ユーザーまたはAIが手を打つ(駒を進める)
いよいよ駒を動かしていく。


手番がユーザーのときは、単純にどんな手を打つか質問するだけ。


手番がAIのときは、「ゲーム名」「現在の盤面」「駒の所有情報」をもとに、次の一手を生成させる。




手順5:打った手をチェックする
ユーザーまたはAIが手を打ったら、その手が有効か無効か、また勝敗が決まったか決まっていないかを確認する。


「ボードゲーム名」「打った一手」「現在の盤面」「駒の所有者」をもとに、有効 or 無効(無効の場合は理由)、勝敗決定 or 未決定を生成。
※この判定が難しいらしく、4oでは全くうまくいかなかった。。。

※この判定が難しいらしく、4oでは全くうまくいかなかった。。。

あなたはボードゲーム「 game_name 」の審判です。 以下のJSONであらわされる盤面において、プレイヤー「 turn 」が一手を打ちました。 この一手が「有効か無効か」を判定してください。 また、この一手により「勝敗が決定したか」も併せて判定してください。 # プレイヤーがプレイ中のボードゲーム game_name # 各プレイヤーが使う駒の種類 piece_owner # 現在の盤面 board # 現在の盤面に対する、プレイヤー「 turn 」の手 move # output isValidMove : その一手が有効(true)か、無効(false)か isDecisiveMove : その一手で勝敗が決したか(true)、否か(false) reason : 有効でない場合の理由を日本語で表記
無効の場合はGo toで「現時点の盤面の描画」まで戻し、再度手を考えさせる。


手順6:勝敗の確認
先ほどの判定で、勝敗が決定しているかも確認しているので、それに合わせて分岐する。


勝敗が決まった場合は、勝者をユーザーに送信して終了。


手順7:盤面を進める
勝敗が決していないときは一手の情報をもとに盤面を進め、手番を入れ替え、盤面の描画まで戻る。


勝敗が決まっていない場合は、「ゲーム名」「現在の盤面」「駒の所有者」「手を打ったプレイヤー(ユーザーorAI)」「一手の情報」をもとに、手の通りに駒を動かした後の盤面情報を生成させる。
※ここも4oだとうまく動かないことが多かった。。


※ここも4oだとうまく動かないことが多かった。。


生成した盤面を変数に入れ、手番を入れ替え、Gotoで盤面の描画まで戻る。


以上で構築は完了。
動作確認
オセロ
まずはオセロ。こんな感じで盤面を作ってくれて、


駒を置くと、盤面が進む。


AIも手をきちんと考えてくれるので、普通に遊べる。


ちなみに角を普通にとらせてくれるので、レベルはそんなに高くないかも。


チェス
チェスも(若干見にくいけど)きちんと盤面を作ってくれる。


駒も普通に動かせて、(駒の上下は入れ替わっちゃったけど盤面は間違ってない)


AIも駒を動かしてくる。


取られるところに駒を動かすと、


普通にとってくる。


ということで、こちらも遊べそう。
チェッカー
AIのすごいところは、構築者がルールを知らないゲームも遊べること。チェッカーを要求すると、盤面を作ってくれる。


すごい!と思ってたら、残念ながら駒を動かすと盤面が崩れてしまう。。


ということで、限界はあるみたいだけど、ほぼプログラムなしで色々なゲームを作れるのはすごい。
コメント