
Unityで作ろう!ゲームアルゴリズム(2)
リバーシのアルゴリズム
皆さんはゲームのアイデアを考えるとき、どんな風にアイデアを出していますか?
筆者は斬新なアイデアをひねり出すのが苦手なほうで、考えて考えて考え抜いた挙句、しばしば他のゲームの二番煎じになってしまったりします。
ただ、二番煎じというのは結構重要なものでして、ルールが完成された既存のゲームに別のゲームを融合させるとプレイ感の全く異なる新しいゲームができ上がったりします。
そうは言っても、できれば今までに見たことの無いようなアイデアを出してみたいものです。
ちょっと前のゲームですが、個人的にはZen Boundなどは衝撃でした。
(色々なモノをロープで上手に縛るという謎のゲームです)
日本のゲームですと、塊魂なども当初は斬新でとっても好きでした。
さてさて、今回のゲームをご存じない方は恐らくほとんどいらっしゃらないでしょう。
リバーシのゲームアルゴリズムを作ってみることにします。
■リバーシって?
2人用の対戦ゲームで交互に自分の色の石を置き合い、相手の石を挟むことで裏返して自分の色にできるゲームです。
※別の呼び方に馴染みがある方も多いかと思いますが、本記事では商標の関係上リバーシで統一させていただきます。
リバーシはルールがとてもシンプルなので、アルゴリズム実装の練習にはうってつけです。
ちなみに筆者はおばあちゃんっ子で、昔よくリバーシで遊んだ記憶がよみがえってきます。
当時はあまりに負けすぎてリバーシが嫌いになりました。おばあちゃん、孫を相手に容赦なし。
■ルールをまとめてみよう
さて、実装のイメージがしやすくなりますので今回もルールをまとめてみましょう。
・縦横にマス目が並んでいる
今回は一般的な8x8にします。
・中央に2個ずつ白黒の石を置いた状態からスタート
実はリバーシの初期配置は厳密に決められていません。
今回はよく見る初期配置からスタートします。
・自分の石で相手の石を挟むとひっくり返せる
リバーシの一番のポイント。
一気にたくさんひっくり返せると気持ち良いです。
・相手の石がひっくり返せる場所にしか石は置けない
置けない場合はパスとなり、相手の順番に移ります。
・板面が全部埋まるか、両者とも置けるマスが無くなったら終了
それぞれの色の石を数えて勝敗を決めます。(言わずもがな、数の多いほうが勝ちです)
ちなみに、皆さんは白黒両者とも置けるマスが無くなったことってありますか?
リバーシは同じ盤を使ったゲームでもチェスや将棋と比べると格段にシンプルなルールですが、それでも何度も楽しめるのはスゴイことですね。
ここでちょっとひといき。
冒頭でも触れましたが、別のゲーム同士の合体は面白いものを生み出すことがあります。
タイミングの良いことに、つい最近リバーシにRPGを合体させたゲームを目にしました。
どんな形で合体しているかを軽く説明しますと、置く石がひとつひとつキャラになっていて、それぞれ特殊な能力(与えるダメージが多かったり、回復が出来たり、手元にある時のみBUFF効果があったり)を持っています。
ゲームを始める前にキャラ数十体でデッキを組んでおき、そこから手番になるたびにデッキから石をひとつ引いて、盤面に1つ置く、を繰り返します。
デッキから手札を引いてくる形なので、カードゲーム的な雰囲気ですね。
そして、仮に盤面上の自分の石の数が負けていても、敵のHPを0にしてしまえば勝ちとなります。
リバーシをベースにしたゲームであっても、味付けを変えるだけでプレイ感の全く異なるゲームになってしまった訳です。
(良し悪しは人それぞれですけどね)
■プログラムを見てみよう
では、リバーシのプログラムを見ていってみましょう。
今回はスクリプトの数が少し増えました。
・Game_SceneController.cs
ゲームの流れを司るクラスです。
後述のGame_Fieldに入れてしまうことも出来ますが、メンテナンス性と可読性を考えますとクラスは役割ごとに細分化していった方が後で幸せになれます。
(プログラムはちょっと長いので、Gistにアップしました)
https://gist.github.com/akako/541ac41428a037f6d7212e1be3df3f0f
・Game_Field.cs
盤面制御用のクラスで、盤面の管理と制御のみに特化させています。
今回のプログラムの中では一番コード量が多いのですが、役割が限定的なので中身は単純です。
https://gist.github.com/akako/98ba4ab4939c3d93db5d61080a0d512b
・Game_Cell.cs
こちらはマインスイーパのときと同じく、表示機能&入力機能に特化した
シンプルなクラスになっています。
https://gist.github.com/akako/d082e736416f50d9fc7586230d6464e5
・Game_Message.cs
ゲーム内でのメッセージを表示するためのクラスです。
Unityのコルーチンを上手く使えば「メッセージが閉じられたら次の処理を行う」といったことも簡単に実装できます。
中身は非常にシンプルですので、後述のサンプルプロジェクトにてご確認ください。
・Game_SoundManager.cs
音声ファイルを制御するクラス、と言うと仰々しいのですが、ただの音声リソース保持オブジェクトです。
利便性向上のため、どこからでもインスタンスにアクセス出来るようにしています。
こちらも後述のサンプルプロジェクトにてご確認ください。
■遊んでみよう
今回のプログラムのプロジェクトはこちらにアップしましたので、ダウンロードして遊んでみてください。
2次利用・改変等ご自由にどうぞ。
https://github.com/akako/gamealgorithm-reversi/releases/tag/for_algorithm2
[動画]
https://youtu.be/MH0ZtPDGXFY
マインスイーパの時は端折りましたが、音を入れるだけでグッとゲームっぽくなりました。
(動画には音声が含まれていないので、ぜひお手元で試してみてください)
■今回のポイント
出来るだけクラスを細かく分け、それぞれの中でやるべきことだけをやるようにすれば構造がシンプルになります。
今回は5つのクラスを使いましたが、それぞれ役割分担が明確で繋がりが緩いため、カスタムしやすいかと思います。
また、8方向へのチェック機能など、流用できそうなものはできるだけメソッドを細分化して、同じ処理を何度も書かずに済むように作りましょう。
ちなみに、今回は便利機能として置けるマスを赤枠で目立つよう表示していますが、置ける場所を探すのが好きな方もいらっしゃるかと思いますので、こちらの機能は一長一短ですね。
■次回予告 AI作るよ!
次回はプログラムに手を加えつつ、ちょっとしたAIを実装してコンピュータと対戦できるようにしてみましょう。
どうすれば強いAIが出来るかを考えてみると面白いですよ!
おまけ(リバーシのひみつ)
余談になりますが、リバーシは「二人零和有限確定完全情報ゲーム」に分類されますので、実は先手/後手のいずれかの勝ちが確定しています。
↑読み方はふたりれいわゆうげんかくていかんぜんじょうほうゲームで、要は打てる手が有限かつ運に左右されないゲームということです
ただし、あらゆるパターンの手を読み切るのはコンピュータの処理能力を持ってしても大変なため、まだどちらの勝ちが確定するかは見出せていないようです。
(盤面が6x6の小さいサイズですと、双方最善手を打った場合に後手が必ず勝つそうです)
もちろん、人間の能力だけで完全な先読みを行うのはまず不可能と言って良いので、普通に遊ぶ分にはどちらが勝つかは腕次第というわけです。
リバーシが楽しいのは、人間の処理能力が足りないお陰でもあるわけですね。
ちなみに筆者はいつも頭の中がパッパラパーで処理能力もへったくれもありませんが、割と幸せに暮らしています。