前回は複数色のライツアウトのパズルゲームを作りましたが、今回はその解を表示するライツアウトシミュレーターをつくります。2色から6色まで対応可能です。

HTML部分

HTML部分を示します。

style.css

グローバル変数と定数

グローバル変数と定数を示します。

ページが読み込まれたときの処理

ページが読み込まれたときの処理を示します。ページが読み込まれたらセルを生成して最初はどのセルもクリック数は 0 なのでそのような情報を2次元配列 cellStates に格納します。そのあとセルへの着色、イベントリスナの追加、ボリューム設定の初期化の処理をおこないます。

セルを生成する

セルを生成する処理を示します。これは前回のものと同じです。

セルが何回クリックされたか(ただし総クリック数ではなく colorCount で割ったときの剰余)を格納する2次元配列 cellStates を初期化する処理を示します。

2次元配列 cellStates に格納されている値をセルの色に反映させる処理を示します。setCellColors1関数はユーザーが問題を入力するためにセルをクリックしたときにも呼び出されます(解が表示されたとき以降にクリックされたときは別の処理をおこなう)。

ボリュームをレンジスライダーで調整できるようにする処理と効果音再生の処理を示します。

イベントリスナの追加

セルや求解ボタン、クリアボタンがクリックされたとき、ラジオボタンの状態が変更されたときに対応するイベントリスナを追加する処理を示します。

ラジオボタンの状態が変更されたときにおこなわれる処理を示します。

選択されたラジオボタンに合わせて colorCount の値を変更するのですが、cellStates に格納されている値のなかに colorCount – 1 より大きな値が格納されていると誤作動がおきるので、cellStates に格納されている値が colorCount – 1 を超えないように調整しています。そのあとセルの色を再設定しています。

セルがクリックされたときの処理

セルがクリックされたときの処理を示します。[解を調べる]ボタンがクリックされる前はクリックされたセルだけ、解が表示されたあとはクリックされたセルとその上下左右のセルの色が変わるようにします(表示された解が本当に正しいか確認できるようにする)。両者は解が格納される2次元配列 answer が 非null であるかどうかで区別できます。

求解と結果の表示

解を求めるアルゴリズムですが、最初の1行のそれぞれのセルを何回クリックするのかが確定してしまうとそれ以降は何回クリックすべきか考えるセルの上にあるセルの色が黒になるように回数を調整するだけで解を求めることができます(要するに貪欲法)。最初の1行だけ総当たり法で全部の組み合わせを考えます。

もしこの方法ですべて黒にすることができない場合は解は存在しません。

最初の1行だけ総当たり法が必要です。そのためには 0 ~ colorCount – 1 の整数をCOL_COUNT 個組み合わせたもののすべての組み合わせ(重複順列)が必要です。これは N進法で表した 0 から n の k 乗 – 1 までの数の各桁を利用すればよいので以下のような関数を定義します。

simulateOnClickCell関数は row行 col列目のセルをクリックしたら2次元配列 cellStates がどうなるかをシミュレートするためのものです。

上記の関数を用いて解を求める処理を示します。求解のアルゴリズムは上記のとおりです。cellStates のコピーを生成してこれをつかってシミュレートします。解は複数存在するのでクリック数が最小のものを求めます。

解が得られたらこれを表示し求解ボタンを非表示にするとともにラジオボタンを操作不能にします。解が存在しない場合はその旨を表示します。

解を取得したあとセルをクリックしたらそのセルと上下左右のセルの色を変更してクリアまでに必要なクリック数を表示させます。その処理を示します。

解が格納されている2次元配列 answer の値から各セルの色を計算することができます。そのセルに対応する answer の要素とそのセルの上下左右のセルに対応する要素の値の総和を求めます。この値を colorCount で割った剰余を求め、これを colorCount から引きます。こうして得られた値を colorCount で割った剰余が表示すべき色となります。

[クリア]ボタンがクリックされたときの処理を示します。

2次元配列 cellStates を初期化し、解が格納されている2次元配列 answer に null を代入して求解前の状態に戻します。またラジオボタンが操作できるようにします。