aburi6800のブログ

コンピュータのプログラミング、ゲームに関するニッチな情報を書いていくブログです。

【MSX】MSX-BASICの研究(1) 条件分岐ロジック

この記事について

MSX-BASICでプログラムを書いていて思い出すのが、昔ベーマガでDr.Dが「論理式を使うのじゃ」と口を酸っぱくして言っていたこと。 確かに論理式を使うとIF文は無くなるが、しかし、論理式は本当に速いのだろうか?
というのも、ネットでBASICの高速化テクニックを探していたところ、ON〜GOTO〜を使うほうが速い、という記事を見つけたためで、本当はどれが速いのだろうか?と考えた次第。
それじゃあ実際に比較してみようか、というのがこの記事の趣旨になります。

今の時代にどれだけの人が必要としている情報なのかわかりませんが(汗

※(2021/8/9)パターン4として、移動量を配列変数に定義した場合をテストしてみました。
記事の最後に追記しています。

テスト方法

今回のテスト方法は、以下の方針としています。

  • WebMSXで実施。
  • 一般的に使用される、SCREEN 1、WIDTH 32、DEFINT A-Zで初期化した状態で実行する。
  • ロジックは、実際の実装を考慮して4方向の判定処理とする。
  • カウントダウン終了から画面右端までの移動時間を測る。

パターン1

素直に入力値をIF文でひとつひとつ判定していくコードです。

プログラムリスト

100 ' *******************************
110 '   CHARACTER MOVE LOGIC TEST 1
120 ' *******************************
130 ' *** COMMON INITIALIZE ***
140 SCREEN 1:WIDTH 32:DEFINT A-Z
150 LOCATE 0,0:FOR I=3 TO 1 STEP-1:PRINT I;:FOR J=0 TO 999:NEXT J,I:PRINT " START"
160 X=0:Y=10:TM=TIME
200 ' *** LOGIC ***
210 S=STICK(0):VX=0:VY=0
220 IF S=1 THEN VY=-1:GOTO 260 
230 IF S=3 THEN VX=1:GOTO 260
240 IF S=5 THEN VY=1:GOTO 260
250 IF S=7 THEN VY=-1
260 LOCATE X,Y:PRINT " ";:X=X+VX:Y=Y+VY:LOCATE X,Y:PRINT "A";
270 IF X<32 GOTO 200
300 ' *** RESULT *** 
310 LOCATE 0,1:PRINT "TIME="; TIME-TM
320 END

実行結果

f:id:aburi6800:20210808125512p:plain
パターン1の実行結果

パターン2

ON〜GOTO〜で分岐させるコードです。

プログラムリスト

100 ' *******************************
110 '   CHARACTER MOVE LOGIC TEST 2
120 ' *******************************
130 ' *** COMMON INITIALIZE ***
140 SCREEN 1:WIDTH 32:DEFINT A-Z
150 LOCATE 0,0:FOR I=3 TO 1 STEP-1:PRINT I;:FOR J=0 TO 999:NEXT J,I:PRINT " START"
160 X=0:Y=10:TM=TIME
200 ' *** LOGIC ***
210 S=STICK(0)
220 ON S+1 GOTO 270,230,270,240,270,250,270,260,270
230 VX=0:VY=-1:GOTO 270
240 VX=1:VY=0:GOTO 270
250 VX=0:VY=1:GOTO 270
260 VX=-1:VY=0:GOTO 270
270 LOCATE X,Y:PRINT " ";:X=X+VX:Y=Y+VY:LOCATE X,Y:PRINT "A";
280 IF X<32 GOTO 200
300 ' *** RESULT *** 
310 LOCATE 0,1:PRINT "TIME="; TIME-TM
320 END

実行結果

f:id:aburi6800:20210808125735p:plain
パターン2の実行結果

パターン3

論理式を使ったコードです。

プログラムリスト

100 ' *******************************
110 '   CHARACTER MOVE LOGIC TEST 3
120 ' *******************************
130 ' *** COMMON INITIALIZE ***
140 SCREEN 1:WIDTH 32:DEFINT A-Z
150 LOCATE 0,0:FOR I=3 TO 1 STEP-1:PRINT I;:FOR J=0 TO 999:NEXT J,I:PRINT " START"
160 X=0:Y=10:TM=TIME
200 ' *** LOGIC ***
210 S=STICK(0)
220 VX=(S=7)-(S=3)
230 VY=(S=1)-(S=5)
240 LOCATE X,Y:PRINT " ";:X=X+VX:Y=Y+VY:LOCATE X,Y:PRINT "A";
250 IF X<32 GOTO 200
300 ' *** COMMON RESULT *** 
310 LOCATE 0,1:PRINT "TIME="; TIME-TM
320 END

実行結果

f:id:aburi6800:20210808125608p:plain
パターン3の実行結果

比較結果

結果は以下のようになりました。

パターン 処理方法 処理時間
1 IF文のみ 56
2 ON〜GOTO〜 51
3 論理式 59

総括

ON〜GOTO〜で処理するのが一番速いですね。実際にテストしていても、体感できるくらいに違いました。
また、パターン3の論理式がパターン1のIF文のみより遅かったという結果は、ちょっと意外でした。
しかし、パターン1のプログラムを見ていただけるとわかりますが、IF文で判定とは言え、条件に合致したときに他のIF文に入らないようにGOTOで飛ばしていますので、速くなっていたのでしょう。
論理式ではすべての値を評価する必要があるので、全てのIF文を実行しているのと同じことになっているのだと考えます。

実際、パターン1で各IF文のGOTOを書かなかった場合、処理時間は64と最も遅い結果になっていました.。

プログラムで条件分岐書く時は、ON〜GOTO〜で書けるように変数の値も考えると良いですね。

また気になる事があったら、検証してみたいと思います。


※2021/8/9 追記

パターン4

入力に対する各方向への移動量を配列変数に定義したコードです。

プログラムリスト

100 ' *******************************
110 '   CHARACTER MOVE LOGIC TEST 4
120 ' *******************************
130 ' *** COMMON INITIALIZE ***
140 SCREEN 1:WIDTH 32:DEFINT A-Z
142 DIM VX(9),VY(9):FOR I=0 TO 8:READ VX(I),VY(I):NEXT I
144 DATA 0,0,0,-1,0,0,1,0,0,0,0,1,0,0,-1,0,0,0
150 LOCATE 0,0:FOR I=3 TO 1 STEP-1:PRINT I;:FOR J=0 TO 999:NEXT J,I:PRINT " START"
160 X=0:Y=10:TM=TIME
200 ' *** LOGIC ***
210 LOCATE X,Y:PRINT " ";:S=STICK(0):X=X+VX(S):Y=Y+VY(S):LOCATE X,Y:PRINT "A";
220 IF X<32 GOTO 200
300 ' *** COMMON RESULT *** 
310 LOCATE 0,1:PRINT "TIME="; TIME-TM
320 END

実行結果

f:id:aburi6800:20210809132336p:plain
パターン4の実行結果

比較結果

パターン4を含むと、以下の結果になりました。

パターン 処理方法 処理時間
1 IF文のみ 56
2 ON〜GOTO〜 51
3 論理式 59
4 配列変数 43

配列変数が抜き出て速いですね。
パターン1や2にあるGOTOが無いのでこの結果になったのだと考えます。
BASICはインタプリタ言語なので、命令数が1つ増えただけでも処理速度に影響するというのは認識ありましたが、実際に結果を見ると相当違いますね。

なお、このテストでは、座標の上限値/下限値を1方向しか判定していないので、実際にゲームに組み込んだ場合の性能とは異なります。
あくまで指標として捉えていただけると幸いです。