2019年6月17日月曜日

SDGsロゴの錯視

貧困なし, 飢餓ゼロ, 健康と幸福, 高度の教育,...など, 2030年までの17達成目標を掲げる国連のSDGs(持続可能な開発目標 Sustainable Development Goals)のロゴはなかなか華麗だ. 早速PostScriptで描いてみた.





 
 













カラフルな17個の扇形で囲まれていて, その隣り同志の扇形の間には白い間隔がある. この間隔は等幅のようでもあるが, なんとなく内側の方が広く見えるから不思議だ. 扇形が内側で狭くなるのにつられて, 間隔は逆に内側が広く感じるのであろうか. これを取り敢えずSDGsロゴの錯視といおう.

そこだけ取り出して描いたのがこの図だ.





これだけ眺めると, 外縁での間隔goと, 内縁での間隔giは別に違っては見えないが, 上の図ではたしかに錯視が起きる.

北岡さんの錯視のカタログhttp://www.psy.ritsumei.ac.jp/~akitaoka/catalog.htmlを見たが, こんなに簡単なのは掲載されていないようだ.

間隔の幅Gを変えたり, 内縁半径Rを変えたりして, 錯視の起きる範囲をしらべたいと思い作ったウェブアプリが下だ. 左下は+, -でRを加減する. Rをクリックすると標準に戻る. 右下はGについての同様なメニューである.



錯視の起きる起きないの境界は微妙なので, はっきりしたことはいえないが, 錯視はほどほどの間隔の時に起き易いらしい. このウェブアプリは出来たばかりで枯れていないので, うまく動作しない時はご容赦を乞う.


2019年6月15日土曜日

Tパズル

昨年夏のプログラミング・シンポジウムは諏訪のかんぽの宿で開催された. その客室にはお茶などと一緒にTパズルが置いてあり, それをいじった泊り客が気に入って宿の売店で購入するのを期待している.




Tパズルは上の図の左の家型の五角形を4分割したなんの変哲もないピースを組み合わせ, 指示されたいろいろな形を構成するパズルである. 最初の指示が図の右のT型を作るので, Tパズルというらしい. 元の家型の時のピースの縦横の辺が, T型では斜めになっているので, この問題は最初からいささか意地が悪い.

インターネットで探すと, 下の図のように様々な問題があるので, ちょっとやってみたくなり, 百円ショップで小学生の使う工作用紙を購入し, 自作した.


     
自作するには下のような図を描き, 同じ形の表と裏を貼り合せた. この升目が工作用紙の1cmである. 各辺の内側の数値は, T型の足の幅を基本単位とするその辺の長さで, 出来上がったピースにも同様に記入してある. この図では各ピースが繋って描いてあるが, 作業に便利なように, 本当はピースの間に隙間があった.



実際に出来たものは下の写真の通りで, 旅館で販売しているものより遥かに大きい. 市販のものは辺に寸法が書いてなく, いわばアナログ仕様だが, それでは√2と1.5の区別もつき難そうだ. 私のは寸法が記入してあるので間違うことはない.
    




さて, 私のやり方をちょっと種明かししよう. 上にあった問題の1番のT型と12番の家型を例にする.

型の図をPCに読み込み, 適当に拡大する. 角に順に番号をつける. マウスを動かし, それぞれの角の座標を読み取る. 座標はそれほどの精度を要求しない. それが下の2枚の図だ.




次にこの形を角を頂点とする三角形に分割する. T型では((0 6 7) (0 1 6) (4 5 6) (4 6 1) (4 1 2) (4 2 3)), 家型では((1 2 3) (1 3 4) (1 4 0))とした. そして夫々の型で, 座標と三角形の頂点の組をSchemeのプログラムで読み込む. その値を確認するため, プログラムはSchemeのgraphics機能を利用して出力する. それが次の図である. T型の足など多少怪しいがまぁよしとしよう.
   



   
続いてこの座標系において相隣る2点間の距離を計算する. それぞれの点のx, y座標が既知だから, Pythagorasの定理で距離は分る. 更にこの座標系での各々の三角形の面積を求め, 形全体の面積を算出する.

x0,y0; x1,y1; x2,y2を頂点とする三角形の面積は, 行列式

|x0 y0 1|
|x1 y1 1|
|x2 y2 1|

の半分であることは高校生のころ, 解析幾何の授業で学んだのでそれを使う. ただ三角形の頂点を時計廻りか反時計廻りかで辿ると面積が正負になり, いつも怪しくなる. そういう時は(0,0) (1,0) (0,1)の三角形で試みると反時計廻りで正になると分るが, プログラムでは絶対値をとってから合計している.

一方, 4個のピースの面積の和は6平方基本単位であるから, 今得られた面積を6で除して平方根をとると, それが座標系の長さと基本単位の比で, それぞれの辺が基本単位に変換できる.

