スタイルシート ライツ アウト の説明
戻る


JavaScript を使わず,スタイルシートだけでライツ アウト ゲーム(5×5)を作ってみます.
画面
(これはキャプチャ画像です.これで遊ぶことはできません.)
使い方と仕組みについて説明します.


使い方

「シャッフル」をクリックするとライトの点灯状態のシャッフルを開始し,「シャッフル」ボタンの表示が「ゲーム開始」に変わります.
「ゲーム開始」をクリックするとシャッフルが停止し,ライトをクリックできるようになります.
ライトをクリックするとライトの点灯/消灯が切り替わります.


点灯/消灯の切り替え状態の保持

ライトの点灯/消灯の切り替え状態をチェック ボックスを使って保持しています.
チェック ボックスは非表示にしておき,各チェック ボックスに対してラベル(LABEL タグ)を関連付けます.ラベルをライトの位置に配置し,チェック ボックスのチェック状態にしたがってラベルの色を変えます.
ライトをクリックする度にチェック ボックスの状態がトグルし,ライトの点灯/消灯が切り替わります.


シャッフル

ライトの点灯状態をシャッフルするためにアニメーションの機能を使います.
それぞれのライトについて,点灯/消灯の状態を表すカスタム プロパティを定義しておいて,その値が変化するアニメーションを無限に繰り返すように設定します.そして,「ゲーム開始」をクリックしたらアニメーションを停止し,その時点のプロパティの値で開始時のライトの点灯状態を決めます.各ライト毎にアニメーションの速度を変えてあるので,単に複数の点灯状態の中からひとつを選ぶだけでなく,「ゲーム開始」をクリックするタイミングによって点灯状態の組み合わせも変わります.

基本的には,上述のようにランダムにライトの点灯状態を決めますが,25 個のライトすべての点灯状態をランダムに決めてしまうと,以下のような不都合が生じます.

ひとつは,解けない点灯状態の組み合わせができてしまう場合があることです.
5×5 のライツ アウトの場合,点灯状態の組み合わせの中には解くことができないものが存在します.すべてのライトの点灯状態をランダムに決めてしまうと,そのような解くことができない組み合わせになることもあります.

もうひとつは,すべてのライトが消灯した状態になってしまう可能性があることです.
偶然,すべてのライトが消灯になってしまったら,ゲームになりません.

普通のプログラムなら,そのような状態になったらもう一度シャッフルをやり直すということもできますが,スタイルシートでは,ある条件を満たすまで処理を繰り返すというようなことはできません.
そのため,以下のような処理を行います.

25 個すべてのライトの点灯状態をランダムに決めるのではなく,右下の 2 個のライト(図で網掛けで示したもの)を除く 23 個のライトの点灯状態をランダムに決めます.
ライト配置の図
その結果によって残りの 2 個のライトの点灯状態を調節することで,解ける組み合わせにすることができます.
23 個のライトがすべて消灯になった場合,解けない組み合わせにしないためには,残りの 2 個のライトも消灯でないといけません.つまり,その場合 25 個すべてのライトが消灯になってしまいます.そこで,23 個のライトがすべて消灯になった場合は,すべてのライトを点灯に変更します.


カスタム プロパティの定義

このプログラム(?)では,多くのカスタム プロパティを @ルールの @property で定義しています.
@property の定義は,たとえばこのように書きます.
@property --a {
  syntax:'<integer>';
  inherits:true;
  initial-value:0;
}
カスタム プロパティを @property で定義している理由はいくつかあります.ひとつは,アニメーションを使うためです.
上述のように,ライトの点灯状態を決めるためにカスタム プロパティのアニメーションを使っています.
カスタム プロパティにアニメーションを使うためには,そのプロパティがアニメーション可能である必要があります.@propertysyntax<integer> を指定することで,そのプロパティをアニメーション可能にしています.

もうひとつは,計算結果の切り捨てのためです.
計算結果の小数部の切り捨てを行うために,整数のカスタム プロパティを定義して,計算結果を一度そのプロパティに設定することで切り捨てを行っています.
ただし,整数プロパティに小数値を設定した場合の丸めは四捨五入です.また,負の数で小数部が 0.5 の場合は負の無限大方向に丸められます(少なくとも Opera 74 では).切り捨てのために整数プロパティを使う場合は,その点を考慮して使用する必要があります.

@property で定義することが必須であるものは上記の二つですが,その他にも多くのプロパティを @property で定義しています.それは処理の効率化のためです.
値が整数であることが決まっているプロパティは整数型と定義しておくと,どうも処理の効率がよくなるようです.
このプログラムでは,スタイルシートとしては比較的複雑な計算を行いますので,少しでも処理効率がよくなるよう,値が整数に限定されるプロパティは @property で定義しています.


このおもちゃは Opera 74 以上用に作っていますが,Google Chrome 107 で動くことが確認できています.Google Chrome の他のバージョンでの動作は未確認です.


戻る