たまには開発ブログみたいなことしてみる。
前提:対戦!連鎖パズル『パズトリ』
僕が作った落ち物パズルです。 AkashicEngine で作られており、ニコ生上で最大21人のオンライン対戦ができます。
で、オンライン対戦はいいのですが、1人で遊ぶときにも対戦相手がいないと困ります。そのため、このゲームでは対戦用のCPUプレイヤーを実装しています。
この記事は、パズトリのCPUプレイヤーがどういう仕組みなんだっけ?という記事です。
パズトリのCPUプレイヤーの仕様
パズトリのCPUプレイヤーはタイマン戦のみ実装しています。
CPUプレイヤーは難易度別に存在しており、「よわい」「ふつう」「つよい」「ヤババ」の4種類がいます。「ヤババ」は「つよい」を倒すと出てくるオマケモードです。
つまり4つのCPUルーチンが実装されている……というわけではなく、実はルーチン自体は1つしかありません。ルーチンは1つだけでパラメータ違いで4種類いるという仕組みになっています。
パズトリCPUのパラメータ
パズトリCPUには大きく分けて以下の4種類の設定があります。
- 目標連鎖数
- そのCPUが目指す連鎖数
- この連鎖数に至るまでは、なるべく連鎖を伸ばす
- 最大連鎖数
- そのCPUの指し手として採用可能な最大連鎖数
- この連鎖数を超える手はなるべく採用しないようにする
- が、どうにもならない場合は選択されることもある
- 操作にかかる時間
- ブロック落下操作開始までの待ち時間
- スワップ(ブロック入れ替え)をする場合は追加でどのくらい遅くするかなども設定する
- 指し手選択の失敗率
- 最終的な指し手選択をする際に選択を誤る確率(後述)
具体的なパラメータは以下のような感じになっています。
目標連鎖数 | 最大連鎖数 | 操作にかかる時間 | 指し手選択の失敗率 | |
---|---|---|---|---|
よわい | 1 | 3 | 60~120フレーム スワップ遅延:60フレーム |
50% |
ふつう | 3 | 5 | 45~90フレーム スワップ遅延:40フレーム |
10% |
つよい | 4 | 制限無し | 20~60フレーム スワップ遅延:20フレーム |
5% |
ヤババ | 5 | 制限無し | 0~40フレーム スワップ遅延:5フレーム |
0% |
こう見ると、ヤババはだいぶズルですね……最短0フレームって……
CPUルーチンの基本
基本的には「脳内で落下させてみて、その状態の良し悪しを判定し、一番良さげなやつを選ぶ」という仕組みです。普通だね。
パズトリのCPUルーチンでは、「確定指し手」と「暫定指し手」という2つの指し手を計算します。
- 一手目(ネクスト)を計算する
- この時点で最大連鎖制限を超える手は除外する
- 目標連鎖を超える OR 状況が危険な場合はこの時点での最終スコア判定をして、確定指し手一覧に登録
- そうでない場合は、2手目を計算する
- ここで最大連鎖制限を超える手は除外する
- 目標連鎖を超える OR 状況が危険な場合はこの時点での最終スコア判定をして、指し手に登録
- 未達&危険でない場合は、暫定指し手一覧に登録
- 指し手の選択
- 確定指し手がある場合は確定指し手の中から、ない場合は暫定指し手の中から一番良いものを選択する
- ただしCPUの選択ミス率が設定されている場合は、確率でテキトーに指し手を選択する
大きく分けてこの2ステップの処理が行われています。なお、実際の実装は処理負荷の関係もあり、もうちょっと細かくステップを分割しています。
CPUのスコア判定
先ほどのルーチンの中で「スコア判定」という言葉が出てきましたが、ここで言うスコアはゲーム中に表示されているスコアとは完全に別のものです。CPUのためだけに定義している内部的な値です。
具体的には以下のような値をもとに計算をしています。
- 連鎖数によるスコア
- 消せるブロック数によるスコア
- 連鎖とか色とか関係なく数だけ見る
- つまり、同時消しかどうかは見てない
- フィールドの形状によるスコア
- ど真ん中に積み重なったりしてると減点
- 2個以上つながってるブロックの数によるスコア
- たくさんあったほうが連鎖しやすい
- 次のブロックを置いたときに連鎖数が伸びるかによるスコア
- 実際のネクスト表示のブロックではなく、4色それぞれを調べる
- 実は5色目のピンクの飴を考慮してない
- 意図的ではなく、僕の実装ミス><;
- 実際のネクスト表示のブロックではなく、4色それぞれを調べる
指し手ごとにこれらの値を合算した評価用のスコアを計算し、良いものを選択しているわけですね。つながったブロックや、連鎖数が伸びることにスコアを与えているので、パズトリのCPUは基本的に連鎖をどんどん作ろうとする動きをします。
ここからわかるパズトリのCPU
以上がパズトリのCPUの仕組みです。ここから以下のような特徴がわかります。
相手のフィールドを一切見てない
パズトリのCPUのルーチンの中には相手のフィールドの概念がありません。そのため、いわゆる「潰し」みたいな駆け引きをする能力がないです。
同時消しと5色目が弱点
実装的に同時消しを考慮してブロックを配置していくことができません。
パズトリのスコア計算式は色数ボーナスが強いため、同時消しは非常に重要です。それが狙えないというこの部分は明確に人間より弱い部分になっているため、CPUに付け入るチャンスがあります。
また、実装上の不備が原因で5色目のピンクの飴のスコア評価がうまくできていません><;
なので2分以上経つとCPUは若干弱くなっていきます。
このあたりをうまく突くと、ヤババを倒せるかもですね!僕は倒せてないが。
「よわい」でもたまに強い場合がある()
ルーチン自体は一緒でパラメータ制限があるだけなので、場合によっては大連鎖が飛び出してしまう場合があります。特にパズトリはフィールドがそんなに広くないこともあり、どこ置いても連鎖になってくるような状態になると、大連鎖の手を選んでしまうケースがあります。
……許してね(てへぺろ)
以上
そんなわけでパズトリのCPUプレイヤーの中身についてでした。
落ち物パズルのCPUは昔書いたことがあり、そのときとあんまり変わらない非常に愚直な実装です。もっと頭良く書いてあげればいろいろなことできると思うけど、僕にそこまでのロジカルが無かった!!
また似たようなゲーム作る機会があったら、この経験を活かしてもうちょっと面白いCPUプレイヤーを作ってみたいですね。
おまけ:最強のCPUプレイヤー
パラメータを全部全開にしたデバッグ用のCPU、 [MAX] ルエルマ
というデータがあります。
- 目標連鎖数:10
- 最大連鎖数:制限無し
- 操作にかかる時間:0フレーム(スワップ遅延0フレーム)
- 指し手選択の失敗率:0%
つまり、このCPUプレイヤーの実装での限界の状態ですね。
なぜルエルマなのかというと、 #パズトリ にはCPUのデバッグ用にヤババの一個上の「MAX」というやつがおり、そいつの名前がルエルマだったからです。
— Ruたん (@ru_shalm) 2024年6月8日
(※CPU用の思考パラメータを全部MAXにしたやつ。ほぼ理論上最速で落とす) pic.twitter.com/W5u3MNm4Jg
これは普通にズルなのでゲーム内では戦えません。なんなんだこいつ!