これでT型を計算すると
(2.8999986101772106 .8652158634699881 .9960165420683874 2.935646424994157 1.0222409451321806 .9698622511287074 2.8779826845214163 1.0169988220903106)
が出てきて, 番号0の角からの順の辺の長さが, 3,1,1,3,1,1,3,1であることが分る. (0.865を1にするには勇気がいるが.)

また家型の方は
(1.418992855950106 2.022013340831029 1.993599932770006 1.4095980475184093 2.7873862791620128)
だから, √2, 2,2,√2, 2√2らしいとなる.

ここまで来たら大体の問題はわけもなく解けるが, 実際にやってみると案外微妙な値になる型もあり(1.5か√2かなど), ここに述べた方法が特効薬であるわけでもない. 元々の問題の図もさほど精密ではなく, また中にはこれはどうかと思う問題もあったが, 目くじらを立てることもあるまい.

2019年6月13日木曜日

連分数と近似分数


 
 
Martin GardnerがそのThe Unexpected Hanging(ネットで見つかる)の40ページで, 自然対数の底eを近似する, 分母分子とも3桁以内の分数は何かと問うている. その答は覚えやすい878/323 (=2.718266253869969...)だが, その計算法が今回の話題である.

Gardnerは自分では説明せず,
George Chrystal, Algebra An Elementary Text-Book for the Higher Classes of Secondary Schools and for Colleges, Part II. 1906
を見よとしか書いていない. この古典は有名らしく, ネットで探すと読むことができる. (648ページもある!)
http://www.archive.org/details/algebraelementar02chryuoft.pdf

しかしこれは, 高木貞治先生の「初等整数論講義」(手元のは第2版だが)の「中間近似分数」の章にそのものずばりの解説がある.

円周率πの同様な近似値355/113は遥かに有名であった. この分数を得るには連分数を使う.

普通の連分数は



の左上のような形である. この元のTexプログラムは
   \[a_0+{b_1\over\displaystyle a_1+
     {\strut b_2\over\displaystyle a_2+
       {\strut b_3\over\displaystyle\ddots+
         {\strut b_n\over a_n+\ddots
   }}}}\]
   \[a_0+\frac{b_1}{a_1}\:\raisebox{-1.3ex}{+}\:\frac{b_2}{a_2}
      \:\raisebox{-1.3ex}{+}\:\raisebox{-1.ex}{\ldots}\,
   \raisebox{-1.3ex}{+}\:\frac{b_n}{a_n}
   \raisebox{-1.3ex}{+}\:\raisebox{-1.ex}{\ldots}\]

この式にあるbiを1, aiを正の整数kiにしたものを単純(simple)連分数とか正則(regular)連分数といい, 右上のように書き, 物の本にはこれだけを扱ううものが少くない.

こういう表示法は空間をとるので, 通常は下の左や右のように書く. kiを部分商という.

こういう連分数から, 878/323や355/113のような近似分数が得られる.

円周率πの連分数展開で得られる部分商は7, 15, 1, 292, 1,...
で, この値を順に求める方法が「初等整数論講義」に載っている. これを見ると連分数は, Euclidの互除法に似ていることが分る.



部分商kの値から,


の関係でp, qが計算できる. πの場合のk, p, qは下の表の通り. p/qは連分数の展開を途中で止めたときの分数の値であり, 下の計算のようになる. 各行の右は, 左の分数の値とπとの差で, 見て分るように, 正負が交互に現れる.

この表の下の方に, 355/113がある. この近似分数はこうして発見された.


eについては, 今回はPythonで書いて

import math
x=math.e
ai=[]
while len(ai)<12:
    a=math.floor(x)
    ai.append(a)
    x=1/(x-a)
print(ai)

すると得られた結果は

[2, 1, 2, 1, 1, 4, 1, 1, 6, 1, 1, 8]


πと同じような表を作ると



しかしこの計算には, 問題の878/323がない. そこで「中間近似分数」が登場する.

 p5=106, p6=193,p7=1264
q5=39, q6=71,q7=465
の間には
p7-p5=p6×k6
q7-q5=q6×k6

の関係があるから, pの方は106に193を6回足すと1264になり, qは39に71を6回足すと465になる. この足し算の途中の値rλ, sλを分子, 分母にして計算すると, p5/q5からp7/q7の間の近似値が次々と得られる. これを中間近似分数(intermediate convergents)という.

この計算が次の表である.
    
    
    
そしてこの中に, 問題の878/323があったということだ.






2019年4月22日月曜日

15パズル

最近, 高木貞治先生の「数学小景」を眺めていたら, その中に「十五の駒遊び」という題で15パズルの話があった.

ところで, 最近知った15パズルの面白い解き方は, 福岡教育大学の藤本さんの提案する「回転型操作」によるものだ.

