ライツアウトを作る | マーブルルール

ライツアウトを作る

LabVIEW Games

スポンサーリンク

この記事で扱っていること

  • ライツアウトを作る方法

を紹介しています。

小学生だったころに、タカラ社(現タカラトミー社)から、ライツアウトというゲームが出ていてよく遊んでいました。

ふとしたときに、それが懐かしくなり(自分の年がばれますが)、LabVIEWで表現できないかと思って作ったのが今回の記事です。

ゲームとしては、5×5マスのボタンがあり、それぞれが「赤」「緑」「無(消灯)」のいずれかになっていて、最終的に全てのボタンを「無」の状態にすればクリア、という単純なものです。

ルールはシンプルで、

  • ・プレイヤーがあるボタンを押すと、そのボタンの上下左右にボタンが存在していた場合、押したボタン含めそれぞれのボタンが、現在の色を基に規則に沿って色が変化する
  • ・色が変化する規則は、「赤」→「緑」→「無」→「赤」→・・・を繰り返す

というものになります。

より単純なルールの「赤」→「無」→「赤」→・・・といった、2色しかないものもあるようですが、これが3色になると少しだけ難しくなる、といった感じで楽しめます。

本記事では、このブログでは珍しくダウンロードできるファイル(ライツアウトの問題)も用意しているので、ぜひ実際にプログラムを作ってゲームで遊んでみてください。

スポンサーリンク

どんな結果になるか

フロントパネルには2Dピクチャの2次元配列と、問題をやり直すためのボタン、そして終了ボタンがあります。

プログラムを実行すると、画面に問題が出ます。

ゴールとしては、盤面すべてを無色(パネルは無色にできないので実際には白色)にすることです。

あるパネルをクリックすると、クリックした部分とその上下左右の色が変化します。

この操作を繰り返すことで、全体が無色になることを目指します。

プログラムの構造

ユーザーからの入力に都度反応して再びユーザーからの入力を待つ、という単純な動作をするだけなので、この手のゲームは例によってステートマシンで実装できます。

常に表示させておくものとしてはピクチャ配列があり、これはステートマシンのケースストラクチャの外に配置しています。

ステートマシンの各ステートで使用するデータはクラスタとしてまとめています。

クラスタの要素は、下の図のWhileループの左側にあるクラスタを参考にしてみてください。

まずはinitステートです。

フロントパネルを初期化するのに使用しています。

記事後半で紹介するような、ステージを選べるような仕様にするのに備えて、次のinit gameと分けたケースとしました。

次にinit gameです。

ここで、「問題」を作ります。

問題を構成する際に使用するboard statusは数値配列であり、この数値によって盤面が無なのか赤なのか緑なのかを判別します。

問題はset board status.viとupdate board picture.viの二つのサブVIによって表現します。

サブVIの中身について、まずはset board status.viを紹介します。

選ばれたセルに対する2次元配列のboard statusの値を1増やします。

ただし、色の種類は3つなので、board statusの2次元配列の要素も0か1か2のいずれかしかとらないようにするために、3で割った余りを使用します。

次にupdate board picture.viです。

各board statusの配列要素の値を基に、board picture(これも2次元配列)の各要素の色を変えていきます。

Draw Rectangle.viに与えている長方形の大きさは適宜調整してください。

メインのステートマシンに戻り、次はeventステートです。

ユーザーからの入力を待ちます。

ただし、いつでも停止ボタンを押せばプログラムが止まるように、敢えてタイムアウトイベントを設けていますが、この中では特に何もしません。

他のイベントケースの中身は以下の通りです。

ピクチャの配列のマウスダウンイベントではマウスが押された座標を取得できるので、これをX、Y座標とも「ピクチャのサイズ」で割り算し、この値をselected cellとします。

こうすることで、ユーザーが押したマウスの位置を配列の行要素、列要素の番号に変換することができます。

また、最初からやり直しボタンが押されるとinit gameに戻るようにしています。

次にupdate statusステートです。

先ほども出てきたset board status.viとupdate board picture.vi以外にget cell coordinates around selected cell.viがあります。

このviで、ユーザーが選択したセルの上下左右の状態も変化させるようにします。

get cell coordinates around selected cell.viの中身は以下の通りです。

upper limitを入力していますが、これは盤面の縦横のサイズです(今回は5としています)。

ユーザーが押したセルがselected cellとなっていて、これに加えて左右、上下の座標を取得しaffected cellsとして、後続のset board status.viに渡しています。

judgeステートでは、盤面全体が無になったかどうかを確認し、なっていたらfinish、なっていなかったら再びユーザーからの入力を待つためにeventステートに進みます。

finishステートはブロックダイアグラム全体の紹介時に既に見せていますが、Whileループを止めるだけで他に何もしません。

あらかじめ問題を複数登録しておいてステージ選択させる場合

上記のプログラムでは、光らせるボタンの位置をプログラムの中で定数で定義していました。

これでもゲームとして遊ぶことはできますが、せっかくなら複数の問題を登録しておいてステージ選択ができるようにしておくとより楽しめます。

各ステージの問題は外部ファイル(今回はcsvを使用)に書いておいて、これを読み込む形で各問題を出題する形式にプログラムを書き換える場合には、以下のようにします。

initステートでは、ユーザーがステージ決定のボタンを押すまで次に進みません。

init gameステートではファイルからステージ情報を読み取るためのset board status from file.viを新たに設けています。

set board status from file.viの中身は以下の通りです。

特定の形式のファイルに問題が書かれているとして、問題部分のみを抜き出して2次元配列にしてboard statusに渡しています。

実際この問題を残しておくための外部ファイルを用意するのがメンドクサイかと思うので、csvファイルを作りました。

これは、本家のライツアウトの問題を収録しています。

ダウンロードされる際は、ここをクリックしてください(csvファイルがダウンロードできます)。

本記事ではライツアウトを作る方法を紹介しました。

こういった昔遊んだゲームをプログラミングで再現し遊んで懐かしむ、というのもユーザー操作画面を作りやすいLabVIEWでプログラムを作れるようになる醍醐味かなと思います。

そうでなくても、ピクチャに対するクリック位置の検出など、他のプログラムで応用が効きそうな内容については参考になるとうれしいです。

ここまで読んでいただきありがとうございました。

コメント

タイトルとURLをコピーしました