パズル通信ニコリ101号の「オモロパズルのできるまで」コーナーで生まれたパズル。原作ゲサク。「今までありそうでなかった」、「理詰めよりも直感で解ける」、と編集部的には評判はよかったようだが、意外と簡単に解を見つける方法が見つかってしまった。しかも掲載1回のみで消滅。以下その解説をする。
シンクローンのルールは本誌を参照してください。またはゲサクさんの解説をどうぞ。
方向とかはどうでもいいのだが、何となく分かりやすいのでこうする。
普通の割り算であれば0-1はできないので繰り下がりを考慮するのだが、全て繰り下がりを考慮せず1にする。
簡単にいえば各桁についてEx-ORを取る。0-0なら0,1-1なら0,1-0なら1,0-1なら1。
あまりが出たら失敗。でなければ成功
10000...1の左の1の右から数えた桁が左への移動量を示す。下からP+1桁目にあれば移動量はP。移動量をPとすると、盤面の横幅をQとして
左移動量=P % Q (PをQで割った余り) 上移動量=P / Q (PをQで割った整数部分)
となる。
または、
左移動量=Q - P % Q (PをQで割った余りを負の数で取る) 上移動量=P / Q +1 (PをQで割った整数部分に1を加える)
という場合もある。
P=Q×左移動量+上移動量
となっていればよい。整式の除法。
商は、問題を数値にしたときの方法と同じ方法で元に戻す。上の桁には0を詰めて桁を盤面のマス数に合わせる。
ニコリ101号の3番を例に。
■■□□ ■□□□ □■■■
110010000111
10001111101 略記 10001111101
_____________ _____________
11)110010000111 11)110010000111
11 00010
-- 10
00010 10
11 10
--- 11
10 011
11 0
---
10
11
---
10
11
---
11
11
----
11
11
--
0
割り切れた。
11は、左の1が2桁目にあるので左に1動かすことを示す。
□■□□ □■■■ ■■□■
一番左下のマスに行き場がないので間違い。
もし、一番左のマスが左に行くと上の段の右端から出てくるとすると正しい解ではある。
1111010100 略記 1111010100
_____________ _____________
101)110010000111 101)110010000111
101 110
---- 111
110 100
101 0100
---- 0101
111 0011
101
----
100
101
-----
100
101
-----
101
101
-----
11
余りが出た。よってこれは失敗。
以下略記法のみ書く
110100100
_____________
1001)110010000111
1011
01000
001001
00011
余りが出た。よってこれは失敗。
11000100
_____________
10001)110010000111
10000
00010001
000011
余りが出た。よってこれは失敗。
1100111
_____________
100001)110010000111
100110
00111001
110001
100001
00000
割り切れた。
100001は、左の1が6桁目にあるので左に5動かすことを示す。
問題は横4マスなので、左に1マス、上に1マス動かすことになる。(右に3マス上に2マスでもよい。)
□□□□ □■■□ □■■■
実際に左に1マス、上に1マス動かして確認してみると問題図が再現される。また、全ての黒マスがひとつながりになっている。よって解の1つは決定。
110010
_____________
1000001)110010000111
1001010
001011011
0110101
余りが出た。よってこれは失敗。
11001
_____________
10000001)110010000111
10010010
001001111
0011101
余りが出た。よってこれは失敗。
別解があるか確認したい場合はやはり調べるのだろう。
移動しすぎでありえない、というのが目で見て分かる場合、割り算をする必要はない。
例えばこの場合、左に3移動(1001)というのはそもそも中央の2列に黒マスがあるのでありえない。
最初に行う数値化は1次元に変換することである。そして0と1に直すのだから結局、問題をひとつの数にすることになる。
ずらして重ねる、というのは左に何桁かずらしたものを元の数に加える、という動作に当たる。n桁ずらすということは10n倍することにあたる。
また、黒マスは黒マスのまま、白マスは白マスのまま、黒マスどうしが重なると白マスに戻る、というのはEx-ORの操作に当たる。つまり、元の数に何桁かずらしたものをEx-ORすることである。
よってn桁ずらして重ねる、というのは10n+1を元の数に掛けることになる。ただし、加算ではなく、Ex-OR演算で掛ける、ということに当たる。
それの元の形を求めるのだから、Ex-OR演算による掛け算の逆演算であるEx-OR演算の割り算によって問題を10n+1で割れば元の形に戻る。
問題を作るには AX+X=(A+I)X=Y 戻すときは (A+I)-1Y=X
この方法があったからといってパズルが面白くなくなるわけではなく、使わないで頭の中だけで解けばいいわけである。
何がありがたかったか、というと、Ex-ORは逆演算が存在する上にEx-ORの逆演算がEx-ORなので複雑さが全くない、という点。だからEx-ORを用いたペンシルパズルはなかなかうまくいかないだろう。スリザーリンクもカックロも逆演算の妙(一方通行的・正しいかどうかの確認は簡単)をうまく使った面白いペンシルパズルなのだ。
筆算で引き算をしたとき、下りてきた数と割る数の最上位桁は1に決まっているので、そこは引き算結果は必ず0になるので、下の段に書かない。それ以外は0,1を書く。
こうすると、商を書かなくても下りている数の左を見ればわかる。
このへんは2進数の手計算になれていれば分かることなのだが、この説明で分かる人は分かってるし、分からない人は分からないままなのでほとんど意味がないかもしれない…
これをほぼそのままプログラムにしました。Borland C++5.5で動作確認。STLのbitsetを使っています。標準的なC++ならば動くでしょう。相変わらず入出力関係がCなのですが(苦笑)。
上の説明と違い、bitsetの下位ビット(引数で言えば小さいほう)が左上になっています。また、下から割り算をしています。組みやすかったから、という理由だけです。
「全ての黒マスがひとつながりになっている」チェックを作っていないため、分断された解が出てくることもあります。とりあえず目で見て判断してください。
Windowsのコマンドプロンプト用にコンパイルされた実行ファイル
使用法:synchro 問題ファイル名
問題ファイル形式は
1行目 横幅,縦幅 2行目以降 白マス=0,黒マス=1 でCSVを書く 例: 6,4 1,1,1,0,0,0 1,1,0,0,1,0 1,1,1,1,0,1 0,1,0,1,0,1
のように。最大256マス。