鏡のパズルで光を2本にする:交差する光の遊びで、難しさの質を比べる
遊びを見つける執筆にClaudeを使用しています。

鏡で光を曲げて灯台へ届けるパズルで、光の出どころが1本から2本に増えたとします。難しさは単純に2倍になるのでしょうか。それとも、1本のときには存在しなかった別の種類の難しさが現れるのでしょうか。この記事は、その問いを自分の手で確かめるための実験の設計書です。結果はここには書きません。 「プリズムの道」は、鏡(/と\を切り替えられます)と色ガラスを使い、灯台へ同じ色の光を届ける8ステージの光学パズルです。戻す機能、一歩だけのヒント、解放済みステージの選び直し、最少回転の記録があります。各ステージの配置や光の本数は、作品を開いて確かめてください。この記事では、そのルールを少しだけ拡張した小さな試作を自分で作り、「光が1本の版」と「2本の版」を同じ鏡の配置で遊び比べます。 2本の光が同じ鏡を共有すると、片方を直すともう片方が外れる場面が生まれるはずです。ただ、それが本当に「質の違う難しさ」なのかは、記録を取らなければ分かりません。以下の準備と手順で、読者自身が答えを出せる形にします。
「量」と「質」に分けて問いを立てる
「2本のほうが難しい」と言うだけでは、実験になりません。難しさを、数えられる量と、観察で見分ける質に分けます。
量は次の2つです。
- 切り替えた回数(試作が自動で数えます)
- 解くまでにかかった時間(ストップウォッチで計ります)
質は、次の3種類を仮説として置きます。
- 追跡の難しさ:1本の光の行き先を、鏡をいくつも経由して先まで読む難しさです。
- 干渉の難しさ:ある鏡を直すと、別の光が外れてしまう難しさです。光が1本なら起こりにくく、2本で共有する鏡があると起こりやすくなると予想できます。
- 取り違えの難しさ:どの色の光がどの灯台へ向かっているかを見失う難しさです。
最初に、自分の予想を紙に書いておきます。「2本版は時間が2倍になる」「切り替え回数は変わらず、外れる回数だけ増える」など、どんな形でも構いません。予想を先に書いておくと、結果を見たあとに都合よく解釈することを防げます。
準備するもの
用意するのは、次のものです。
- PCのブラウザ(HTMLファイルを開けるもの)
- テキストエディタ
- ストップウォッチ(スマートフォンのものでも可)
- 記録用の紙か表計算
- 協力者(任意。ひとりでもできますが、後述の順序の問題に注意が必要です)
試作のコードは下の通りです。proto.html のような名前で保存し、ブラウザで開くと動きます。外部ライブラリは使いません。
<canvas id="c" width="300" height="300"></canvas>
<p id="m"></p>
<script>
const N=6,S=50,LIGHTS=2; // 1にすると光は1本
const c=document.getElementById('c'),g=c.getContext('2d');
const keys=['3,1','3,4','1,4'],mir={};
keys.forEach(k=>mir[k]='/');
const src=[{x:0,y:1,dx:1,dy:0,col:'orange'},
{x:1,y:0,dx:0,dy:1,col:'deepskyblue'}].slice(0,LIGHTS);
const goal=[[5,4],[3,5]];
let turns=0,broke=0;
function trace(s,mm){
let {x,y,dx,dy}=s;const p=[[x,y]];
for(let i=0;i<40&&x>=0&&y>=0&&x<N&&y<N;i++){
const m=mm[x+','+y];
if(m==='/')[dx,dy]=[-dy,-dx];
else if(m==='\\')[dx,dy]=[dy,dx];
x+=dx;y+=dy;p.push([x,y]);
}
return p;
}
const hit=mm=>src.map((s,i)=>
trace(s,mm).some(q=>q[0]===goal[i][0]&&q[1]===goal[i][1]));
function count(){
let n=0;
for(let b=0;b<1<<keys.length;b++){
const mm={};keys.forEach((k,i)=>mm[k]=(b>>i&1)?'\\':'/');
if(hit(mm).every(Boolean))n++;
}
return n;
}
function draw(){
g.clearRect(0,0,300,300);g.strokeStyle='#ccc';g.lineWidth=1;
for(let i=0;i<=N;i++){g.beginPath();g.moveTo(i*S,0);g.lineTo(i*S,300);
g.moveTo(0,i*S);g.lineTo(300,i*S);g.stroke();}
src.forEach((s,i)=>{g.fillStyle=s.col;
g.fillRect(goal[i][0]*S+15,goal[i][1]*S+15,20,20);
g.strokeStyle=s.col;g.lineWidth=4;g.beginPath();
trace(s,mir).forEach((q,j)=>{const X=q[0]*S+25,Y=q[1]*S+25;
j?g.lineTo(X,Y):g.moveTo(X,Y);});g.stroke();});
g.strokeStyle='#000';
keys.forEach(k=>{const [x,y]=k.split(',').map(Number);g.beginPath();
if(mir[k]==='/'){g.moveTo(x*S+10,y*S+40);g.lineTo(x*S+40,y*S+10);}
else{g.moveTo(x*S+10,y*S+10);g.lineTo(x*S+40,y*S+40);}g.stroke();});
document.getElementById('m').textContent='切り替え '+turns+' 回 / 外れた '+broke+' 回'
+(hit(mir).every(Boolean)?' / 全部届きました':'');
}
c.onclick=e=>{const r=c.getBoundingClientRect();
const k=Math.floor((e.clientX-r.left)/S)+','+Math.floor((e.clientY-r.top)/S);
if(!mir[k])return;
const b=hit(mir);mir[k]=mir[k]==='/'?'\\':'/';turns++;
const a=hit(mir);if(b.some((v,i)=>v&&!a[i]))broke++;
draw();};
draw();console.log('解の数',count());
</script>このコードで決めている点は次の通りです。
- 光は出発点から直進し、鏡のあるマスで向きを変えます。「/」は右向きの光を上へ、「\」は右向きの光を下へ曲げます。
- 2本の光が同じマスで出会っても、互いに干渉せず通り抜けます。これは試作の取り決めで、公式作品の挙動の説明ではありません。
- 色ガラスは入れていません。光の色は出発点で固定で、同じ色の灯台(四角い印)に届いたときだけ到達とみなします。
- 「外れた」は、直前まで届いていた光が、切り替えのあとに届かなくなった回数です。干渉の目印として使います。
- 開発者ツールのコンソールには、鏡の全パターン(鏡がk個なら2のk乗通り)のうち何通りが全部の光を届けるかが出ます。解の数は、配置を調整する物差しになります。
手順:同じ鏡の配置で、光の本数だけを変える
1. 動作を確かめる
最初の配置は3つの鏡しかなく、練習用です。難しさの比較には使えません。ブラウザで開いて、鏡をクリックすると「/」と「\」が切り替わり、光の線が動くことを確かめてください。数回の切り替えで全部届くので、動作確認が済んだら本番用の配置づくりに進みます。
2. 本番用の配置を2つ作る
keys に鏡の位置を足し、src(出発点と向き)と goal(灯台の位置)を書き換えて、配置PとQを作ります。守る条件は次の通りです。
- 初期状態(鏡がすべて「/」)では解けていないこと
- 鏡の数は6〜8個程度にすること
- コンソールの解の数が1以上であること(0なら解けない配置です)
- 光の出発点と灯台は、盤面の中に収めること
- 2本版では、片方の光の通り道に入っている鏡のうち少なくとも1つが、もう片方の光の通り道にも入りうる配置にすること
最後の条件が、この実験の核です。2本の光がまったく別々の鏡を使うなら、2本版は「1本版を2回遊ぶ」のと変わらなくなります。共有する鏡があるかどうかは、解けた状態で両方の光が通る鏡を数えて確認します。
LIGHTS を1にすると、同じ鏡の配置のまま光だけが1本になります。「配置は同じで、光の本数だけが違う」という条件を守ることが、比較の土台です。
3. 遊ぶ順序を組む
同じ配置を同じ人が2回遊ぶと、2回目は答えを覚えているため速くなります。これを避けるために、次の組み合わせで遊びます。
- 人X、1回目:配置P・1本版、2回目:配置Q・2本版
- 人Y、1回目:配置P・2本版、2回目:配置Q・1本版
- 人Z、1回目:配置Q・1本版、2回目:配置P・2本版
- 人W、1回目:配置Q・2本版、2回目:配置P・1本版
1人が同じ配置を2回遊ぶことがなく、本数と配置と順序が偏りません。協力者が少ない場合は、人数分だけ上から取ります。ひとりで行う場合は、配置を3つ以上作り、日を空けて遊び、1本版と2本版の順序を交互にします。
4. 遊んでいる間の記録
遊ぶ前に「ヒントなし、答えの相談なし」を決めておきます。1回ごとに、次の項目を1行にまとめます。
- 切り替え回数、取り方:画面の表示を読み取る、何を見るためか:量
- 外れた回数、取り方:画面の表示を読み取る、何を見るためか:干渉
- 所要時間(秒)、取り方:最初のクリックから全部届くまで、何を見るためか:量・読む負担
- 取り違えの発話、取り方:「どっちの光?」など色や行き先を確かめる発言を観察者が数える、何を見るためか:取り違え
- 手が止まった回数、取り方:10秒以上クリックがなかった回数を観察者が数える、何を見るためか:読む負担
- 感想の一言、取り方:終了直後に「何が一番面倒でしたか」と聞いて書き取る、何を見るためか:質の手がかり
手が止まった回数と発話は、観察者が数えます。ひとりで行う場合は、画面録画を見返して数える方法もあります。
結果をどう読むか
数字が出そろったら、予想と照らして次のように読みます。1回ごとの数字は偶然に左右されるので、できれば異なる配置・異なる人で複数回分を並べて判断してください。
- 切り替え回数と時間がともに増え、外れた回数は変わらない:量が増えただけの可能性が高く、「2倍の作業」に近い難しさです。
- 外れた回数が増え、感想に「直したら別が壊れた」が並ぶ:干渉による質の変化が起きていると読めます。このとき解の数が少ないほど、手探りで偶然当たりにくくなっているかもしれません。
- 時間は延びたのに、切り替え回数はあまり増えていない:手を動かすより、頭の中で光を追う時間が増えています。追跡の難しさが主役かもしれません。
- 取り違えの発話や、手が止まった回数が増える:色や行き先の把握に負担がかかっています。盤面の見せ方、つまり色や線の太さ、灯台の目印の工夫で下げられる可能性があります。
- 1本版と2本版でほとんど差が出ない:配置が2本の光を絡ませていないのかもしれません。共有する鏡の数と、解の数を見直してください。
「外れた回数」は、ミスと同じ意味ではありません。到達していた光があえて外されることは、探索の一部として自然に起こります。数の多さだけで悪い操作と決めつけず、感想の一言と合わせて読みます。
起こりやすい誤り
- 鏡の数を揃えない:1本版だけ鏡を減らすなどすると、本数以外の差が混ざります。配置は固定し、LIGHTS だけを変えます。
- 解けない配置を出す:解の数が0のまま遊ばせると、難しさではなく「そもそも無理」を測ってしまいます。コンソールで必ず確認します。
- 観察者が助言する:「そっちじゃなくて」の一言で、時間と手が止まった回数が崩れます。助言は禁止にします。
- 色だけで光を区別する:色の見え方には個人差があります。協力者に見分けにくい人がいる場合は、線の太さを変えたり、灯台に文字を添えたりして、色に頼らない見せ方に直してから比べます。
- 1回の結果で結論を出す:配置の相性や遊ぶ人の得意不得意で、簡単にひっくり返ります。少なくとも2つの配置と複数の人で確かめます。
- 勝ち負けを競う雰囲気にする:子どもや家族と行う場合は、速さを競わせると手が止まった回数の記録が崩れます。「どこで困るかを教えてほしい」と伝えると、感想の質が上がります。
次の行動
まずは試作を保存して、練習用の配置で LIGHTS を1と2に切り替えて、光の線の動きを確かめてください。次に、公式の「プリズムの道」で1本の光の感覚をつかんでから、共有する鏡のある配置を2つ作って、上の表の順序で記録を取ります。試作が気に入ったら、単独のHTMLとして作品投稿に回す道もあります。その場合は、入口になる index.html を直下に置き、メール確認を済ませてから公開の手順に進みます。

