GUST NOTCH? DIARY

スタートレックのソースを読む その2

その1からの続きです。

  • 変数定義と初期化


230 REM ***** PROGRAM STARTS HERE *****
240 Z$=" "
250 GOSUB 5460
260 DIM G[8,8],C[9,2],K[3,3],N[3],Z[8,8]
270 DIM C$[6],D$[72],E$[24],A$[3],Q$[72],R$[72],S$[48]
280 DIM Z$[72]
290 T0=T=INT(RND(1)*20+20)*100
300 T9=30
310 D0=0
320 E0=E=3000
330 P0=P=10
340 S9=200
350 S=H8=0
360 DEF FND(D)=SQR((K[I,1]-S1)^2+(K[I,2]-S2)^2)
370 Q1=INT(RND(1)*8+1)
380 Q2=INT(RND(1)*8+1)
390 S1=INT(RND(1)*8+1)
400 S2=INT(RND(1)*8+1)
410 T7=TIM(0)+60*TIM(1)
420 C[2,1]=C[3,1]=C[4,1]=C[4,2]=C[5,2]=C[6,2]=-1
430 C[1,1]=C[3,2]=C[5,1]=C[7,2]=C[9,1]=0
440 C[1,2]=C[2,2]=C[6,1]=C[7,1]=C[8,1]=C[8,2]=C[9,2]=1
450 MAT D=ZER
460 D$="WARP ENGINESS.R. SENSORSL.R. SENSORSPHASER CNTRL"
470 D$[49]="PHOTON TUBESDAMAGE CNTRL"
480 E$="SHIELD CNTRLCOMPUTER"
とりあえずここまでで、利用される変数が宣言され、いくつかの情報が初期化されます。
まだまだ前準備の段階です。

240行で文字列変数 Z$ に70個の空白文字を代入しています。多くのBASICと同じように、代入処理の「LET」は省略できます*1。実はこの後280行で要素数72の文字列配列として宣言されるのが少し気持ち悪いです。宣言後に初期化したい感じですね。

260行は、数値変数の二次元配列をいくつか宣言しています。プチコンでも二次元配列まで利用できます*2。HP BASICは 1 origin のようですが、プチコンは 0 origin です*3。配列の要素の上限は32768個まで。括弧には()と[]のどちらも使えるとのことです*4

G[8,8] は、各要素が3桁の数でひとつの宇宙域の状態を示しており、それが8x8個分で銀河系の状態を保持しています。G は Galaxy の G だと思われます。3桁の数字は、100の位がクリンゴンの数、10の位が基地の数、1の位が星の数を表します。たとえば 「205」であれば、クリンゴンが2、基地なし、星5個、となります。

C[9.2] は、ワープや魚雷のコースを求める際に使われる、基準となる方向ベクトルの要素を表しています。コースは1〜9の数値で指定されます(9は1と等しくなります)。420行から440行で値を設定しています。C は Course の C ではないでしょうか。

K[3,3] は現在の宇宙域内にいるクリンゴンの情報を格納します。ひとつの宇宙域には、クリンゴンは最大でも3つまでしか現れないのです。宇宙域内でのX座標、Y座標、エネルギー、の3つの値が入ります。K は Klingon の K ですね。

N[3] は長距離センサを表示する際に、一行分(3個の宇宙域)の状態が G の配列からコピーされます。長距離センサは現在いる宇宙域の9近傍の3x3の宇宙域の表示を行いますが、行ごとに使いまわされます。

Z[8,8] は、銀河系地図の情報が入ります。長距離センサでスキャンした範囲の宇宙域の情報は、既知の情報として銀河系地図に記録されます。具体的には、スキャンした範囲の G の情報が Z にコピーされます。