2件の論文がある.

情報処理学会研究報告にある「スライドパズルにおける回転型操作とアクセスビリティ」と, 近着の数式処理にある「Loop generatorによる15パズルの最適アルゴリズムとGod's numberについて」.

私は明解な手順には関心があるが, 最短手順には興味がないので, 後の論文は眺めた程度であった. 前の論文も解法は数式処理しシステムGAPを使って記述してあるので, GAPに馴染まぬ凡人にはとんと理解し得ぬ. 以下では私がSchemeで書いたプログラムの考え方を述べる.

この回転操作(英語ではloop generatorというらしい)は, 前回の15パズルのブログと似たやり方だが, 経路の単純なのが取り柄だ. 回転操作の前と後では, 空白は右下隅(15)に置くことにする. (イタリックの数字は場所の番地である.) 回転操作にはa, b, cがあり, それぞれ下の図の赤, 緑, 青の線のようにこまを回す. もちろん反対方向にも回す(回転数にマイナスを付けて示す). 例えばaを1回というと, 0にあったこまは4へ移動, 2回というと8へ移動する. bを1回では, 5のこまは9へ, 2回では13へ進む. 逆回転はは回数を負にする. aを-2回というと, 02へ行く.



回転経路が重なるのは, 図の7, 11, 13, 14の場所で, ここを経由して回転だけを使い, こまを任意の場所から他の任意の場所へ移すのである.
 
例えば5にあるこまを0へ移すには, aを4回して移動先013へ移動し, bを2回で移動元を13へ移し, aを-4回して最終目的地0へ動かす.

移動元と移動先が同じループに属しているといささか面倒だ. 例えば4から1へ移動するには,どちらもaのループにあるから, あらかじめ4を内側のループ, bかcのaと重ならない場所へ移動しておく. つまりaを3回で, 4のものを13へ; 次にbを-1回で9へ; 移動先の1は, a3回で8へ来ているから, 後2回で13へ進める. そこでbを1回行い, 4にあったものを13へ移す. それからaを-5回行うと, I1の位置へ行くわけである.

こういう手順が判明したから, aのループにある, 上端と左端にあるべき7個(4,3,2,1,,5,9,13)のこまを目的位置へ移す. この時はb, cのループの場所は自由に使ってよい. その後, bのループの5個(8,7,6,10,14)を揃える. この作業場所はcの10である. bが揃うと残りはcのループの10, 11, 14の番地に11, 12, 15のこまが残るだけになり, もとの配置のパリティが合っていれば, c1回かc-1回で完成する.

プログラムは後で示すことにし, 実際に走ったところを見よう. 下の図の左上(A)が最初の状態で, 空白はすでに右下15にある. 

こま4はbのループにあるから, (a 7)(b 2)(a -7)を行うと, (a 7)で4の目的地313へ行き, (b 2)で4が13へ行き, (a -7)で4が3へ移る. (B)になる.



こま3は元々は目的地2にあったのだが, 4の移動のとばっちりで0にいる. そこで(a 4)(b -1)(a -4)(a 6)(b 1)(a -6)を実行する. (a 4)で3を13へ, (b -1)で9へ, (a -4)でaループを一旦元へ戻す. 改めて2の位置を(a 6)で13へ運び, (b 1)で3をそこに置き, (a -6)で(C)のように3が収まる. (a -4) (a 6)と続けるのは無駄だが, プログラムが明瞭になるからこのままにしてある.

こま2は3に連られて目的地に来ていたからなにもしない. (D).

次は1の番だ. またaのループにあるから, (a 3)(b -1)(a -3)(a 4)(b 1)(a -4)の前半で9の位置に置き, 後半で0へ移す. (E).

5はaループだが同時にbループでもある. この場合は, bの中へ入れればよいが, 私のプログラムでは(b 2)で5へ入れることにしている. それから(a 3)(b 2)(a -3)で(F).

9は(a 1)(b -1)(a -1)(a 2)(b 1)(a -2)とする. (G).
 
次の13もa, cループだから, 一旦10へ移す. (c 1). その後(a 2)(c 1)(a -2) で(H). ここまででaループの7個が終わる. 以後はaループの7個には影響しないように注意.

(H)を見ると8はb, cループにあるから, (c -1)で10へ避難. それから(b 5)(c 1)(b -5). (I)になる.
 
7はcループにあるから簡単だ. 6の場所を(b 4)で14へ. それから(c 1)(b -4)で(J). 幸運にもついでに6, 10も揃うから(K),(L)も同じ図だ.

14はb, cループ上にいるから(c -1)で10へ引上げ, (b 1)(c 1)(b -1).

最後は11, 12, 15のcループ. 11が10にあれば何もしない. 11にあれば(c 1), 14にあれば(c -1)だ. (N).

