この記事で扱っていること
- 神経衰弱を作る方法
を紹介しています。
注意:すべてのエラーを確認しているわけではないので、記事の内容を実装する際には自己責任でお願いします。また、エラー配線は適当な部分があるので適宜修正してください。
トランプを使った遊びで、誰しも一度は神経衰弱をやったことがあると思います。
伏せられているトランプから二つ選び、それらの数字が同じであればそれらのトランプを手に入れることができ、再び選ぶ、選んだ二つが同じでなければ相手のターンになる、という操作を繰り返して、場のトランプ全てが無くなった時点で手に入れたトランプの多い人が勝ち、というルールになります。
ルールも単純なので、プログラムを組むときにも必要以上に難しくならないよう、今回はWhileループ一つで、なおかつ見た目にはステートマシンも使わず(考え方としてはステートマシンですが)イベントストラクチャのみでの実装としました。
なお、神経衰弱のルール自体はトランプである必要はないため、今回は単なる図形をマークに、色の違いでペアを作っていくようにしています。
どんな結果になるか
フロントパネルには、プレイヤーそれぞれの得点を示す数値表示器と、誰のターンかを示すブール、そしてトランプに見立てたピクチャ表示器が並んでいます。

プログラムを実行後、順にピクチャを2つ選択し、絵柄が揃ったら得点を得て自分のターンが続きます。
異なる絵柄のピクチャを選択した場合には相手にターンが移ります。
これを、全てのピクチャでペアを作れるまで続けます。

今回は「絵柄」としては単純に様々な色の丸で表現していますが、ピクチャ表示器に何を表すかは自由に決められるので、例えばこれを自分が持っている画像を表示させるように構成することもできます。
プログラムの構造
プログラムはイベントストラクチャが入ったWhileループだけで完結するようにしました。
イベントの数も2つしかなく、片方は途中でゲームを終わらせるための停止ボタンの値変更イベントなので、実質考えなくてはいけないのは、全てのピクチャ表示器に対するマウスダウンイベントです。

まず、イベントストラクチャのあるWhileループに入る前にはピクチャのリファレンスを配列にしています。
これはイベントの中で特定のピクチャの表示を消したりする(デフォルトに戻す)のに使用するためです。
ローカル変数でも代用できる操作ではありますが、リファレンスを使用することで、例えばピクチャの数を増やす場合でもリファレンスを増やすだけで対応できるので拡張性の面でリファレンスを採用しています。
また、0から19までの要素をもった配列をシャッフルしている部分がありますが、これはペアを作るのに関係しています。

ペアと判断させる仕組みについて説明するために、上記では0~19までの合計20の数字を使っていますが、簡単のために0~5の6個の数字を例にとります。
この0~5までの数字をシャッフルして、例えば数字の並びが[2,5,3,1,0,4]になったとします。(各ピクチャに対するラベルを数字にしているのはこのためです)
この並びに対して、最初から数えて2つずつをペアとみなします。
なので今回の例では2と5がペア、3と1がペア、0と4がペア、とみなすようにします。(当然ゲーム中はこれらがペアであることは表面的には見えていません)
そしてこれらペアを検索する処理として、「元の配列の中で該当する要素がある指標番号を検索し、これを2で割った余りが0ならその指標番号の一つ後に、余りが1なら一つ前の数字がペアの要素と判定する」ことを考えます。
例えば、あるターンでユーザーによって「3」のラベルがついたピクチャが選択されたとします。
この要素3の指標番号は元々の配列では2となっており、2で割った余りは0となるので、上のルールから、指標番号2の一つ後である指標番号3の要素、つまり1がペアだと判断できます。
別の例で、もしあるターンで「4」が選ばれた場合、この要素の指標番号は元々の配列で5となっていて、2で割った余りが1なので、一つ前の指標番号である4の要素、つまり0がペアだと判断できます。
この仕組みを作るために、Whileループに入る前にあらかじめ数字配列をシャッフルしてペアとなる要素を決めています。
Whileループの中に入り、各イベントの中身を紹介します。

各ピクチャに対するマウスダウンイベントの中は、プレイヤーが一つ目のピクチャを選んだか二つ目のピクチャを選んだかで場合分けをするためにケースストラクチャを用いています。
外側のケースストラクチャ(TrueかFalseで判断している部分)は、もし誤って既にペアが揃ったピクチャを選んでしまっても無効となるよう判断するために設けています。
外側のケースストラクチャのFalseケースの中ではまず、今誰のターンで1枚目を選ぶのか2枚目を選ぶのかといった判断をシフトレジスタで持っている列挙体から判断しています。
1枚目を選んだ場合(1st selectケース)、選んだピクチャ(のラベル)に対して上で説明したルールからペアになる数字をこの時点で判定し、次のループでその値を使用して、選んだピクチャと同じかを判定していきます。
また、ペアが揃わなかった時(2nd selectのケースの中にあるケースストラクチャでFalseの場合)には、すぐに次の人のターンになると選んだピクチャの「中身」が確認しづらくなるため、適当な時間(下記の図では2000ミリ秒)止まるようにしています。
なお、上から3番目の青いワイヤ(1st selectか2nd selectの列挙体)でインクリメントの関数を使用していますが、列挙体は内部では数字扱いなので、このように書くことで「1st select」→「2nd select」→「1st select」→・・・と繰り返させることができます。

時間制限を設ける場合
ただひたすらに「思い出す時間」を与えてしまうのではなく、時間制限を設けて、一定時間が過ぎると相手のターンに移ってしまうように組むこともできます。

今回は、時間経過は常に測定しておいて、プレイヤーがピクチャを選択したらその測定をリセットする、という仕組みをとりました。
時間測定には専用のWhileループを用意し、ピクチャが選択されるたびに測定をリセットするような信号をキューで渡しています。

イベントストラクチャ自身にもタイムアウトイベントを設けて、設定した時間(以下の図では5000ミリ秒)経過すると相手ターンに移ることを示すポップアップを表示します。

なるべく処理を増やさないようにしようとした結果、かえって複雑な形で時間測定のリセットを行うことになってしまいましたが、以下の図のように実装すれば時間測定およびリセットができます。

上記の例ではイベントストラクチャのタイムアウト値が定数になっていますが、例えばプレイヤーAには時間制限を設けるがBには設けない、とか、ゲームが進につ入れてタイムアウト時間を長く(あるいは短く)するように指定することもできるかと思います。
本記事では、LabVIEWで神経衰弱を作る方法を紹介しました。
ルールが単純でかつ素早さが勝敗を分けるタイプの処理でもないため、イベントストラクチャ一つで完結させましたが、ゲームの組み方として参考になればうれしいです。
ここまで読んでいただきありがとうございました。
コメント