図書館防衛システム「Patch Controller」の試作①
この記事はニューノーマル ぴょこりんクラスタ Advent Calendar 2020のために書きました。
今日のテーマは『知的作業の自動化』です。もう少し絞るならマネジメントの自動化です。夢がありますね。管理対象の人形たちを上手に管理する夢のようなシステム、『Patch Controller』の現状と展望について今日は説明いたします。
対象となる知的作業
ぱちゅコン
遠い昔に発売された東方の二次創作*1同人TD(Tower Defence; Toshokan Defence)ゲームです。本を奪いにやってくる敵対人形たちから図書館の蔵書(20冊)を一定時間守りきるゲームです。 限られたお金で、こちらも戦わなければいけません。守るための兵力として、どの人形をどれだけ買うか、どの人形のレベルを上げるか、どこに移動させるかといったことをリアルタイムで考える必要のあるゲームです。
一方、ある程度マネージャが無能でも、各々の人形たちはそれぞれのポリシーに従って動いて成果を上げてくれるので安心です。好戦的で相性の悪い敵にも飛び込むような子もいるし、相性が良いはずなのに距離を保とうとする子もいます。かわいいですね。
ちなみに味方の人形は一定時間で復活します。最近の言葉でいうとリスポーンってやつですね(?
大まかな説明
自動化をするには①実行するアプリを起動し、②状況を理解し、③実行する必要がありますね。 大体以下のようなことをしました。
①実行するアプリを起動
これは簡単ですね。subprocess.Popenでおしまい。ちなみに今回はUbuntuでWindows向けのゲームを動かしてるのでWineを使ってます。Wineについて僕は上手に説明できませんが、"WINdows Emulator" の略だとか、"Wine Is Not an Emulator" の略だとか言われています。オタクはめんどくさいですね(????)。
②状況の理解
ディープラーニングで最強の状況理解(?)と行きたいとこですが、今回は簡単にスクショ撮影+テンプレートマッチングによる状況把握くらいにしておきましょう。
賢い人形マネジメント(?)まで出来ればいいんですが、今回はちゃんとゲームを起動して、メニュー画面で選択して、ゲームをプレイして、ゲームが終わったことに気づいたらまたゲームをして・・・みたいな一連の流れの自動化を対象とする、という感じです。面白みがなくてすまんな。
例えばゲームの窓上部、ゲームのタイトルなどが書いてあるところをテンプレートにして、対象となるゲームの窓の位置を特定したり、あとは勝利、敗北時にロゴが表示されるので、それらのロゴが表示されたのを終了判定に使ったり、みたいなことをします。
大体OpenCVとPIL、pyscreenshotあたりを使えばできるかと。OpenCVのテンプレートマッチングは簡単に使えてつよつよで良いです。
今回は時間がなかったのであくまでシーンの移動あたりをきちんと実装、戦略を持って人形を運用するところまで持ってけませんでした。そのあたりは乱数で頑張ってもらいます。現場が優秀なので大丈夫(??????)。
③実行する
クリックやキー入力ですね。pyautoguiを使います。ゲームを対象としたときだけちょっとだけ注意したいのが、クリックにpyautogui.click()、キー操作にpyautogui.press()を使うとゲーム側に拾ってもらえないことが多いということです。
なんか困ってる人多いらしく、加えて何やら小難しい議論をしている人たちもいます。
このあたりの記事に引っ張られて、結構諦めてる方が多いように見えるんですが、そういう話ではない気がするんですよね(そういう話もあるのかもしれませんが)。
ゲームにおけるキーやマウス操作の受け付けって、常時やってるわけではなく、定期的にキーやマウスが押されてるか確認しにいく形で実装されているんじゃないかと思います。なのでpyautogui.click()やpyautogui.press()だと一瞬すぎて検知されないのではないかと。というわけで
# これはキー操作の場合 pyautogui.keyDown(key) # 押さえて time.sleep(0.1) # 0.1秒待って pyautogui.keyUp(key) # 離す
みたいに押してる間の時間を加えてあげれば結構動くものも多いのではと。0.1秒、人間の押す時間にしてはちょっと長いくらいかもしれません。僕の場合はこれで動きました。(これに気が付かなかったらめげてこの企画お蔵入りしてました。)
demo
仲間たち
優秀な仲間たちを紹介します。
左から、中国、咲夜さん、パチュリーさん、おぜうさま、フランちゃんです。
- 中国:近接型の特攻隊長、復帰も早い主戦力です
- 咲夜さん:メイド長。弾幕型で復帰も早い主戦力その2です。
- パチュリーさん:飛行型ですが、得意な近接型は近接型をぶつけることが多いので影が薄い。
- おぜうさま:弾幕の飛距離がすごい。敵として来ると怖いけど味方だとどうもなかなか。
- フランちゃん:近接型単体の能力は高いが、値段も高いし復帰にも時間がかかる。一番かわいい(個人の感想です)。
プレイ画面の見方は大体こんな感じ。
動作について
起動→メニュー選択→ゲーム開始→ランダムな感じの操作→負けたので最初に戻ってもう一回プレイ
をひたすら繰り返す感じの実装をしています。1回負けてもう1勝負といったところで動画を終えています。
ランダム操作はランダムとはいえ、
- ①開始前にお金がなくなるまで最大10体人形を買う
- ②開始後、40回人形購入を試行する(お金がなくて買えないケースもカウント)
- ③ゲーム終了までランダムに人形のレベルアップを試行
②、③の間は各人形を中央から見て周囲のどこかにランダムで移動させています。ランダムに人形の部隊を選択して、x座標(中央、中央+150dot、中央-150dot)、y座標(中央、中央+150dot、中央-150dot)で、計9通りの場所にランダム移動させています。 ゲームとしてはマウスで領域選択して、その中の人形を全部移動、みたいなこともできるのですが、今回は簡単のため同一人形をまとめて同一箇所に移動する機能だけ実装しています。
蛇足ですがWine経由のアプリの音が録音できないので詳しい方教えてください(???)。なので動画は無音です。2倍速くらいで見るのがちょうどよいかと。ちなみにコンソールがすごい勢いで動いてるのは僕のすごい実装ではなくWineから吐き出されてるログです(映す意味ある?)。
最初と最後のpythonの実行と中断の操作以外、僕はマウス操作、キー操作しておりません。 こんな感じの雑な動きでも、まぁまぁ善戦してくれます。まだNormalモードすらクリアできませんけど・・・。
まとめと今後の展望
お約束事を守りつつ、現場はよくわからないので能力に応じた適切なリソース配分なんてできないJTCマネジメントしぐさと、それによって疲弊する現場が再現できたのではないでしょうか。
キー、マウス操作がちゃんと動くところに持ってくのに時間がかかってしまったのが反省点ですね。
さて、現状ノーマルすらクリアできないのは(実はこんなクソ雑実装でもイージーはクリアできたのです)、人形を動かすオペレーションの問題より、むしろリソースのアサインが致命的であると考えています。
今回はランダムに5種類全員使っていますが、基本的には2〜3種類を使うのが正攻法です(全部使うとレベルアップ等の効率が悪いので)。近接型は少し多めにしてあげるとか、そのあたりをきちんとやると安定すると考えられます。実は現行のクソザコロジックでも、使用する人形を中国、咲夜さん、フランちゃんに絞るだけで時々ノーマルモードクリアしてくれます。
このあたりをルールベースで詰めても面白くないので、強化学習っぽい感じで上手に学習できたら面白いかなと思います。そこが上手にできた上で人形たちの移動のオペレーションにも持っていけると良いかなと。
人形を動かすオペレーションの課題は人形間の相性で、ここまで言及してなかったのですが、人形には近接型、弾幕型、飛行型の3タイプがあり、じゃんけんのような関係になっています。今回の動画の直接的な敗因になったであろう、10:14あたりから右上に現れたボス(弾幕型の藍しゃま、でかくて黄色い髪)に加え、更にその後ろから飛行型のパチュリーさん(味方ではない)が来たやつ、これはやばかったですね。弾幕型は近接型に弱いので近接型で速攻でボコらなきゃ行けないのですが、近接型が近くにおらず初動が遅れ、追いついた飛行型(近接型に強い)のパチュリーさんの後方からの援護射撃で中国が壊滅しています。こちらの弾幕型の咲夜さんなんかも善戦して、なんとかパチュリーを倒したんですがその後やってきた近接型の妖夢(灰色の髪)にボコボコに駆逐されてますね。このタイミングでもっと中国やフランちゃんが残って壁になってくれればまだ戦えた・・・。こうしてリスポーンも追いつかずどうにもならなくなると、徐々に徐々に本は奪われ、リスキルされ、終わりを迎えるのです。もうどうにもならない、取り返しのつかない人生みたいですね(?)。
これを避けるためには『とにかく近接型をいち早くボスにぶつけて瞬殺する』『周囲を弾幕型で援護射撃、パチュリーを駆逐する』みたいなことをしなければなりませんでした。こういった相性に応じたオペレーションもゆるーく実現できると良いですね。
というわけでぱちゅコンを自動で操作するPatch Controllerを実装してみました。続く(のか?)