GUST NOTCH? DIARY

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

その3からの続きです。

  • 現在の宇宙域の配置を設定


810 K3=B3=S3=0
820 IF Q1<1 OR Q1>8 OR Q2<1 OR Q2>8 THEN 920
830 X=G[Q1,Q2]*.01
840 K3=INT(X)
850 B3=INT((X-K3)*10)
860 S3=G[Q1,Q2]-INT(G[Q1,Q2]*.1)*10
870 IF K3=0 THEN 910
880 IF S>200 THEN 910
890 PRINT "COMBAT AREA CONDITION RED"
900 PRINT " SHIELDS DANGEROUSLY LOW"
910 MAT K=ZER
920 FOR I=1 TO 3
930 K[I,3]=0
940 NEXT I
950 Q$=Z$
960 R$=Z$
970 S$=Z$[1,48]
980 A$="<*>"
990 Z1=S1
1000 Z2=S2
1010 GOSUB 5510
1020 FOR I=1 TO K3
1030 GOSUB 5380
1040 A$="+++"
1050 Z1=R1
1060 Z2=R2
1070 GOSUB 5510
1080 K[I,1]=R1
1090 K[I,2]=R2
1100 K[I,3]=S9
1110 NEXT I
1120 FOR I=1 TO B3
1130 GOSUB 5380
1140 A$=">!<"
1150 Z1=R1
1160 Z2=R2
1170 GOSUB 5510
1180 NEXT I
1190 FOR I=1 TO S3
1200 GOSUB 5380
1210 A$=" * "
1220 Z1=R1
1230 Z2=R2
1240 GOSUB 5510
1250 NEXT I
1260 GOSUB 4120

810行では、この宇宙域でのクリンゴン、基地、星の数を入れておく変数を0で初期化します。

820行で、現在のエンタープライズの位置を確認しています。Q1, Q2 は、銀河系での座標が入っていました。初期値は確実に銀河系内にいますが、ワープで移動することで、8x8の領域の外にでてしまうこともあります。そのため、現在の座標が 1<=Q1<=8, 1<=Q2<=8 であることを確認しています。もし銀河系の外にいる場合、クリンゴン、基地、星の数はそれぞれ0のままなので、エンタープライズ以外に何もない、という状態になります。
プチコンでは「論理演算子」という名前ではなく「ビット演算子」という呼び方になっていますが、機能は同じようです。「OR」はそのまま使えます*1

銀河系内にいる場合は、現在の座標の宇宙域でのクリンゴン、基地、星の数の情報を G[Q1,Q2] から、変数 X にコピーします。3桁の数値の100の位がクリンゴンの数、10の位が基地の数、1の位が星の数でした。Xを100で割って整数部分を取り出すことでクリンゴンの数 K3 を得ます。(X-K3)で整数部が0になりますので、Xを10倍して整数部分を取り出すことで、基地数 B3 が得られます。G[Q1,Q2]を10で割ったものの整数部を10倍すると、1の位が0になります。この数を元の数から引くことで1の位の数か残るので、S3 が得られます。
それぞれの数値が0でない場合は、宇宙域内での位置を決定し、その情報を Q$,R$,S$ に文字列として設定します。

その前に、クリンゴンがいるにもかかわらずシールドの値が低い場合は警告メッセージを出します。(870行から900行)

910行から1250行までが宇宙域の情報の設定です。

まず、910行から940行でクリンゴンの値を初期化します。910行の命令で配列が0でクリアされていると思われるのですが、920行から940行で、再度エネルギーを0に設定しるのが冗長のような気がします。

950行から970行で、宇宙域を表す配列を初期化しています。ここで、最初に空白文字列で初期化したZ$が使われるのですが、240行では70文字しか代入されていないのが謎。72文字の空白にしておくべきでしょう。

980行からは以下のことを行っています。

  • エンタープライズを(S1,S2)の座標に書き込む
  • クリンゴンがいる場合は、
  • 基地がある場合は
    • 適当な書き込める座標(空白の座標)を求める
    • 基地を書き込む
  • 星の数の分だけ
    • 適当な書き込める座標(空白の座標)を求める
    • 星を書き込む

次の図は宇宙域を表す配列の具体的な例を示しています。1つの座標は3文字で表現されていて、Q$,R$,S$ で8x8の座標を表現します。

