JavaScriptでライツアウトをつくります。

ライツアウトは、5×5の形に並んだライトをある法則にしたがってすべて消灯 (lights out) させることを目的としたパズルです。よくあるのはあるライトを押すと、自身とその上下左右最大4個のライトが一緒に反転するというものです。

ライツアウト攻略法は検索すると多くの情報が公開されていて問題を入力すると答えが表示されるサイトもあります。ここでは既存のものと差別化するつもりで点灯・消灯の反転だけでなく複数の色が変化するタイプのものをつくります。といってもこれも既存品が多数あるのですが・・・。

HTML部分

まずはHTML部分を示します。

style.css

グローバル変数と定数

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

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

ページが読み込まれたときの処理を示します。セルを表示するためのdiv要素を追加し、イベントリスナを追加します。

セルの生成

セルを表示するためのdiv要素を追加する処理を示します。

セルは 1 行に 5 個、これを 5 行分生成します。生成されたセルはサイズを適切な大きさに調整したあと、何行何列目のものかすぐわかるように2次元配列に格納しておきます。またセルに文字が表示されているときにクリックすると自動的に文字が選択されてしまうのでそうはならないように、userSelect = ‘none’を設定しています。

ボリューム設定と効果音の再生

効果音の初期化とボリューム設定を可能にする処理を示します。

イベントリスナの追加

ゲーム開始の処理

ゲームを開始する処理(クリア後続きを再開する処理でもある)を示します。

最初は簡単な問題からはじめてクリアできたらクリアまでに必要なクリックの回数が多い問題に変更します。クリアまでにクリックできる回数には上限を設けてそれを超えた場合は不正解として扱います。どうしても答えがわからない場合のために、ギブアップボタンをクリックしたら、各セルをクリックする回数を表示させます。

スタートボタンをクリックしたらスタートボタンは非表示にしてギブアップ用のボタンを表示させます。またセルをクリックしたらクリックに反応するようにします。ギブアップしたときに表示されていた数字を非表示にしてクリックできる回数を limitMax に設定します。

そのあと問題を生成します。initCellStates関数でセルの初期状態を設定します。そしてその状態から各セルに適切な色をつけて表示させます。

問題を生成する

セルに新しい初期状態を設定する処理を示します。

2 次元配列に 0 を設定します。そのあと各要素にランダムに値を設定します。この値は各セルをこの回数だけクリックすればよいというものです。最初は (2, 2)の位置からはじめて配列の範囲外に出ないように場所をずらしながら値を増やしていきます。

getCellColors関数はcellStates[row][col]を調べてそのセルの色を取得する関数です。クリックするとそのセルとその上下左右のセルの色が変わるので、それらのセルに対応する cellStates の値を合計したものを COLOR_COUNT で割ったときの剰余から色がわかります。

setCellColors関数はgetCellColorNumber関数から取得できた色をセルに反映させるためのものです。

showNumbers関数は2次元配列 cellStates の値を対応するセルに表示させます。また hideNumbers関数はこの値を非表示にします。

ギブアップ時の処理

ギブアップしたときの処理を示します。

giveuped フラグをセットして cellStates の値を表示させます。giveuped フラグがセットされているときにゲームクリアしても失敗として処理されます。ゲームを再開できるようにスタートボタンを再表示させます。

セルをクリックしたとき

セルをクリックしたときにおこなわれる処理を示します。ignoreClickフラグがセットされていなければセルを選択したときの処理をおこないます。

対応するcellStatesの値をデクリメントします。そして各セルの色を求めて反映させます。そのあとステージクリアチェックをして必要であれば処理をおこないます。

ステージクリア判定

ステージクリアをチェックする処理を示します。

残り手数をデクリメントしてステージクリアしているか調べます。すべてのセルにおいてgetCellColorNumber関数が0を返したときはステージクリアです。そうでない場合は残り手数を表示させます。すでに手数オーバーしているときはその旨を表示します。ステージクリアの場合はonGameClear関数を呼び出します。

ステージクリア時におこなわれる処理を示します。

ステージクリア以降はクリックに反応しないようにします。giveuped フラグが立っていない状態で limit が負数でなければステージクリアです。ステージクリアのときは次の問題を2手分難しくします。クリア判定されてもステージクリアではない場合はその旨を表示します。