270行は文字列配列の宣言です。
ここで問題となるのは、プチコンでは長さを指定した文字列変数が宣言できないことです。文字列の配列は宣言できますが*5、たとえば DIM A$(5) というのは、5文字の文字列 A$ ではなくて、A$(0)からA$(4) でアクセスできる文字列が5つという意味になります。また、部分文字列の取り出しはできますが*6、部分文字列の設定はできないようです。表示のための文字列は上書きしたり文字列の配列として保持すればいいですが、宇宙域の情報を文字列で保存している部分は数値配列に置き換える必要があります。

C$[6] は、現在の状況を表す文字列が入ります。具体的には "DOCKED", "GREEN", "RED", "YELLOW" のどれかです。Condition の C でしょう。

D$[72]、E$[24] は、計器の名称の文字列が入ります。460行〜480行で初期化されます。

A$[3] は、主に宇宙域内の座標の状況を調べるために、Q$,R$,S$の文字列と比較する際の比較元文字列が設定されます。5680行からの文字列比較ルーチンで使われています。

Q$[72]、R$[72]、S$[48] は、短距離センサの表示で使われる、現在の宇宙域の8x8の座標の情報を文字列として保持しています。ひとつの座標を表現するのは3文字で、何もない場所は" "、エンタープライズがいる場所は"<*>"、基地がある場所は">!<"、クリンゴンのいる場所は"+++"、星のある場所は" * "です。72+72+48=192=8*8*3 です。

D$とE$、Q$とR$とS$は、ひと続きの配列として宣言した方が扱いやすいはずです。72要素で分割しているのは、当時のシステムの制限なのかもしれません。

Z$[72] は Q$、R$、S$ を空白文字で初期化するために使われています。

文字列について、プチコンでは以下のようにするのが無難でしょう。

    • C$: 配列ではないので、C$ としてそのまま使う
    • D$,E$: 計器の名称を切り出すためのものなので、D$(8)としてしまって、それぞれに計器名を初期化して使う。E$は使わない。
    • A$: これも配列ではないので、そのまま A$ として使う
    • Q$,R$,S$: 8x8 の座標の表示文字列を保持するのが目的なので、 Q$(8,8) で宣言する。R$とS$は使わない。
    • Z$: 配列ではないので、そのままZ$として使う。あるいはZ$を登場させなくてもいいかも。

290行で、任務開始時の宇宙暦を設定します。T0が開始年、Tがゲーム中の現在の年を表します。RND(1)は0から1の値を返すので、20から39の値を求め、それを100倍した値が得られますので、2000年から(100年単位で)3900年までの値となります。
プチコンのRND()関数は、RND(X)で0から(X-1)の値を返します*7 *8。RND()関数は元々整数しか返さないので、(RND(21)+20)*100 のように置き換えられます。プチコンでは代入を重ねることはできないみたいですので、ここは二つの代入式に分ける必要があります。


T0=(RND(21)+20)*100:T=T0
となります。一行に複数の命令を記述するには「:」を使います*9。もし、0.00 から 0.99 までの乱数が必要な場合などは、RND(100)/100 のように書く必要があるでしょう。
また、INT()はありません。小数の値から整数部を取り出すには FLOOR() 関数を使います*10

300行の T9 は任務期間です。固定で30年となっているようです。ここで細かいことをいうと、クリンゴンとの対立は23世紀にピークを迎え2293年には和平協定を結ぶので、それを考えると任務開始の年は2200年から2263年の間にした方がいいんじゃないかと思います。


T0=2200+RND(63):T=T0
310行の D0 は基地に停泊中に1になるフラグです。Dock の D です。

320行はエンタープライズのエネルギーの設定です。E0 が初期値で3000からスタート。E は残量を示します。Energy の E です。

320行は光子魚雷の数です。P0 が初期値で10発。Pが残量を示します。Photon Torpedo の P ですね。

340行の S9 は、クリンゴン艦のエネルギーを示します。どの船も一律で200の値が設定されます。Shield の S ですかね。