最初に書き込むのはエンタープライズです。(S1,S2)の位置に書き込みます。配列への書き込みは5510行からのサブルーチンが行います。書き込みたい文字列をA$に、書き込みたい座標を(Z1,Z2)に設定してから呼び出すことで書き込みが行われます。


5510 REM ****** INSERTION IN STRING ARRAY FOR QUADRANT ******
5520 S8=Z1*24+Z2*3-26
5530 IF S8>72 THEN 5560
5540 Q$[S8,S8+2]=A$
5550 GOTO 5600
5560 IF S8>144 THEN 5590
5570 R$[S8-72,S8-70]=A$
5580 GOTO 5600
5590 S$[S8-144,S8-142]=A$
5600 RETURN

変数 S8 は Q%,R$,S$ の全要素を通算した192要素の何番目から書き込めばいいのかを求めます。一行分の要素は3*8=24文字分です。なので、S8 = (3*8)*(Z1-1) + 3*(Z2-1) + 1 = 24*Z1 + 3*Z2 -26 で求められます。配列が3つに分かれているので、73<=S8<=144 の時は Q$ に、145<=S8 の時は S$ に書き込まないといけません。なので、Q$に書き込むときは添字を-72して、S$に書き込むときは添字を-144する必要があります。
ここで、HP BASIC では、部分文字列の代入ができるようなのですが、プチコンでは文字列の部分代入はできません。ですので、データの持ち方から変える必要があります。
たとえば、次のような方法が考えられます。


DIM Q$[8,8]

Q$[Z1-1,Z2-1] = A$

これだと、サブルーチンにする必要もないですね。オリジナルでは、表示の際に部分文字列を取り出して表示しやすいように、文字列配列を状態の保存場所にしてあるのだと思います。表示時に適切に整形できるのであれば、連続した文字列にこだわる必要はありません。

さて、元の処理に戻ると、次はクリンゴンの設定です。5380行からのサブルーチンを呼んで、書き込み可能な適当な座標を求めます。


5380 R1=INT(RND(1)*8+1)
5390 R2=INT(RND(1)*8+1)
5400 A$=" "
5410 Z1=R1
5420 Z2=R2
5430 GOSUB 5680
5440 IF Z3=0 THEN 5380
5450 RETURN

R1とR2に1から8の適当な数字を求めます。これをZ1とZ2にコピーして 5680行からの文字列比較ルーチンを呼び出します。このルーチンは、Q$,S$,R$ の中の(Z1,Z2)の座標に相当する3文字とA$の3文字を比較して、一致した場合は Z3 を 1 に、不一致の場合は Z3 を 0 に設定します。すなわち、A$=" " と比較して一致しなかった場合は、既に何かが書き込まれているということで、別の座標を求めなおして空白の座標を探しています。


5680 REM ******* STRING COMPARISON IN QUADRANT ARRAY **********
5683 Z1=INT(Z1+.5)
5686 Z2=INT(Z2+.5)
5690 S8=Z1*24+Z2*3-26
5700 Z3=0
5710 IF S8>72 THEN 5750
5720 IF Q$[S8,S8+2] <> A$ THEN 5810
5730 Z3=1
5740 GOTO 5810
5750 IF S8>144 THEN 5790
5760 IF R$[S8-72,S8-70] <> A$ THEN 5810
5770 Z3=1
5780 GOTO 5810
5790 IF S$[S8-144,S8-142] <> A$ THEN 5810
5800 Z3=1
5810 RETURN

Z1 と Z2 は既に整数のはずですので、0.5を足してINT()をとっても、元の数と同じになるはずです。
S8 は(Z1,Z2)の情報に相当する比較対照位置を求めています。既に述べたのと同じです。
指定位置からの3文字分の部分文字列とA$が一致している場合は、Z3=1となります。
プチコンでやるならこんな感じでしょうか。


DIM Q$[8,8]

Z3=0
IF Q$[Z1-1,Z2-1]!=A$ THEN RETURN
Z3=1
RETURN

また、元の処理にもどります。クリンゴンの次は基地の書き込みです。これもクリンゴンの時と同様の手順で行われます。

同じようにして星を書き込みます。

最後に、1260行で 4120行からのサブルーチンを呼び出します。このサブルーチンは現在の状況を確認して短距離センサの出力を行います。これは次回に回しましょう。
その5に続きます。