Unityで作ろう!ゲームアルゴリズム(3)リバーシのAIを作ってみよう
skill

Unityで作ろう!ゲームアルゴリズム(3)
リバーシのAIを作ってみよう

2016.12.12

筆者はずっとインドア派(というかゲーマー)だったのですが、最近は外出して体を動かすことにハマっています。
お散歩にジョギング、立ち寄った公園でお花の写真を撮るなど、楽しみ方はいろいろ。

ちょっと歩くだけで、脳をビビっと刺激する変わった人や妙なモノに出会ったりするものです。
アイデアが煮詰まったなら、ぜひ気晴らしに散歩に出てみましょう!

さて、前回はリバーシのアルゴリズムを作りました。
今回はリバーシの対戦相手となるAIを作ってみましょう。

賀好 昭仁

AIとはなんぞや

まずは用語の説明から入りましょう。
AIとは、Artificial Intelligence(人工知能)のことです。

世の中には様々なAIが溢れています。
そして、AIのほとんどは何らかの目的を達成するために作られています。
例えば、工業用の機械を制御して製品を作るための制御AIや、部屋中をくまなく掃除するための掃除機AIなど、その用途専用に最適化されたAIが沢山存在しています。
本記事で作成するAIも「リバーシの対戦相手を務める」という目的があります。

一方で、最近ディープラーニングと呼ばれる手法を利用した新しいタイプのAIが登場し始めています。

ディープラーニングとは、機械学習の手法のひとつです。
ざっくり説明しますと、まず「ニューラルネットワーク」という、人間の脳の仕組みを模した機能を備えるAIを準備します。
このAIにデータを与えると、AIはデータの特徴を分析し、学習していきます。
十分に学習が進むと、それまでの学習を元にして、与えられた情報がどのようなものであるかを判断することが出来るようになります。

ディープラーニングで出来上がったAIの例を挙げてみますと、2016年3月、Googleが「ネコを認識するAI」が出来たと発表し、話題となりました。

このAIがなぜスゴイかと言いますと、「人間がAIにネコとはどのようなものであるかを教えた」わけではなく、AIにYouTubeから取り出した1,000万枚の画像を与えてディープラーニングを進めた結果、「AIがネコの特徴を覚えた(ネコを判別させたかった訳ではないのに、勝手にネコを判別できるようになった)」という点です。

これは驚くべきことで、AIが置かれた状況に応じて臨機応変に(それこそ、まるで生き物のように)成長していける可能性を示唆しています。
いずれは「自ら言葉を覚え、人と自在に会話できるAI」なども誕生することでしょう。


いやはや、思い切り脱線してしまいました。

