Squeak Smalltalk で万華鏡を書いてみた件
http://d.hatena.ne.jp/scinfaxi/20080719/1216413198 経由で。
まずは、オリジナルの Ruby コードの雰囲気を反映させつつ Squeak Smalltalk に移植してみました。
Ruby の rand() と違い Smalltalk の Integer>>#atRandom は 1 から指定した数までの乱数を発生すること、Smalltalk では配列のインデックスのスタートが 1 であること、Ruby での a[i]=v は Smalltalk では a at: i put v とメッセージ送信式で書かないといけない(条件分岐も同じ)こと、などが比較的目立つ違いかと思います。
| b a n c | "万華鏡の具" b := #('+' '☆' 'o' '*' '。' '+' '`' '、' '‥' '.' ',' 'O' '0' '●' '◎' '○' 'L' 'i' '@' '★' '、' ';' ':' '┗' '┣' '━' '┃' '┏' '┓' '┛' '┣' '┳' '┫' '┻' '╋' '┯' '┨' '┷' '┿' '┝' '┰' '┥' '┸' '╂' '─' '│' '┌' '┐' '┘' '└' '├' '┬' '┤' '┴' '┼'). a := Array new: 100 withAll: ' '. 25 timesRepeat: [ n := 45 atRandom. c := b atRandom. (n between: 1 and: 5) ifTrue: [ a at: n put: c. a at: 11-n put: c. a at: 90+n put: c. a at: 101-n put: c ] ifFalse: [ (n between: 11 and: 15) ifTrue: [ a at: n put: c. a at: 31-n put: c. a at: 70+n put: c. a at: 101-n put: c ] ifFalse: [ (n between: 21 and: 25) ifTrue: [ a at: n put: c. a at: 51-n put: c. a at: 50+n put: c. a at: 101-n put: c ] ifFalse: [ (n between: 31 and: 35) ifTrue: [ a at: n put: c. a at: 71-n put: c. a at: 30+n put: c. a at: 101-n put: c ] ifFalse: [ (n between: 41 and: 45) ifTrue: [ a at: n put: c. a at: 91-n put: c. a at: 10+n put: c. a at: 101-n put: c ]]]]] ]. "表示部分" World findATranscript: nil. Transcript cr; show: ('{1} {2} {3} {4} {5} {6} {7} {8} {9} {10} {11} {22} {13} {14} {15} {16} {17} {18} {19} {20} {21} {22} {23} {24} {25} {26} {27} {28} {29} {30} {31} {32} {33} {34} {35} {36} {37} {38} {39} {40} {41} {42} {43} {44} {45} {46} {47} {48} {49} {50} {51} {52} {53} {54} {55} {56} {57} {58} {59} {60} {61} {62} {63} {64} {65} {66} {67} {68} {69} {70} {71} {72} {73} {74} {75} {76} {77} {78} {79} {80} {81} {82} {83} {84} {85} {86} {87} {88} {89} {90} {91} {92} {93} {94} {95} {96} {97} {98} {99} {100}' format: a)
で、同じことを行列オブジェクト(a Matrix)を使ってもっとシンプルに書けないかと試してみたのがこちら。
まず 10×10 の行列を用意し、その左上 5×5 の範囲に、25 個の具をまき散らします。最後に行方向と列方向に鏡像を作って完成です。
| 万華鏡の具 行列 | 万華鏡の具 := #( '+' '☆' 'o' '*' '。' '+' '`' '、' '‥' '.' ',' 'O' '0' '●' '◎' '○' 'L' 'i' '@' '★' '、' ';' ':' '┗' '┣' '━' '┃' '┏' '┓' '┛' '┣' '┳' '┫' '┻' '╋' '┯' '┨' '┷' '┿' '┝' '┰' '┥' '┸' '╂' '─' '│' '┌' '┐' '┘' '└' '├' '┬' '┤' '┴' '┼'). 行列 := Matrix new: 10 element: ' '. "具をまき散らす" 25 timesRepeat: [行列 at: 5 atRandom at: 5 atRandom put: 万華鏡の具 atRandom]. "鏡像の生成" 1 to: 5 do: [:行# | 行列 atRow: 11-行# put: (行列 atRow: 行#)]. 1 to: 5 do: [:列# | 行列 atColumn: 11-列# put: (行列 atColumn: 列#)]. "表示" World findATranscript: nil. 1 to: 10 do: [:行# | Transcript cr. (行列 atRow: 行#) do: [:各々 | Transcript show: 各々] separatedBy: [Transcript space]]
これを Ruby に逆移植すると、こんな感じ。
Ruby の Matrix は、ちょっと用途が違うみたいで使えなかったので、配列の配列で表現しています。このため、列を操作するのに #transpose を使っていったん行と列の入れ替えを行ない、列操作を行操作に代えて行なってから再び #transpose で元に戻すことをしています。
万華鏡の具 = [ "+","☆","o","*","。","+","`","、","‥",".",",","O", "0","●","◎","○","L","i","@","★","、",";",":","┗", "┣","━","┃","┏","┓","┛","┣","┳","┫","┻","╋","┯", "┨","┷","┿","┝","┰","┥","┸","╂","─","│","┌","┐", "┘","└","├","┬","┤","┴","┼"] 行列 = Array.new(10){Array.new(10){" "}} #具をまき散らす 25.times{ 行列[rand(5)][rand(5)] = 万華鏡の具.choice } #鏡像の生成 (0..4).each{ |行#| 行列[9-行#] = 行列[行#] } 行列 = 行列.transpose (0..4).each{ |行#| 行列[9-行#] = 行列[行#] } 行列 = 行列.transpose #表示 行列.each{ |行| puts 行.join(" ") }