スタイルシート 箱入り娘 の説明
戻る


JavaScript を使わず,スタイルシートだけで箱入り娘パズルを作ってみます.
全くのお遊びです.これが何か実用の役に立つようなことは多分無いでしょう.スタイルシートは本来,動作を記述するものではありませんので,かなり力ずくで作っています.
画面
(これはキャプチャ画像です.これで遊ぶことはできません.)
使い方と仕組みについて説明します.


使い方

「初期配置」でブロックの配置を選びます.
ブロックを動かして,娘のブロックを下の出口から外に出します.

動かせるブロックにマウス ポインタを置くと,動かせる方向に矢印が表示されます.
矢印の表示
ブロックをクリックすると,ブロックが矢印の方向に動きます.
2 方向に動かせるブロックの場合は,ポインタの位置によって動く方向が変わります.ポインタに近い側の辺の方向に動きます.
ブロック移動 左 ブロック移動 右

ブロック移動 上 ブロック移動 下

ブロック移動 左 ブロック移動 上
「やり直し」で最初のブロック配置に戻せます.


ブロックの位置の保持

このゲームでは,現在のブロックの配置によってブロックを動かせる方向が決まります.そのような処理を行うには,各ブロックの位置を保持しておく必要があります.そのためにラジオ ボタンを使っています.
各ブロックについて,各マスに対応するラジオ ボタンを使います.小僧以外のブロックは複数のマスを占めるので,左上のマスの位置を保持します.たとえば娘のブロックでは,次の図で網掛けで示した部分の位置を保持します.
保持するマスの位置
小僧のブロックは 20 個のマスのすべてに置けます.小僧以外のブロックは,ブロックの一部が盤からはみ出る位置には置けないので,置ける位置は 20 箇所より少なくなります.
各マスに次のように番号を振ると
マスの番号
各ブロックを置ける位置はこうなります.
1 2 3 5 6 7 9 10 11 13 14 15
父親/母親/下男/下女1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
番頭1 2 3 5 6 7 9 10 11 13 14 15 17 18 19
小僧1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
この位置の数分のラジオ ボタンを使って,チェックされているラジオ ボタンでブロックがあるマスを表します.
たとえばブロックの位置がこのような場合
ブロック位置の例
ラジオ ボタンの状態はこのようになります.
位置
1234567891011121314151617181820
父親
母親
番頭
下男
下女
小僧
小僧
小僧
小僧

○ チェックされていないラジオ ボタン
● チェックされているラジオ ボタン


ブロックの移動

以下のような方法で,動かすブロックをクリックしたときにラジオ ボタンのチェック状態が変更されるようにします.

ラジオ ボタンは非表示にしておき,各ラジオ ボタンに対してラベル(LABEL 要素)を関連付けます.
各ブロックについて,そのブロックを動かすラベルがブロックと重なるようにしておきます.(ラベルをブロックの要素の子要素としています.)
移動できる空きがあるブロックについて,動かす先のマスに対応するラジオ ボタンに関連付けたラベルがブロックの要素の前面になるようにします.
移動できるブロック
ラベルの重なり
ブロックの位置をクリックすると,動かす先のマスに対応するラジオ ボタンがチェックされ,ブロックはそのマスに移動します.

動かせるマスが 2 方向にある場合は,2 つのラベルを前面にします.このとき,ラベルがブロックを半分ずつ覆うように位置と大きさを設定します.
移動できるブロック(2 方向)
ラベルの重なり(2 方向)
左/右の 2 方向,上/下の 2 方向に動かせる場合は,ラベルをブロックの半分の大きさの矩形にします.
左右の 1 方向と上下の 1 方向に動かせる場合は,ラベルを三角形にして,ブロックを覆う範囲をマスの対角線で分けます.
2 方向のラベルの形


条件分岐

スタイルシートでは,プログラミング言語のように if 文などで条件を判定して処理を分けるようなことができません.プロパティの設定はすべて式として書かなければなりません.また,直接数値の大小を比較するような機能もありません.
2024年に W3C の Working Draft で条件によってプロパティの値を設定する機能(if() 関数)が提案されましたが,その機能が実装されても,このプログラム(?)のように計算の結果によってプロパティの値を変えることは,どうもできなそうです.
そのため,条件によって値を変えるところは,すべての条件の場合の値を計算しておいてから,そのうちのどれかが選ばれるような式を書くような形になります.

たとえば --x に,ある条件を満たす場合は --n1,満たさない場合は --n2 の値を設定するという場合,条件を満たす場合に 1,満たさない場合に 0 となるようなプロパティ --b を計算しておいて
--x:calc(var(--b) * var(--n1) + (1 - var(--b)) * var(--n2));
と書きます.
--b はプログラミング言語で言うブール変数に相当します.
--b の計算の仕方は,たとえば --v が整数を表すプロパティである場合,その値が 42 に等しいかどうかを表す --b はこのように計算できます.(小数の場合はもう少し面倒です.)
--b:calc(1 - min(abs(var(--v) - 42), 1));
--b1--b2 を条件の真偽を表すプロパティ(1/0)とすると,論理演算は次のように計算できます.
論理積(AND)
  var(--b1) * var(--b2)
論理和(OR)
  min(var(--b1) + var(--b2), 1)
否定(NOT)
  1 - var(--b1)
このような考え方で,条件分岐的な処理を力業で書いています.


戻る