報道を自動化するエンジニアはゲーム自動化の夢を見るか

Pythonエンジニアの @kimihiro_n です。 今回は先日行った社内勉強会の話を。

社内勉強会

弊社では月1回、社内の開発者で勉強会を行っています。 内容はLT大会だったり、もくもく会だったり、ハンズオンだったりと幹事の人が好きにテーマを設定して実施しています。 おすすめの本を持ち寄ってビブリオバトル をやった時もありました。

今回、久しぶりに自分の担当が回ってきたわけですが、「AI同士の対戦」みたいなのやってみたいなーと前から思ってました。 AIというと大げさですが、各自プログラムしたゲームのCOM(CPUともいう)を持ち寄って、誰が一番強いのかを決めるみたいな内容です。 ニュースや報道の自動化を進めている弊社のエンジニアだったらゲームの自動操縦だってお手の物のはず…!

COM VS COM で一番強いチームを決める

実際にどうやってプログラム同士を戦わせるかですが、頭に浮かんだのは昔あった「カルネージハート」というゲームです。 アルゴリズムを組み込んだロボット同士を3on3で戦わせて遊ぶゲームなのですが、これがよく出来ていて一時期PSP版にハマっていました。 コーディングはテキストではなくてGUIのパネルみたいなのを並べて作るのですが、条件分岐やループ、関数的な別モジュールの利用といったようにかなり高度なことまで実装できます。 なのでカルネージハートとPSPを人数分用意して…と言いたいところですが、無理だったので代替案を考えることにしました。

ゲームを作る

Web 上でそういったプログラム同士の対戦をするサイト、どこかで見かけた覚えがあったので当初それを掘り起こして使おうと思ってました。 しかしサイト自体が閉鎖してしまったのか検索が甘かったのか、望みのものが見つかりませんでした…。 こうなったら自作するしか…ということで1人ハッカソンを始めました。

作りたいゲーム

  • 操作が単純である
  • ルールも単純である
  • 言語に不慣れなエンジニアでも楽しめる
  • 運要素が少ない(頑張ればその分勝ちやすい)
  • 2人1チームでも協力できる

ぱっと浮かんだ要件は上記のような感じでした。 勉強会の枠は2時間なので、その中で準備・実装・試合をこなすにはそれなりにシンプルであることが重要です。 また開発者といっても「サーバーサイドエンジニア」「アプリエンジニア」、「MLエンジニア」のように専門がそれぞれ異なります。 普段その言語を書いているエンジニアが強くて、他のエンジニアは動かすので精一杯みたいなのだと面白みにかけてしまいます。 なので基本文法を抑えていれば楽しめるようなゲームが望ましいです。 あとはプログラムを改善した分だけ強くなれる性質があったらなー、とか2人で分担や相談できたらなーみたいなことを漠然と思っていました。

Pong ゲーム

f:id:nsmr_jx:20190322171713p:plain
Pong

いろいろ考えた末思い浮かんだのが Pong ゲームでした。 操作が上か下かの2択でシンプル。ルールもボールを跳ね返して相手のゴールに入れるだけで単純です。 また、複数バーを用意することでチームっぽさも出すことができます。 ボールの動きが単純なので最終的な移動地点を予測してしまえば終わってしまう欠点はあるのですが、勉強会の短い時間であればちょうどいい難易度かなというのもポイントです。

Pyxel で作る Pong ゲーム

作るものが決まったので早速実装です。 当初みんな馴染みが多いだろうと Javascript で実装する気満々だったのですが、事前アンケートを取ってみたら Python のほうが慣れてる人多くて Python で作ることにしました。

github.com

ちょうど Python で使ってみたかった Pyxel(ピクセル) というゲームエンジンがあったのでこれ幸いと利用してみることに。

サンプルにあるように

import pyxel

pyxel.init(160, 120)

def update():
    if pyxel.btnp(pyxel.KEY_Q):
        pyxel.quit()

