シンクローン理詰め解法

シンクローンとは

パズル通信ニコリ101号の「オモロパズルのできるまで」コーナーで生まれたパズル。原作ゲサク。「今までありそうでなかった」、「理詰めよりも直感で解ける」、と編集部的には評判はよかったようだが、意外と簡単に解を見つける方法が見つかってしまった。しかも掲載1回のみで消滅。以下その解説をする。

シンクローンのルールは本誌を参照してください。またはゲサクさんの解説をどうぞ

方法

方向とかはどうでもいいのだが、何となく分かりやすいのでこうする。

流れ

  1. 左上から右下に黒マスを1、白マスを0として、マス数桁の数値を作る
  2. 11,101,1001…で変な割り算をする
  3. 割り算がうまくいったらその割る数が答えの移動量を示し、商がもとの形を示す

変な割り算

普通の割り算であれば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

順に割ってみる

11

割り算
    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動かすことを示す。

商を戻してみる
□■□□
□■■■
■■□■
確認

一番左下のマスに行き場がないので間違い。

もし、一番左のマスが左に行くと上の段の右端から出てくるとすると正しい解ではある。

101

割り算
      1111010100    略記      1111010100
   _____________           _____________
101)110010000111        101)110010000111
    101                      110
    ----                      111
     110                       100
     101                        0100
     ----                         0101
      111                           0011
      101
      ----
       100
       101
       -----
         100
         101
         -----
           101
           101
           -----
              11

余りが出た。よってこれは失敗。

1001

割り算

以下略記法のみ書く

        110100100
    _____________
1001)110010000111
      1011
       01000
         001001
            00011

余りが出た。よってこれは失敗。

10001

割り算
          11000100
     _____________
10001)110010000111
       10000
        00010001
            000011

余りが出た。よってこれは失敗。

100001

割り算
            1100111
      _____________
100001)110010000111
        100110
         00111001
            110001
             100001
              00000

割り切れた。

移動量

100001は、左の1が6桁目にあるので左に5動かすことを示す。

問題は横4マスなので、左に1マス、上に1マス動かすことになる。(右に3マス上に2マスでもよい。)

商を戻してみる
□□□□
□■■□
□■■■
確認

実際に左に1マス、上に1マス動かして確認してみると問題図が再現される。また、全ての黒マスがひとつながりになっている。よって解の1つは決定。

1000001

割り算
              110010
       _____________
1000001)110010000111
         1001010
          001011011
             0110101

余りが出た。よってこれは失敗。

10000001

割り算
                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マス。

ホームに戻る