Ulam Spiral を Squeak Smalltalk で


ちょうど無限素数列を使えそうなお話だったので Squeak Smalltalk で描いてみました。日本語版Squeak(Squeak4.2-ja-all-in-one) などのワークスペースへペースト後、あらためて選択してから do it(式を評価、alt/cmd + d など)で下の図が得られます。


| primesGen pen dotSize width center isPrimeOrNotGen form |
primesGen := Generator on: [:g |
   | primes next |
   primes := OrderedCollection withAll: #(2 3 5 7).
   primes do: [:prime | g value: (next := prime)].
   [  [:exit | [
         next := next + 2.
         primes anySatisfy: [:prime |
            prime * prime > next ifTrue: [exit value].
            next isDivisibleBy: prime]
      ] whileTrue] valueWithExit.
      g value: (primes add: next)
   ] repeat].

isPrimeOrNotGen := Generator on: [:g |
   1 to: Float infinity do: [:n |
      primesGen peek = n
         ifTrue: [primesGen next. g value: true]
         ifFalse: [g value: false]]].

dotSize := 2.
width := 200.
center := Display center.
pen := Pen new defaultNib: dotSize.
pen place: center.
pen north; turn: 180.
Display fillWhite; restoreAfter: [
   1 to: width do: [:length | 2 timesRepeat: [
      pen turn: -90.
      length timesRepeat: [
         isPrimeOrNotGen next ifTrue: [pen down].
         pen go: 0; up; go: dotSize]]].
   form := Form fromDisplay: (center - (width  * dotSize// 2) extent: width asPoint * dotSize + dotSize)].
form asMorph openInHand


http://squab.no-ip.com/collab/uploads/61/ulamspiral.png


もっとも、今回のように矩形のサイズをあらかじめ決めてしまうのであれば、必要な素数の最大値も決まるので、組み込みの素数生成器(Integer class>>#primesUpTo:)でもまったく問題ありません。

| pen dotSize width center isPrimeOrNotGen form |
width := 200.

isPrimeOrNotGen := Generator on: [:g |
   | primesStream |
   primesStream := (Integer primesUpTo: width * (width + 1) + 1) readStream.
   1 to: Float infinity do: [:n |
      primesStream peek = n
         ifTrue: [primesStream next. g value: true]
         ifFalse: [g value: false]]].

dotSize := 2.
center := Display center.
pen := Pen new defaultNib: dotSize.
pen place: center.
pen north; turn: 180.
Display fillWhite; restoreAfter: [
   1 to: width do: [:length | 2 timesRepeat: [
      pen turn: -90.
      length timesRepeat: [
         isPrimeOrNotGen next ifTrue: [pen down].
         pen go: 0; up; go: dotSize]]].
   form := Form fromDisplay: (center - (width  * dotSize// 2) extent: width asPoint * dotSize + dotSize)].
form asMorph openInHand