見出し画像

Unityで「しちならべ」を作る(6)

こんにちは「つけらっとゲームス」プログラム担当のとちです。

情報系学科のある専門学校で、外部講師として「七並べ」のシステム設計を授業で扱ったこともあり解答例として設計書を作りながら、Unityで「しちならべ」を作ったお話です(前回分はコチラ ↓ )

今回は「戦術性のあるゲームを作る際、プログラムにプレイヤーの相手をさせようと考えているけど、どう作ればいいか?」という記事です。

ちなみに専門学校の外部講師としての記事はこんなのがあります。ご興味がございましたら以下もご覧くださいね。

前回は「トランプをどうやってシャッフルするか?」をお話しました。
今回は対戦相手である「Com1~3の思考ルーチン」を解決したいと思います。



七並べのルールを再確認

ここまでも何度か再確認していますがCom1~3の思考ルーチンを作るに当たって、もう一度大事な部分を思い出してみましょう。

んで、大事な部分とはどこか?
「同じマークで且つ7から連続して隣り合った数字の札を出せる」という点です。逆に言えば連続して隣り合っていない場合は出せないわけです。

これはプレイヤーの手番であっても同じなので、考え方を流用できます。

場の中央にある7から隣り合い、且つ連続した数字なら、その札は出せるので「7からAに向けて」と「7からKに向けて」のループ2つを、マーク数つまり4回まわしているプログラムとなります。

Unityで「しちならべ」を作る(4) から引用

上記が「プレイヤーの出せる札を判断するプログラムコード」の説明です。
同じことをすればCom1~3の手札から出せる(出せない)札を判断できますよね。

//─────────────────────────────────────────────────────
//		PcardSv		プレイヤーのデータ
//─────────────────────────────────────────────────────
public struct PcardSv										//
{															//
static public GameObject[] Pobj    = new GameObject[14];	//【変数定義】手札のゲームオブジェクト
static public int[]        PcdID   = new int[14];			//【変数定義】手札のカードID
static public int          Ppass   = 3;						//【変数定義】パス回数 [8]失格 [9]クリア
}															//
//─────────────────────────────────────────────────────
//		E1cardSv	対戦相手(Com1)のデータ
//─────────────────────────────────────────────────────
public struct E1cardSv										//
{															//
static public GameObject[] E1obj   = new GameObject[14];	//【変数定義】Com1 - 手札のゲームオブジェクト
static public int[]        E1cdID  = new int[14];			//【変数定義】Com1 - 手札のカードID
static public int          E1comID = 0;						//【変数定義】Com1 - Com1の個性
static public int          E1pass  = 3;						//【変数定義】Com1 - パス回数 [8]失格 [9]クリア
}															//
 
// この後、E2cardSv、E3cardSvと続く...

上記のコードはゲーム参加者、つまりプレイヤーとCom1~3の手札を管理しています。

【Unityで「しちならべ」を作る(4)】ではプレイヤー手札、つまりPcardSv.PcdID[]から出せる(出せない)札を判断しましたが、Com1手札から出せる(出せない)札を判断するならE1cardSv.E1cdID[]を見れば良いのです。


例外部分の考え方

出せる(出せない)札の判断はできましたが、七並べのルールはそれだけじゃありません。先程の「同じマークで且つ7から連続して隣り合った数字の札を出せる」の他にも例外的なルールがあります。

  • ジョーカーならどの場所にも出せる。

  • 手札から出せない場合はパスとなる。

  • パスは3回までOK

ですね…
そこで出せる手札がなければジョーカーを持っているか判断する必要があります。ここでジョーカーを持っていなければパスするしかありません。
(パス4回目でゲームオーバー、パスはできる限りしたくないですね)

ここでCom1~3の「行動の優先順位」を決めましょう。

  1. 出せる札があったら出す

  2. 出せる札がない場合はジョーカーを出す

  3. ジョーカーが無い場合はパスをする

図にするとこんな感じかな?

解答例「しちならべ」アプリの動作

解答例としてUnityで作った「しちならべ」ではどうなっているでしょうか?

前項の「行動1」で出せる札候補が複数ある場合はフレームカウントを14で割った余りを添え字(index)として、手札配列のindex枚目の手札を場に出しています。

手札配列のindex枚目が出せない札であれば、index+1し、indexが14を超えた場合はindexを0としています。

プレイヤー側から見るとフレームカウントなんて見えないわけですからランダムで選択されているように見えるでしょう。

ジョーカーとパスに対する考え方は前項の図と同じです!


COM1~3思考ルーチン強化案

前述の考え方を実装してテストプレイすると、最初のシャッフル時点で勝つのが難しい場合もあるのですが、Com1~3が思っているより強くて作り手であるわたしが真剣にプレイしても負けたりするんです。

当初はCom1~3をもっと強くしようと考えていたのですが、解答例として作った「しちならべ」では、ここまで書いてきた内容を実装したところで思考ルーチン完成としました。十分強いんですもの…

しかし、もっと強くするにはどうしたらいいでしょう?
七並べの戦術で「出せる札を敢えて止める」という戦い方があります。
以下のスクショをご覧ください。

あなたの手番です。
手札で出せるのはハート4、ダイヤ5、ダイヤ10です。
この状態だったら何を止めますか?

ハート4は手札にハート3があるので場に出しても良いでしょう。

ダイヤ5は手札にダイヤ3があり、ダイヤ4を持っていません。誰かに早くダイヤ4を出してほしいので早めに出した方が良いでしょう。

ダイヤ10より大きなダイヤ札は手札にありません。
ということは、ダイヤJQKを持っている人はダイヤ10が出るのを待っているハズです。意地悪な考え方ですが止めましょう!

こういった対戦相手がいるゲームでは、相手の嫌がることすると勝利に近づくものです。これをプログラムでやればいいのです。


止める札を判断する

では、プログラムで止める札を判断しましょう。
どうやって判断するのか、実は既に答えを書いています。

ダイヤ10より大きなダイヤ札は手札にありません。
ということは、ダイヤJQKを持っている人はダイヤ10が出るのを待っているハズです。意地悪な考え方ですが止めましょう!

これです。

手札を全件探索し、6以下の札であれば、その札より小さい札が他にあるなら優先的に出す。8以上の札であれば、その札より大きい札が他にあるなら優先的に出せばいいのです。

止める札は優先的に場に出されません。
ジョーカーを出さないといけないとか、パスするくらい追い詰められているなら出します。

フローチャートで表現するとこんな感じ

この考え方をどこに追加するのかというと…

「行動1」に挿入しましょう。
これでCom1~3は更に強くなるハズです!


おわりに

今回の記事を読むと、当たり前のことを書いているだけな気がします。
実際に友人たちと七並べをするとき、こんな考え方でゲームをしていると思います。

そうなんです、普段自分でゲームをしている段取りを順序良く文章化して、それをプログラムにやらせているだけで戦術性のあるゲームの対戦相手の動きを作れるんです。

このへんのお話はコチラの記事にもまとめていますので、より複雑な戦術性のある考え方を求めている方、ご興味のある方はご覧ください!

ちなみに専門学校の外部講師以外では、普段はこんなゲームをいじっている人です。もしよかったら以下の記事もご覧くださいませ~。

それではまた別の記事でお会いしましょう!

この記事が参加している募集

ゲームの作り方

この記事が気に入ったらサポートをしてみませんか?