Smalltalk-72で遊ぶOOPの原点:スラスターの火炎を描く(再び謎解き&少しアレンジ編)
アラン・ケイの“メッセージングによるプログラミング”という着想に基づき(非同期処理などいろいろ足りていないながらも──)比較的忠実に実装された1970年代の非常に古いSmalltalk-72に実際に触れてみるシリーズ 第2弾です(なお最新のSmalltalkについては Pharo などでお楽しみください!)。
今回は謎言語「Smalltalk-71」で書かれたスペースウォー・ゲームを Smalltalk-72に移植して動かすことを目指します。前回(2019年)を含む他の記事はこちらから→Smalltalk-72で遊ぶOOPの原点 | Advent Calendar 2023 - Qiita
flame
のあるべき実装を予測する
triangle
が用意できたので、改めて Smalltalk-71 の flame
を見ていきましょう。
スキャン画像を再掲します。
flame
は、:size
を引数にとるプロシージャ(Logo風に言うと。あるいは、Smalltalk-72風にはアクション)です。まず、軌跡が残らないようにペンを上げ(penup
)、反対を向き(left 180
)、2 + sqrt 3
だけ移動し(forward 2 + sqrt 3
)描き始めるためにペンを下げています(pendown
)。
はい。まずここ。ちょっと引っかかりますね^^;
:size
を引数にとるこれまでのプロシージャの例に倣えば、forward 2 + sqrt 3
は forward (2 + sqrt 3) * :size
の方がしっくりきます。
また、炎が描かれる場所までのタートルの移動と考えても、2 + sqrt 3
という中途半端な固定長より、宇宙船の胴体の半分の長さ、つまり (2 + sqrt 3) * :size
分だけ移動すると考える方が妥当です。
そのあとのtriangle size
についても、size
という返値有りプロシージャの存在という可能性も微レ存ながら、ここはやはり flame
プロシージャが引数として得た :size
を参照するのがスジだと思います。したがって:
が抜けていると解釈します。
次の forward .5
については .
をゴミと見ることもできますが、文字の間隔や次行の 1.5
の .
と似た位置と大きさであることから、そのままの .5
(0.5
)が妥当と判断しました。 triangle 1.5 * :size
の行の forward
の後の 5
についても同様に .
が消えた .5
(0.5
)でよさそうです。
最後の triangle 1 * :size
の行の forward
の後の空白の解釈は難しいですが、ここは素直に空白ととらえて forward :size
と考えることにしましょう。
etc.
は、ペンの位置と向きを元あった場所に戻す記述の省略と思われます。これは冒頭の penup
の行の逆+α(triangle
を描くために移動した分も戻す)を記述すればよいだけです。
したがって、あるべき Smalltalk-71 の flame
の定義はこうなります。
to flame :size penup, left 180, forward (2 + sqrt 3) * :size, pendown triangle :size, forward .5 * :size triangle 1.5 * :size, forward .5 * :size triangle 2 * :size, forward .5 * :size triangle :size, forward :size penup, left 180, forward (2 + sqrt 3 + 2.5) * :size end to
Smalltalk-72 へトランスパイルして動かしてみましょう。
to triangle size ( @ pendn turn 90 go 0.5 * :size turn `120 go size turn `120 go size turn `120 go 0.5 * size turn `90 ) to flame size ( @ penup turn 180 go ((sqrt 3) + 2) * :size pendn. triangle size. @ go 0.5 * size. triangle 1.5 * size. @ go 0.5 * size. triangle 2 * size. @ go 0.5 * size. triangle size. @ go size. @ penup turn 180 go ((sqrt 3) + 2.5 + 2) * size ) disp clear @ home penup goto 200 200 pendn. ship 30. flame 30
よい感じなのですが、炎の中の縦線がちょっと邪魔だし、最後の線分の長さも中途半端なので、ここは大胆(?)に改変して triangle
後の縦線は描かないように penup
を挿入することにします。
to triangle size ( @ pendn turn 90 go 0.5 * :size turn `120 go size turn `120 go size turn `120 go 0.5 * size turn `90 ) to flame size ( @ penup turn 180 go ((sqrt 3) + 2) * :size pendn. triangle size. @ penup go 0.5 * size. triangle 1.5 * size. @ penup go 0.5 * size. triangle 2 * size. @ penup go 0.5 * size. triangle size. '@ go size'. @ penup turn 180 go ((sqrt 3) + 1.5 + 2) * size ) disp clear @ home penup goto 200 200 pendn. ship 30. flame 30
[追記: よく考えると ship
は penup
した状態で終わっているので、flame
も triangle
もそれに倣っておけば、このアレンジは無用ですね^^; ]
to triangle size (
@ pendn turn 90 go 0.5 * :size
turn `120 go size
turn `120 go size
turn `120 go 0.5 * size turn `90
penup
)
to flame size (
@ penup turn 180 go ((sqrt 3) + 2) * :size pendn.
triangle size. @ go 0.5 * size.
triangle 1.5 * size. @ go 0.5 * size.
triangle 2 * size. @ go 0.5 * size.
triangle size. @ go size.
@ penup turn 180 go ((sqrt 3) + 2.5 + 2) * size
)
disp clear
@ home penup goto 200 200 pendn. ship 30. flame 30
(「sqrt」を実装する(準備編)へ続く)