全体の手は
(a 7)(b 2)(a -7);4
(a 4)(b -1)(a -4)(a 6)(b 1)(a -6);3 2
(a 3)(b -1)(a -3)(a 4)(b 1)(a -4);1
(b 2)(a 3)(b 2)(a -3);5
(a 1)(b -1)(a -1)(a 2)(b 1)(a -2);9
(c 1)(a 2)(c 1)(a -2);13
(c -1)(b 5)(c 1)(b -5);8
(b 4)(c 1)(b -4);7 6 10
(c -1)(b 1)(c 1)(b -1);14
(c -1);11 12 15

であった.
 
一方, Schemeによるプログラムはこんな具合いだ.
(define bs (range 0 16))

は盤面のこまのリスト. 
(define atab '(
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14)
(4 0 1 2 8 5 6 3 12 9 10 7 13 14 11)
(8 4 0 1 12 5 6 2 13 9 10 3 14 11 7)
(12 8 4 0 13 5 6 1 14 9 10 2 11 7 3)
(13 12 8 4 14 5 6 0 11 9 10 1 7 3 2)
(14 13 12 8 11 5 6 4 7 9 10 0 3 2 1)
(11 14 13 12 7 5 6 8 3 9 10 4 2 1 0)
(7 11 14 13 3 5 6 12 2 9 10 8 1 0 4)
(3 7 11 14 2 5 6 13 1 9 10 12 0 4 8)
(2 3 7 11 1 5 6 14 0 9 10 13 4 8 12)
(1 2 3 7 0 5 6 11 4 9 10 14 8 12 13)))
(define btab '(
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14)
(0 1 2 3 4 9 5 6 8 13 10 7 12 14 11)
(0 1 2 3 4 13 9 5 8 14 10 6 12 11 7)
(0 1 2 3 4 14 13 9 8 11 10 5 12 7 6)
(0 1 2 3 4 11 14 13 8 7 10 9 12 6 5)
(0 1 2 3 4 7 11 14 8 6 10 13 12 5 9)
(0 1 2 3 4 6 7 11 8 5 10 14 12 9 13)))
(define ctab'(
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14)
(0 1 2 3 4 5 6 7 8 9 14 10 12 13 11)
(0 1 2 3 4 5 6 7 8 9 11 14 12 13 10)))

はa, b, cそれぞれの回転で, 0,...のこまがどこへ行くかを示す. atab, つまりaの表は, 最初の行が(a 0)に対応. 同じ場所に留まる. 次の行(4 0 1...)はaの1回転で, 04へ, 10へ移ることを示す. 最後の行(atab[10])は-1回のものだ. b, cについても同様.
  
