Smalltalk-72で遊ぶOOPの原点:宇宙船「spaceship」の仮実装と複数インスタンスの動作確認

アラン・ケイの“メッセージングによるプログラミング”という着想に基づき(非同期処理などいろいろ足りていないながらも──)比較的忠実に実装された1970年代の非常に古いSmalltalk-72に実際に触れてみるシリーズ 第2弾です(なお最新のSmalltalkについては Pharo などでお楽しみください!)。

今回は謎言語「Smalltalk-71」で書かれたスペースウォー・ゲームSmalltalk-72に移植して動かすことを目指します。前回(2019年)を含む他の記事はこちらから→Smalltalk-72で遊ぶOOPの原点 | Advent Calendar 2023 - Qiita


描いて移動するだけの spaceship

複数の宇宙船のキーボードからの同時操作を早く試さないといけないので、まず移動 moveship と描画 display ship のみに限定した spaceshipSmalltalk-72で実装します。

to clock (!mem 280)

to spaceship : pilot thrust steer trigger numtorps location speed direction time (
    isnew ? (:pilot. :#thrust. :#steer :#trigger. 
        "numtorps _ "speed _ "direction _ 0.
        "location _ point (rand between 50 462) (rand between 50 462).
        "time _ clock)
    0 < clock - time + MOVELAG ? (
        "time _ clock + MOVELAG.
        moveship.
        display ship)
    )

"SSIZE _ 6. "MOVELAG _ 0. "SPSCALE _ 1.0. "DIRSCALE _ 1.0. "LSCALE _ 1.0.

システムクロックの取得については mem 280 のままでもよさそうですが、Smalltalk-71の元のコードに見た目を似せるため clock アクションを作りました。(不明点が多かったり、いろいろ破綻してきているので、もはや「元のコードに似せる」努力自体、無駄なあがきのようにも思えますが…^^;)

spaceship はこれまでのプロシージャと違い、クラスとして機能する(インスタンス生成能を持つ)と仮定して、Smalltalk-72版ではインスタンスを生成する isnew とその非偽時、つまり、インスタンス生成直後のコンテキストである場合に実行される初期化処理を加えています。

仮引数の pilotthruststeertrigger は送られてきたメッセージから引数としての値をフェッチ : しています。後三者については、逐次評価して値が変わるオブジェクトであることを想定して(将来的にはジョイスティックをエミュレートするオブジェクトを渡す予定)、通常の値のフェッチ : ではなく参照をフェッチ :# しています。

その他のインスタンス変数については、適当な値で初期化しました。

非同期処理を想定したと思われる pause ... のところは悩ましいところですが、指定した間隔を置いて処理をするように最初に移動しました。もっとも、このエミュレーターは大変遅いので、画面更新や位置情報の更新のためのラグを考慮する必要はほとんど無いと思われます。

なおここで使用している MOVELAG を含めたグローバル変数については、すべて大文字に変更しました。加えて、Smalltalk-71版に登場する :size については何かと問題が発生したため SIZE からさらに SSIZE に名前を変えています。なお、Smalltalk-71 でプロシージャの仮引数として :size を使っているものは変更無しです。

これをうけて moveshipdisplay については次のようにコードが変更になります。どうぞあしからず。

to moveship (
    "speed _ speed + SPSCALE * thrust.
    "direction _ (direction + DIRSCALE * steer) mod 360.
    location x _ (location x + (cos direction) * LSCALE * speed) mod 512.
    location y _ (location y + (sin direction) * LSCALE * speed) mod 512.
)

to display (
    @ penup goto location x location y up turn direction + 90 pendn.
    (:#) SSIZE.
    (0 < thrust ? (flame SSIZE)
    0 > thrust ? (retro flame SSIZE))
)

グローバル変数の初期値はそれぞれ、上図およびコピペ用のコードに示したとおりです。

spaceship について、あとは、moveshipdisplay ship だけをコールするようにコードしました。

では、さっそく動かしてみましょう。とりあえず、thruststeertrigger530false に設定しています。

disp clear
"s1 _ spaceship 'Jimmy' 5 30 false.
repeat (s1)

良い感じですね。宇宙船を増やしてみましょう。

"s2 _ spaceship 'Beth' `5 `20 false.
repeat (s1. s2)

あらゆる年齢の「子供たち」のための パーソナルコンピュータ

esc キーで停止します。

簡易スケジューラーを作る へ続く)