ディープラーニング用AIのプログラミングも記事にしたいところですが、筆者自身まだまだ理解が足りていませんので、いずれ機会があればということで。(笑

どんなAIをつくる?

さて、本題に戻りましょう。

今回作成するAIは「リバーシができるAI」です。
一言で「リバーシができるAI」と言っても、実装の方向性はいくつか考えられます。

1.ゲームの展開を予測するAI
今後のゲームの展開を予測し、最善と思われる手を打つAI

2.学習型のAI
どういった手を打った結果どのような成果が得られたかを逐次収集し、どんどん強くなっていくAI

3.セオリーに従うAI
リバーシをプレイする上で「有利になる条件」「不利になる条件」を定義し、それに応じてプレイを進めるAI

前回少し説明しましたが、リバーシの場合は打てる手が限られています。
ロジックが完璧に実装出来たとすると、1.のパターンが最強です。
AIに手を完全に予測されてしまうと、どう足掻いても勝ち目はありません。
その代わり、手を予測するために凄まじい処理能力が必要となります。

2.は対戦する度に強くなっていくAIで、実装するのがとても面白そうです。
ただ、仕組みがかなり複雑になってしまいます。

今回は一番シンプルな3.のパターンで実装を進めてみましょう。
(部分的に1.のパターンも使用します)

リバーシのAIに必要なインターフェース

リバーシのAIが必要とする情報と、情報を与えられた時にどのようなレスポンスを返せばよいかを考えてみましょう。

まず、AIが次の手を打つために必要な最低限の情報は
・自分の石の色
・現在の盤面の状況
です。
これらの情報から現在の状況がわかれば、次にどのような手を打てばよいかが計算出来るというわけです。

情報を受け取ったのち、AIが返すべきレスポンスは「次の手」です。
リバーシにおける「次の手」とは「どのマスに石を置くか」ということですので、マスの座標を返せばOKです。

ランダムに石を置くAIを作ってみる

まずは適当なAIを作ってみましょう。
石が置けるマスからランダムで1マス選ぶAIです。

Game_AI_Base.cs
AIに必要な処理をまとめた基底クラスです。
盤面シミュレータのサブクラスを同梱し、簡単に盤面のシミュレーションが出来るようにしています。
AIはこのクラスを継承し、フィールド情報を受け取って次の手を返すGetNextMove()メソッドを実装すればOKです。
https://github.com/akako/gamealgorithm-reversi/blob/master/Assets/Scenes/Game/Scripts/AI/Game_AI_Base.cs


Game_AI_Random.cs
ランダムに石を置くAIです。
盤面シミュレータから石を置けるマスを取得し、その中からランダムで1つ選んで返すだけの処理となっています。
https://github.com/akako/gamealgorithm-reversi/blob/master/Assets/Scenes/Game/Scripts/AI/Game_AI_Random.cs

AIを組み込んでみる

以下にAIを組み込んだプロジェクトを準備しましたので、試しにプレイしてみてください。
https://github.com/akako/gamealgorithm-reversi/releases/tag/for_algorithm3

今回のAIはシンプルで組み込みはとても簡単ですので、組み込みに関する解説は割愛させていただきます。
(Game_SceneController.cs・Game_Field.cs・Game_Cell.cs スクリプトの前回との差分をご確認ください)

ちゃんと動くAIを作ってみる

Game_AI_RandomのAIと対戦してみると、ランダムに石を置くだけではとっても弱いことがお判りいただけるかと思います。
次はリバーシのセオリーに沿って次の手を打つAIを作ってみましょう。

まずはセオリーを書き出してみます。
Google先生にセオリーを教えてもらい、実装しやすそうなものをいくつかチョイスしました。

・角を取る
・角の斜め隣は出来るだけ打たない
・序盤は少なく取る
・取った石が相手の石に囲まれている場所を狙う(「中割り」と呼ぶそうです)
・終盤は石をたくさん返せる場所を狙う

余談ですが、筆者は今回の調査で「中割り」を初めて知りました。

セオリーの重み付けをしてみる

盤面の状況は様々で一概には判断出来ないため、「どの状況がどの程度重要か」をAIに教えてあげます。

・角を取る
「50ポイント」の重要度

・終盤までは角の斜め隣は出来るだけ打たない
盤面の3分の2が埋まるまでは、該当マスは「-30ポイント」の重要度

・序盤は少なく取る
盤面の3分の1が埋まるまでは、「取れる石の数 ✕ -10ポイント」の重要度

・取った石が相手の石に囲まれている場所を狙う(「中割り」と呼ぶそうです)
「取った石の周囲にある相手の石の数 ✕ 2ポイント」の重要度

・終盤は石をたくさん返せる場所を狙う
盤面の3分の2が埋まっていれば、「返した石の数 ✕ 5ポイント」の重要度

上記の計算を実装し、どの手を打てば良いかを判断出来るようにしてみます。
(なお、各値は筆者の感覚で適当に設定しています

Game_AI_Theory.cs
前述の処理を実装したAIです。
石を置けるマスのポイントを計算し、ポイントが一番高いマスを返すというわかりやすい処理になっています。
https://github.com/akako/gamealgorithm-reversi/blob/master/Assets/Scenes/Game/Scripts/AI/Game_AI_Theory.cs


こちらのAIも前述の
https://github.com/akako/gamealgorithm-reversi/releases/tag/for_algorithm3
に同梱しており、Game_SceneController.cs 63〜64行目のコメントを付け外しして

  //ais.Add(Game_Field.StoneColor.Black, new Game_AI_Random(Game_Field.StoneColor.Black));
  ais.Add(Game_Field.StoneColor.White, new Game_AI_Theory(Game_Field.StoneColor.White));

にすれば、Game_AI_Theoryと対戦出来るようになります。
ちなみに、両方の行のコメントアウトを外せばGame_AI_RandomとGame_AI_Theoryの対戦を見ることも出来ますよ!

(オマケ)AIに性格を付けてみる

AIにも個性があった方が、より一層ゲームが盛り上がります。
例えば、

・調子に乗るAI
盤面に自分の石が多いと調子に乗って適当に打つようになるAI

・欲に目がくらんでしまうAI
3つ以上石をひっくり返せるならば、それがどんな酷い手であっても打ってしまうAI

・スロースターターなAI
序盤は適当に打つが、終盤になると急に強くなるAI

などです。
リバーシのAIであれば、上記のいずれもGame_AI_Theoryを少しカスタムするだけで作れるかと思います。

ゲームに登場するキャラクターの性格を考えて、それに相応しいAIを作ってみると良いかもしれません。

まとめ

ディープラーニングからAIの性格まで、ずいぶん話が広がってしまいました。

ゲームにおいてAIはゲームバランスに直結するため、プログラマとしては腕の見せどころです。
強すぎず弱すぎず、プレイヤーが「心地よい」と思えるような対戦相手を作ることを目指しましょう。(激ムズゲームも需要はありますけどね)

また、複雑で面白いAIが作れるならば、それ自体がゲームになることもあります。
少し昔のゲームですが、シーマンやワンダープロジェクトJなどは高度なAIが主役の興味深いゲームでした。

応用の幅は無限大ですので、本格的にAIに関して勉強してみるのも楽しそうですね。

次回予告

マインスイーパ→リバーシと盤面を使ったゲームが続きましたので、次回は少し趣を変えて「ゲームにおける自動生成のアルゴリズム」に関して学んでいこうと思います!

原稿: 賀好 昭仁
qnoteスマホアプリ開発チーム技術主任。PHP・Android・iOS・Unityなど複数のプラットフォームでの開発を行う。
しばしば7匹の先輩猫社員たちにイスを占領される。

この記事はどうでしたか?

おすすめの記事

キャリアを考える

BACK TO TOP ∧

FOLLOW