(define (rotate tab)
 (let ((b (make-list 16 0)))
  (do ((i 0 (+ i 1))) ((= i 15))
   (list-set! b (list-ref tab i) (list-ref bs i)))
  (set! bs (list-copy b)) 'ok))
(define (a n) (rotate (list-ref atab (modulo n 11))))
(define (b n) (rotate (list-ref btab (modulo n 7))))
(define (c n) (rotate (list-ref ctab (modulo n 3))))

(a n)がaのループをn回実行する. aの表から使うべき行をとりだし, rotateへ. rotateは16個のリストbを用意し, bs内のこまの番号をbへ移して最後にbをbsへ戻す.
(define ps0 '(4 3 2 1 5 9 13))
(define qs0 '(3 2 1 0 4 8 12))
(define ps1 '(8 7 6 10 14))
(define qs1 '(7 6 5 9 13))

ps0はaループのこまの番号, qs0はその目的地. ps1とqs1はbループのものである. 次がいよいよ解くプログラムである.
(define (solve2)
 (do ((i 0 (+ i 1))) ((= i 7))
  (let* ((p (list-ref ps0 i)) (q (list-ref qs0 i))
   (r (elemindex p bs)) )
   (if (not (= r q)) (begin (set! r
    (case r
     ((7) (b 2) 5)
     ((11) (c 1) 10)
     ((14) (c -1) 10)
     ((13) (b -2) 5)
     ((0 1 2 3 4 8 12) (let ((l (length (member r qs0))))
      (a l) (b -1) (a (- l)) 9))
     (else r)))
    (if (= r 10)
     (let ((l (- 8 i))) (a l) (c 1) (a (- l)))
     (let ((l (- 7 i))) (a l)
      (b (length (member r '(6 5 9)))) (a (- l))))))))

ここまでがaループのプログラムで, 7個についてdoループを回す. letへ来て, pはこまの番号, qは目的地, rは現在地である. r=qなら何もしない. そうでないならcase式へ来て, r=7なら(b 2)を実行, こまを5へ, という風に読む. rが0,1,2,3,4,8,12なら, rがqs0にある位置から後方の長さlを知り, (a l) (b -1) (a (- l))を行ない, こまを9へ移す. 上のいずれでもなければelseへ来て, 回転はせず, rはそのまま. 上のbeginの次の(set! r ...)でrを更新する.

結局移動するこまはcの10かbの5,6,9のどこかにいるから, それらの情報を使い, 目的地へ移動する.

bループのプログラムが以下だが, 説明は同様だ.
 (do ((i 0 (+ i 1))) ((= i 5))
  (let* ((p (list-ref ps1 i)) (q (list-ref qs1 i))
   (r (elemindex p bs)))
   (if (not (= r q)) (begin
    (case r
     ((11) (c 1))
     ((14) (c -1))
     ((7 6 5 9 13) (let ((l (length (member r qs1))))
      (b l) (c -1) (b (- l)))))
   (let ((l (- 5 i))) (b l) (c 1) (b (- l)))))))
 (case (elemindex 11 bs)
  ((11) (c 1))
  ((14) (c -1)))
(drawbs))

という次第で無事に並べ替られる. なかなか楽しい.

2019年3月11日月曜日

Lyonsの7テスト

Martin Gardnerは面白い話を沢山書いた. 最近, Lyonsの7テストというものを読んだ. ニューヨークの精神神経科医 L. Vosburgh Lyonsが考案したという.

7で割ったときの剰余を計算するのは面倒だが, Gardnerによるとこれが一番効率がいいそうだ.

まず例から. 14桁くらいの整数を考える. n=12340123456789とでもするか. 右から2桁ずつ区切り, 12 34 01 23 45 67 89とし, それぞれの区画の2桁の数の7での剰余をとる. つまり上の例では

5 6 1 2 3 4 5

が得られる. これを3個ずつ揃え

   3 4 5
   6 1 2
         5
ーーーーー


それぞれをmod 7で足す. 2 5 5になるわけだ. 右の2個を55のように読み, 左の2個を25のように読み, 右の7の剰余6から左の7の剰余4を引くと元の数の7の剰余2が求まる.

なぜうまくいくか. とりあえずn=123456のような6桁だけで考えてみる.

2桁ずつをa, b, cとすると n=10000a+100b+c. n mod 7が欲しいから

10000 mod 7 = 4, 100 mod 7 = 2を入れて

n mod 7 = 4a+2b+c. こうして右の2桁 10b+c から 左の2桁 10a+b を引いたから,

10b+c - (10a+b)=-10a+9b+c. -10=4 mod 7, 9=2 mod 7だから

4a+2b+cになり目出度し目出度し.

6桁より大きいときは n=106a+bだが 10000=4 mod 7, 100=2 mod 7 だったから1000000=8 mod 7=1 mod 7で, n=a+bと同じになり, 6桁ずつ束にして扱えばよいことがわかる.

なるほど.

この方法が優れている理由を冷静に考えてみると, 2桁の数を7で割った剰余は簡単に得られることを利用しているからだ. 我々は7の段 7,2 14; 7,3 21; 7,4 28を諳じているから, それに70を足した84, 91, 98が7の倍数であることも承知している.

3桁を7で割るのはもっと面倒だが, それが出来るなら, Gardnerがいうように7の剰余は次のように得る.

n=12340123456789 を右から3桁ずつに分ける.

12 340 123 456 789 それぞれの7の剰余をとる.

5 4 4 1 5

右から交互に 5 - 1 + 4 - 4 + 5 = 9 = 2 mod 7

この方法は11での剰余なら

1 10 2 5 8

8 - 5 + 2 - 10 + 1 = -4 = 7 mod 11. n mod 11 = 7.

13の剰余なら

12 2 6 1 9

9 - 1 + 6 - 2 + 12 = 24 = 11 mod 13. n mod 13 = 11.

というふうに使えるが, 11や13の除数を得るのに計算機を使うなら最初から計算機を使えばよいから, そんなにメリットはない.

ところで今の手品の秘密は 7×11×13=1001 にある.


2019年2月10日日曜日

中学入試問題

数日前の新聞に, 開成中学の数学の入試問題が掲載されていた. そのうち1問をやってみたが, 最近の小学生はこれが解けるのかと感心した.

下の図の左に示す直方体ABCD-EFGHがある. DC上にPを, DP=8, PC=12になるようにとる. EF上にQを, EQ=4にとる. CG上にRを, CR=9にとる.

直方体をPQRを通る面で切り, 断面をXとする.

そのXをABFE側から(以下南から)見た面積は228; ABCD側から(以下上から)見た面積は266.

この時高さAE, 奥行ADを計算する.



すぐ分るのはPRはXの辺であること. すると

平行な2面と, これと交わる他の面との交線は平行であり, 3次元空間での平行線はどの方向から見ても平行に見える.

ことから, Qを通るRPと平行な線はXの辺である. その線とAEとの交点をSとする.

    PR || SQ.

Xの辺には, PからADへ向って引く線のADとの交点をT, QからFGへ向った引く線のFGとの交点をUとする. PT || UQ, TS || RU.


   
Xの大体の形が分ったので, 南から見た図を作ると下のようになる. 太線の内側の面積が228, 左下の三角の面積が6, 右上の三角の面積が54, 長方形の面積は228+6+54=288で幅が20だから高さは14.4となる.



次は東から見た図である. 高さが分ったから, 図のAS=11.4とRG=5.4が分る. TSとRUが平行だから, ある比例定数aに対してAT=11.4a, UG=5.4aとする.

さらに上から見た図では, DP=8とQF=16が分っており, TPとQUが平行だから, DT=bとすると, FU=2b.

直方体の奥行=ST+TD=FU+URだから

  11.4a+b=2b+5.4a

  これから b=6a

  従って 奥行=17.4a
  左上の三角=24a, 右下の三角=96a,
  266+24a+96a=17.4a×-120
  226=348a-120a=228a a=266/228,

  故に奥行=17.4×266/228=20.3

 
とまぁすらすら書いたが, 結構図を何度も書きなおし, 沈思したことも何度かあった. 私が子供の頃はこんな問題はなくて助かったなぁ.

2019年2月4日月曜日

年のうちの春

古今集に「年のうちに春は来にけり一年を去年とや言はむ今年とや言はむ」という和歌がある. 旧暦の正月になる前に立春が来たということで, これだけ読むとこの現象は珍しいのかと思いがちであるが, 旧暦の月名の決めかたからすると, 立春 < 旧正月となる確率は1/2程度である.

旧暦の1ヶ月は天体の月の朔から次の朔の前日までの約30日で, 冬至を含む月を11月とする. 従って冬至が11月のちょうど中間にあると, 翌月の12月の終りまで45日あり, そこが丁度立春になるから, 立春と旧正月が一致するわけだ.

冬至が11月の真ん中より前半に来ると, 立春は12月末より前で, 12月中に来ることになり, 年のうちに春が来てしまう.

そこで2000年から2019年までの旧正月の日付を調べてみた.
    2000 2/5  〇
    2001 1/24 
    2002 2/12 〇
    2003 2/1
    2004 1/22
    2005 2/9  〇
    2006 1/29
    2007 2/18 〇
    2008 2/7  〇
    2009 1/26
    2010 2/14 〇
    2011 2/3
    2012 1/23
    2013 2/10 〇
    2014 1/31
    2015 2/19 〇
    2016 2/8  〇
    2017 1/28
    2018 2/16 〇
    2019 2/5  〇

この〇印が旧正月が立春2/4より遲い年である. 19年のメトン周期に10回あるから, 半分という確率は大体合っていた. なお上の表から1年立つと11日早まるのも読み取れる.

15パズル

先日のブログは15パズルを手で解く方法であった. 今回は計算機でやる話だ. 計算機による解法もいろいろあるが, とりあえずはプログラムを簡単にするという方針でいく.

下に14枚の図がある. これらはどれも4×4の15パズルの盤面の右下の3×3の部分を表している. その証拠はますの左上に斜体の数字で示す番地だ. まず図Aを見てほしい. 数字の代りに文字の変数でこまを示す. 空白のますには文字も書かない. 図Aの下にあるuldrはこれからこまを移動する方向である. 従ってまずgを上げる. hを左へ寄せる. eを下げる. gを右に寄せる. その結果が図Bだ. その矢印が示すように, 10,11,14,15の中でg,e,hが右回転したことになる. ほかのこまには影響しない.

この手順を右回転, 10,11,14,15の4ますを主戰場ということにする.

さて主戰場以外の場所のpを14に移動し(この時ほかのこまに影響があってもよい), 右回転し, 14のこまをpにもどすと(影響はもとに戻って), 15にあったものがpに, pが11に, 1115に移動したことになる.

p→11,11→15;15→p



どこかのこまを14に移動するには, 図C,Dに見るように, Cでurddluを実行する. するとDのように, 14,13,9,5,6のこまが左大回転する. gが2度のuで2段上に登るのは, 10に空白を残すためである.

ここで主戰場の右回転すると, Eになり, 先程の左大回転を逆回転するとFになって, f,e,hが回転する.

Gからの図では左大回転を2回実行し, 右回転, 右大回転2回で, d,e,hが回転することが分る. Kからの図は先に右大回転をすると, b,e,hが回転することを表す. ここには図がないが, Kの大回転を2回ずつ実行すると, a,e,hが回転することは容易に分る.

以上で5,6,9,13との交換はできたが, ほかの場所との交換は, 大回転の道順を工夫すればよいのも明らかだ. それが次の図である. 上の道順はルート0のつもりで, 左上のrt0である. 6のますに1, 7のますに2とあるのは, それぞれ右大回転を1回, 2回行うという意味だ. 913の2と1は左大回転の2回と1回を示す.

これを見れば, 主戰場の外のすべてのますを14へ移動する方法が分る.

   



これをまとめたのが以下で, 最初のrotは右回転, 続くrt0+, rt0-などはrt0の左大回転と右大回転である.
 
  
rot uldr
rt0+ urddlu
rt0- duuuld
rt1+ urrddllu
rt1- drrulld
rt2+ urrddluu
rt2- ddruuuld
rt3+ urdddlluru
rt3- dldrruuuld
rt4+ urrdddlluu
rt4- ddrruuulld


以下はpを11,15と交換する手順を, rtpで示したもので, 例えば左上の0との交換には, 上の図のrt4を4回転するから, rt4-が4回, その後, 右回転, 更にrt4+を4回を示している. rt10,11,14,15がないのは, そこが主戰場だからだ.

rt0 rt4- rt4- rt4- rt4- rot rt4+ rt4+ rt4+ rt4+
rt1 rt2- rt2- rt2- rot rt2+ rt2+ rt2+
rt2 rt2- rt2- rot rt2+ rt2+
rt3 rt3- rt3- rt3- rot rt3+ rt3+ rt3+
rt4 rt1- rt1- rt1- rot rt1+ rt1+ rt1+
rt5 rt0- rt0- rot rt0+ rt0+
rt6 rt0- rot rt0+
rt7 rt3- rt3- rot rt3+ rt3+
rt8 rt1+ rt1+ rt1+ rot rt1- rt1- rt1- 
rt9 rt0+ rt0+ rot rt0- rt0-
rt12 rt1+ rt1+ rot rt1- rt10
rt13 rt0+ rot rt0-


この準備が出来ると, ランダムな配置から元へ戻すことが可能になる. 前回のブログのランダムの例から戻す手順をやってみたのが以下だ.

まず左上0の直ぐ下がランダムな状態で, その下へ進んで(sp10)は空白を10へもっていく命令を実行したところである. 命令の後の1は時間順を表す.

この状態の右下15をみると9のこまがあり, これを8に戻したいから(rt8)を行う. (rt8)2の後のように, こま9は場所8へ移動している. そして10が15に来たから, 次は(rt9)を行う. そして10は9へ入る. 次は13だから(rt12), 次は12だから行先は主戰場の中だ. 従って(rot)をして主戰場の中を回転する. すると8が15に来る. そこで(rt7)を実行して8を7に入れた. これで左端の列は終り, 2列目へ.

2列目は順調に進行する. 3列目の中程, (rt0)で1を左上へ移動すると, 主戰場は11, 12, 15になり, rotしても様子は変らない. この場合はこまの並びで自分の場所にいないものを探す. するとこま4が1にいるから(rt1)を行い, 4を主戰場へ取込み, 1拍おいた後に3へ送る準備をする. それが時間番号でいうと, 18,19,20になる.

このように進んで, 22までくると, 主戰場以外はすべて揃ったので, 後は適当な回数の(rot)を実行し, 右下隅に12が来たら(l)(u)を行い, 最後を揃えて終わる. これをプログラムに書き直すのは簡単だ.

0             (rt2)7        (rot)14       (rot)21        
                              
  7  4 11  2    7  4  3  2   11  4  3  2    1 15  3  4
 15  1 14 __   15  1 14  8    5  1  7  8    5  6  7  8
 13 12 10  5    9 10 __ 11    9 10 __ 12    9 10 __ 11
  8  6  3  9   13  6 12  5   13 14 15  6   13 14 12  2
                                                 
(sp10)1          (rt4)8        (rt5)15      (rt1)22          
                                                 
  7  4 11  2    7  4  3  2   11  4  3  2    1  2  3  4
 15  1 14  5    5  1 14  8    5  6  7  8    5  6  7  8
 13 12 __ 10    9 10 __ 15    9 10 __  1    9 10 __ 15
  8  6  3  9   13  6 12 11   13 14 15 12   13 14 12 11
                                                 
(rt8)2          (rt0)9        (rot)16      (rot)23          
                                                 
  7  4 11  2   11  4  3  2   11  4  3  2    1  2  3  4
 15  1 14  5    5  1 14  8    5  6  7  8    5  6  7  8
  9 12 __ 13    9 10 __  7    9 10 __ 15    9 10 __ 12
  8  6  3 10   13  6 12 15   13 14 12  1   13 14 11 15
                                                 
(rt9)3          (rot)10        (rt0)17      (rot)24          
                                                 
  7  4 11  2   11  4  3  2    1  4  3  2    1  2  3  4
 15  1 14  5    5  1 14  8    5  6  7  8    5  6  7  8
  9 10 __ 12    9 10 __ 12    9 10 __ 11    9 10 __ 11
  8  6  3 13   13  6 15  7   13 14 12 15   13 14 15 12
                                                 
(rt12)4          (rt6)11        (rt1)18      (l) (u)25     
                                                 
  7  4 11  2   11  4  3  2    1 15  3  2    1  2  3  4
 15  1 14  5    5  1  7  8    5  6  7  8    5  6  7  8
  9 10 __  8    9 10 __ 14    9 10 __  4    9 10 11 12
 13  6  3 12   13  6 15 12   13 14 12 11   13 14 15 __
                                   
(rot)5          (rot)12        (rot)19        
                                   
  7  4 11  2   11  4  3  2    1 15  3  2
 15  1 14  5    5  1  7  8    5  6  7  8
  9 10 __  3    9 10 __ 15    9 10 __ 12
 13  6 12  8   13  6 12 14   13 14 11  4
                                   
(rt7)6          (rt13)13     (rt3)20        
                                   
  7  4 11  2   11  4  3  2    1 15  3  4
 15  1 14  8    5  1  7  8    5  6  7  8
  9 10 __  5    9 10 __  6    9 10 __  2
 13  6 12  3   13 14 12 15   13 14 11 12

最後に一言. これはプログラムをさぼるという方針のため, 実際にこまを動かす回数は膨大になっている. 人手向きではないことに注意が必要だ.

2019年2月2日土曜日

15パズル

15パズルというのは, Rubikキューブよりほぼ百年前に登場した, Rubikキューブと同じ置換パズルである. しかし, Rubikキューブにくらべれば, 解くのははるかに簡単である.

置換パズルについてはそのうち説明るすることにし, 15パズルは下の図のようなものだ. 1から15までの数を書いた正方形のこまが, 16枚収まる正方形の枠に入っている. 図のAのように左上から右下にかけて, 1から15のこまが並び, 最後が1箇所空白になっている. これを整列状態をいおう. 空白に隣接したこまは空白の方向へ滑らせて移動でき, 移動した後が空白になる.

図のBは12のこまを下へ移動したところ; Cは11を右へ移動したところである. このように空白へ隣のこまを移動することで, ランダムになったある状態(例えば図のD)から出発し, こまを上下左右に移動することを繰り返すだけで, 整列状態へ戻すパズルである. こまの色は整列した場所の色としては意味があるが, こま自身の色には意味はない.


  

少しやってみると, すぐに出来るようになるが, 難しい場所もある. 人手でやる場合の戻し方の要領を次の図に示す. こまを上へ動かす, 右へ動かすという代りに, 15パズルの世界ではu, rのように書く. 下, 左はd, lである.



Aはこまのある場所を示す番地の図だ. 番地は以下の文では斜体で書く.  こま1の場所が0なのはややこしいが, とにかくこのように番号をつける. まず0から15の場所から1のこまを探し出し, それを0へ移動してBにするのは簡単だ. 次に2のこまを1へ移動するとCになる. これもなんでもない.

3を2へ入れるのは多少問題で, その時4が3にあればめでたいが, 4以外のものがあるところへ4を入れようとすると, 3に影響が及ぶ. 解決法は3と4をひとまとめにして収めることである. Dのように4を2に入れ, 3には3以外のもの(今はそれをxとする)があるとして3を7に置く. 空白は6に移動しておく.

4を下げ, xを左へ, 3を上, 4を右に動かす. つまり図の下にあるように, dlurを実行すると, Eの図になる. 続いてxを下げ, 3を左, 4を上に動か  すとFのように3と4が収まるのである.

運悪く3の位置に3がある時は, 図のG,H,I,Jのように動かす. Gの下に示すdruを実行すると, Hの図になり, 4と3が縱に並ぶ. この4と3を離したいから, Hの下のuldrでI, 4と3の間にyが闖入した. その下のdluでJ, その下のurdでDの図になる.

この下の段も同じ要領で, 5,6,7,8が収まる. しかし次は9,10,11,12を揃えるのではなく, 9,13を3,4の方法で入れる. さらに10,14も同様にして入る. すると最後は10,11,14,15に11,12,15が残るので, 10に11が来るまでぐるぐる回せば完成である.

15パズルは整列状態からこまを適当に滑らせてランダムにしてみても, そうランダムにはならない. かといって全部のこまをとりだし,バラバラに箱詰めしても, 整列状態には戻らない配置になる可能性がある.


遊んでみるためには, 私の作った下の図のようなのがhttp://www.iijlab.net/~ew/15puz190202.html
にある.
 


空白の隣のこまをクリックすると, そのこまが空白の方向へ移動する. 下のClrをクリックすると整列状態になり, Ranをクリックするとランダムになる.