350行の S は、エンタープライズのシールドに回されているエネルギーの値を持ちます。ここで、H8 という変数がでてくるのですが、この値に0が代入されるところと1と比較されるところがあるのですが、H8 に値を代入するところは出てきません。このプログラムは REV B ということなので前のプログラムの残骸なのかもしれません。

360行の DEF というのは関数を定義できる命令のようです。C の define と一緒ですね。
変数は以下のことを表しています。現在の宇宙域内での話です。

クリンゴンエンタープライズユークリッド距離を求める関数ですね。当時の HP BASICのマニュアルがないので推測するしかないのですが、引数 D には意味がないようです。使われているところでは0が与えられていました。
さて、プチコンではマクロや関数の定義はできないみたいですので、これはサブルーチンとしておくしかありません。変数 DIST を用意しておくことにします。また、算術演算子にはべき乗は用意されていないようです*11。POW() のような関数もないみたいですので、ここはベタに書くしかないでしょう。平方根をとる SQR() はあります*12。こんな感じになるでしょうか。


K[I,1]=(値):K[I,2]=(値):S1=(値):S2=(値)
GOSUB @FND
(ここでDISTの値を使う)
〜〜〜
〜〜〜
@FND
DIST=SQR( (K[I,1]-S1)*(K[I,1]-S1)+(K[I,2]-S2)*(K[I,2]-S2) )
RETURN
370行から400行は、エンタープライズの初期座標を求めています。Q1, Q2 は、銀河系内の8x8のどの宇宙域にいるかを示す座標です。Q1 がX座標、Q2がY座標です。S1, S2 は宇宙域内の8x8の領域での座標です。S1がX座標、S2がY座標です。それぞれ、1から8の値を適当に求めています。プチコンの配列は 0 origin ですので、こちらも 0から7の値を求めた方が扱いやすいかと思います。

410行は現在時刻を求めています。T7がゲームの開始時刻で、終了時に何分でクリアしたのかが表示されます。TIM()関数の仕様がわかりませんが、おそらくTIM(0)が分を返し、TIM(1)が時間を返すようです。プチコンで現在時刻を取得するには、TIME$*13 と TMREAD()関数*14を使います。以下のようになります。


TMREAD(TIME$),HOUR,MIN,SEC
T7=MIN+60*HOUR
420行から440行は、ワープや光子魚雷のコースを求めるために使われるベクトルの値です。一つ目の添字がコース、二つ目の添字は1がX座標で2がY座標を表しています。たとえばC[3,1] ならば、コース3の方向のベクトルのX座標の値を持っています。コースの9は1と同じ方向です。宇宙域の座標も宇宙域内の座標も、左上を原点として、下方向がX軸、右方向がY軸で表されていることに注意しましょう。

プチコンでもコースの数値と添字をあわせるために、C[10,2] で確保しておいて、0は使わないというのもアリです。代入は地道に一個ずつやるしかないですね。あ、DATAにしておく手もありますか*15プチコンはX軸とY軸が逆なので、値を入れ替えておくとこんな感じになります。

DIM C(10,2)
FOR I=1 TO 9
FOR J-0 TO 1
READ C(I,J)
NEXT
NEXT
DATA 1,0, 1,-1, 0,-1, -1,-1, -1,0, -1,1, 0,1, 1,1, 1,0

450行で、配列 D を0で初期化しています。DIM で宣言されていませんが、D は8つの要素を持ち、各計器の故障状況の数値を保存しています。Damage の D ですかね。負の値の時は故障中です。添字を間違っているようなところが見られますが、それはおいおい触れていきます。
プチコンでは、配列は0で初期化されるようです。ですが、続けてゲームをする場合は初期化が必要になります。FOR...NEXTで各要素に0を代入してやるか、最初の方で CLEAR を実行するようにすればいいかと思います*16 *17

460行から480行は、計器名を設定しています。1装置あたり12文字です。一行で書いてしまってもいいと思うのですが、なぜか分割して設定されています。

まだ、初期化が続きます。その3に続きます。