def draw():
    pyxel.cls(0)
    pyxel.rect(10, 10, 20, 20, 11)

pyxel.run(update, draw)

Pyxel 初めて触ったゲームエンジンですが、updateで毎フレームの内部状態を更新して、drawでレンダリングしてあげれば利用できるというシンプルな仕組みでとても書きやすかったです。 ドット絵を描くエディタやサウンド編集ツールなんかもついていてかなり凝ったゲームも作れそうです。今回は時間なくてシンプルなドットを描画するのみにとどまりましたがいつかちゃんとしたゲーム作りもチャレンジしたいです。

github.com

で、なんとか出来た対戦ゲームがこちら。 当たり判定に若干怪しいところとかがありますが、大きな理不尽なく遊べるくらいにはなりました。 コマンドラインの引数でチームのプログラムへのモジュールパスを受け取って対戦が可能になっています。

    def atk_action(self, info: GameInfo, state: State) -> int:
        return random.randint(-2, 2)

    def def_action(self, info: GameInfo, state: State) -> int:
        return random.randint(-1, 1)

各自に実装してもらうものも極力シンプルにしていて、毎フレームごとに呼び出される関数が何を返すかで前衛、後衛が上下に移動する仕組みになっています。 Python 不慣れでも苦なく動かせるのではないでしょうか。

pip で配布

Python で作ったゲーム、どうやって配布しようと思っていたのですが、pip で配布してしまえばいいのではという事に気づいてしまったので pongpy という名前で登録しました。 PC ゲームつくるならこの配布方式強いですね。アプリ化とか考えると Python では鬼門ですが…。

勉強会当日

チームビルディング

事前告知してインストールに支障がないかとかを見てもらいつつ、勉強会を迎えました。 最初にペア or ソロ参戦かでチームを作ってもらい、1時間強ほど実装を進めてもらいました。

f:id:nsmr_jx:20190322174456j:plain
作業風景
前衛と後衛で分担して実装をすすめてるチームが多かったですね。 後衛のほうが幅が広くボールがくるまで時間があるので、こっちを強化すると格段に勝ちやすくなります。

また1セットごとに左右が入れ替わって戦う仕組みをいれてあるのですが、ここへの対応をちゃんと入れないと前衛が自チーム側にボールを返して自爆してしまうみたいな罠があります。 実装の後回しになってしまいやすい部分ですがちゃんと考慮してくれたチームがいくつかあって開発者冥利に尽きました。

トーナメント

f:id:nsmr_jx:20190322173941p:plain
トーナメント

実装が出揃ったらいよいよトーナメント戦です。 GitLab にレポジトリを作って、マージリクエストという形でソースコードを出してもらいました。

f:id:nsmr_jx:20190322181628p:plain
観戦の様子
AirMac で画面をミラーリングすると Pyxel がエラーを吐いてしまうなどのトラブルがありましたが、1試合1分ほどで決着がつくので始まってからはサクサクと進みました。 やはり対戦状況が画面で見れるっていうのは楽しいですね。予想以上に盛り上がってよかったです。 (非エンジニアでも見て楽しめるので全社で観戦者募っても良かったかもしれない…。)

f:id:nsmr_jx:20190320200647g:plain
白熱の決勝戦
そして決勝戦です。かなり接戦でいい勝負していました。 前衛の青に当たると上下への振れ幅を大きく返せるので決め手になりやすいです。

f:id:nsmr_jx:20190322100102j:plain
優勝チーム
見事優勝した sugibayashi チームです👏 副賞として Pong にちなんだ ポンジュースがプレゼントされましました。

f:id:nsmr_jx:20190322155112g:plain
参考実装
ちなみに参考実装として用意していたボールの予測を実装したチーム同士の戦いです。 このチームに勝ってくれるのを密かに期待してましたが流石に1時間だと厳しかったみたいで…。 1日単位でハッカソンみたいな機会があったらまたぜひやってみたいですね。 DQNとかの機械学習を持ち出してくるチームもあると思いますし。