■インベーダーゲームは何処へ?
インベーダーゲームが一世を風靡したのは小生が大学生の頃のことであった.1ゲーム100円という料金はパチンコと同じであったから,当時それにはまった若者は多く,インベーダーゲーム専用の喫茶店(ゲームセンターの原型)も出現したほどである.
それから4半世紀も経つと,インベーダーゲームがTVゲームのはしりであって,その後のブームの火付け役となったことを知る者は4−50代のオジサンばかりである.小生の職場で20代のゲームエイジにインベーダーゲームのことを訊ねてみると,異口同音に「何ですかそれ?」という回答が返ってくる.インベーダーゲームはすでに忘れ去られた存在であるようだ.
ところが,つい最近,小学3年生の息子がインベーダーゲームをやってみたいといいだした.どこでそのことを聞きつけたのか訊ねてみると,当時はやったギャグマンガ「すすめ!!パイレーツ」江口寿史のなかにインベーダーゲームのシーンがでていて,それで興味を覚えたらしい.
当時のマンガはいまでも古本屋で入手可能だが,ゲームとなると難しいだろう・・・ということで,インベーダーゲームを作るはめとなった.しかし,幸いなことに10年ほど前に出版された拙著
「実験ノートのグラフ化技法と最新解析法」,山海堂
でインベーダーゲームの作り方を紹介したことがあり,原型を一部を手直しするだけで息子の要求を満たすことができた.
今回のコラムでは,プログラム共々,拙著の解説も書き直して掲載することにした.まったく無の状態から試作するのではつらいので,この記事が同じ年頃の息子をもつお父さんたちにとって幾ばくかの参考になれば幸甚である.
それにしても,当時インベーダーゲームで一攫千金を成した人はどれくらいいたのだろうか? インベーダー成金という話を聞いたことはないが,その後のバブル崩壊,株価暴落を乗り切れず元の木阿弥と化しているのではなかろうか? ゲームをするばかりで,もの作りを忘れたゲームエイジはこれからどこへ向かおうとしているのか?(ゲームエイジャーよ,何処へ行き給う?)等々の想いが去来するのは私ばかりではあるまい.
===================================
【1】第3章 短いゲームプログラムを作ってみよう
この章では,キーの押下状態をINP関数の値を参照することにより取り出す方法を紹介します.キー入力を知るためにINKEY$やINPUT$(1)を使うと,キー入力された文字がいったんキーボードバッファに格納されてしまい,押下状態のチェックに時間がかかります.
そこで,INP関数を用いて入力ポートのキー入力状態のデータを直接センスして調べる方法に変えることによって,いま押されているキーを瞬時に知ることができるようになります.INP関数を使うと超特急の速さで検出できるのみならず,同時に押されている複数のキーの入力状態を検出できるので,ゲームやエディタ,ワープロなどにもってこいの機能を作り出すことができます.
===================================
3.1 キーの押下状態をチェックするINP関数
入力ポートのポート番号とキーボードのキーの対応は図3−1(省略)のようになっています.PC-9801のキーボードはいくつかのキーコードグループに分けられ,さらにこのキーコードグループは8つのキーからなっています.そのため,すべてのキーは各グループごとに8ビット=1バイトで表現することができます.つまり,各キーは何組何番かが決まっているのです(例えば,E8組4番はグラフキー,E8組6番はシフトキー,E8組7番はコントロールキーなど).
(図3−1)
I/Oポート入出力関数INPはポート番号で指定された入力ポートから8ビットのデータを読み取り,それを関数値として戻します.これらのキーはプルアップされているのでOFFで1,ONで0です.すなわち,押されているキーのビットは0,押されていないキーのビットは1となっています.シフトキーだけが押されていると,そのときの入力ポート&HE8(16進)の状態は2進数で10111111となります.これは16進数で表わすと&HBFですから,INP(&HE8)=&HBFが成り立ちます.
ところが,ほかにもキーが押されているとき,等号は成り立ちません.INP関数については多くの解説がなされていますが,著者側の浅薄な理解,曲解,思い違いや解説の不備により,多くの読者に誤解を生んでいるのはこのためです.以下,複数のキーが同時に押されている場合のキー押下状態の検査法について述べますが,実用上はこの問題のほうがより重要な問題です.
===================================
一体どうなっているのかというと,シフトキーと同時に複数のキーが押されている場合には,入力ポート&HE8は
10111111
とはならず,
?0?????? (?は0または1)
の状態となります.
したがって,2つ以上のキーが同時に押されている場合であっても,シフトキーを押した時にはポート番号&HE8のデータはb6 ビットがONの状態ですから,2進数で01000000(=2^6:16進数で&H40)と対応するビットごとに論理積演算を行なうと上位ビットから下位ビットまですべてのビットが0になります[(INP(&HE8 AND &H40)=0].
(図3−2)
b7 b6 b5 b4 b3 b2 b1 b0
SHIFT ? 0 ? ? ? ? ? ?
× × × × × × × ×
&H40 0 1 0 0 0 0 0 0
↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
0 0 0 0 0 0 0 0 0
また,コントロールキーを押した場合にはI/Oポート&HE8のb7 ビットがONになりますから,(INP(&HE8 AND &H80)=0となります.この関係を利用してキーが押されているかどうかをキースキャンして判定します.
したがって,特殊キーに限らずどのようなキーであっても
IF (INP(&H@) AND &HA)=0 THEN 何々する
@に入力ポート番号,
Aに1,2,4,8,10,20,40,80
という書式にすると,そのキーのみが押されている場合であっても,同時にいくつものキーが押されている場合であっても,キーの押下状態をチェックすることができるのです.
===================================
3.2 インベーダーゲームの作成
INP関数の使い方が分かったところで,その応用例として簡単なインベーダーゲームを作成してみることにします.このプログラムは読者からの依頼により 佐藤佳弘著「ゲームで学ぶBASIC」(山海堂)
のプログラムを改造したもので,INP関数の使い方だけでなく同時にキーバッファクリアについて学ぶことを目的として収録しました.
プログラムはおなじみのUFOが左右に行ったり来たりする間に,UFO編隊から飛来するミサイル攻撃を避けながら地上のビーム砲でUFOを撃墜するという内容になっています.
ビーム砲を左右に移動させるには矢印キー[←][→],弾を発射するにはスペースキー[space]を使います.
IF (INP(&H@) AND &HA)=0 THEN 何々する
という書き方をしたのでビーム砲を動かしながら弾を発射することができるようになっています.
[←]:IF (INP(&HEA) AND &H4)=0 THEN 左へ移動
[→]:IF (INP(&HE8) AND &H4)=0 THEN 右へ移動
[space]:IF (INP(&HE9) AND &H40)=0 THEN 弾を発射
これをINKEY$を使って
[←]:IF INKEY$=CHR$(&H1D) THEN 左へ移動
[→]:IF INKEY$=CHR$(&H1C) THEN 右へ移動
[space]:IF INKEY$=" " THEN 弾を発射
のようにした場合は,キー入力された文字がいったんキーボードバッファに格納されるため動作に一瞬の間が生じます.INP関数を用いるといま押されているキーの状態をすぐに知ることができようになるため,動作が驚くほどよくなりゲームの高速化が図られます.また,INKEY$は1文字入力関数であるため複数のキーが押されている場合にすべてのキー入力を同時に検出することはできません.
===================================
【2】プログラムリストと解説
1000 '
1010 ' **** INVADER GAME ****
1020 ' 1993/01/14 coded
1030 ' 1993/02/10 modified
1040 ' 2003/04/27 modified for KOTARO
1050 ON STOP GOSUB *EXIT:STOP ON
1060 SCREEN 3,0:CONSOLE ,,0,1
1070 WIDTH 80,25:COLOR 6:CLS 3
1080 T$=TIME$:S$=RIGHT$(T$,2)
1090 SEED$=S$:SEED=VAL(SEED$)
1100 RANDOMIZE(SEED)
1110 '
1120 BOSS$=" UUU " : BOSS.CLEAR$=" "
1130 UFO$=" TTT " : UFO.CLEAR$=" "
1140 BEAM$=" XXX ": BEAM.CLEAR$=" "
1150 SHOT$="Y" : SHOT.CLEAR$=" "
1160 MISSILE$="V" : MISSILE.CLEAR$=" "
1170 DIM UFO$(3,8)
1180 FIRE=0
1190 MISS.SHOT=0
1200 DAMAGE=0
1210 SCORE=0
1220 REPEAT=1
1230 TIME0=0
1240 TIME.UP=10000
1250 '
1260 ' *** 主ルーチン ***
1270 '
1280 *MAIN:
1290 GOSUB *INIT
1300 FOR T=TIME0 TO TIME.UP
1310 LOCATE 65,0:PRINT "TIME=";T
1320 GOSUB *UFO.MOVE:IF (Y1 MOD 3)=0 THEN U=1
1330 IF U=1 THEN GOSUB *BOSS.MOVE
1340 GOSUB *LAG
1350 IF MISSILE1=0 OR MISSILE2=0 THEN GOSUB *MISSILE.SHOT
1360 GOSUB *KEYIN
1370 IF Z2<>0 THEN GOSUB *BEAM.MOVE
1380 IF S=1 THEN GOSUB *SHOT
1390 IF B>0 THEN GOSUB *HIT:GOSUB *MIN.MAX
1400 IF C>0 THEN GOSUB *BOSS.HIT
1410 IF MARK>24 THEN REPEAT=REPEAT+1:GOTO *MAIN
1420 GOSUB *MISSILE.MOVE
1430 NEXT T
1440 GOSUB *EXIT
1450 END
1460 '
1470 *LAG:LT=1000
1480 FOR LAG=1 TO LT:NEXT LAG
1490 RETURN
1500 '
1510 ' *** 初期画面 ***
1520 '
1530 *INIT:
1540 CLS 3
1550 COL=7
1560 FOR I=1 TO 3
1570 FOR J=1 TO 8:UFO$(I,J)=UFO$:NEXT J
1580 NEXT I
1590 IMIN=1:IMAX=3
1600 JMIN=1:JMAX=8
1610 HIT=0:MARK=0
1620 TIME0=T
1630 X1=0:Y1=1+(REPEAT-1)*2
1640 X2=(80-LEN(BEAM$))\2:Y2=24
1650 IF (Y1+(IMAX-1)*2+1)=(Y2-1) THEN GOSUB *EXIT
1660 ZW=1
1670 GOSUB *UFO.DRAW
1680 COLOR COL:LOCATE X2,Y2:PRINT BEAM$;:COLOR 6
1690 X6=0:Y6=1:U=0
1700 RETURN
1710 '
1720 ' *** UFO 表示 ***
1730 '
1740 *UFO.DRAW:
1750 FOR J=JMIN TO JMAX
1760 FOR I=IMIN TO IMAX
1770 LOCATE X1+(J-1)*5,Y1+(I-1)*2:PRINT UFO$(I,J);
1780 NEXT I
1790 NEXT J
1800 RETURN
1810 '
1820 ' *** UFO 消去 ***
1830 '
1840 *UFO.CLEAR:
1850 FOR J=JMIN TO JMAX
1860 FOR I=IMIN TO IMAX
1870 LOCATE X1+(J-1)*5,Y1+(I-1)*2:PRINT UFO.CLEAR$;
1880 NEXT I
1890 NEXT J
1900 RETURN
1910 '
1920 ' *** UFO 移動 ***
1930 '
1940 *UFO.MOVE:
1950 IF ZW=+1 THEN GOSUB *MOVE.RIGHT:GOTO 1970
1960 IF ZW=-1 THEN GOSUB *MOVE.LEFT
1970 IF (Y1+(IMAX-1)*2+1)=(Y2-1) THEN GOSUB *EXIT
1980 GOSUB *UFO.DRAW
1990 RETURN
2000 '
2010 ' *** UFO 右へ ***
2020 '
2030 *MOVE.RIGHT:
2040 X1=X1+1
2050 IF (X1+(JMAX-1)*5+4)>79 THEN X1=79-(JMAX-1)*5-4 :GOSUB *UFO.CLEAR:Y1=Y1+1:ZW=-1
2060 RETURN
2070 '
2080 ' *** UFO 左へ ***
2090 '
2100 *MOVE.LEFT:
2110 X1=X1-1
2120 IF (X1+(JMIN-1)*5)<0 THEN X1=-(JMIN-1)*5 :GOSUB *UFO.CLEAR:Y1=Y1+1:ZW=+1
2130 RETURN
2140 '
2150 ' *** BOSS 移動 ***
2160 '
2170 *BOSS.MOVE:
2180 X6=X6+1:LOCATE X6,Y6:COLOR 5:PRINT BOSS$:COLOR 6
2190 IF (X6+4)>79 THEN LOCATE X6,Y6:PRINT BOSS.CLEAR$:X6=0:U=0
2200 RETURN
2210 '
2220 ' *** キー入力 ***
2230 '
2240 *KEYIN:
2250 IF (INP(&HEA) AND &H4)=0 THEN Z2=-2
2260 IF (INP(&HE8) AND &H4)=0 THEN Z2=+2
2270 'IF S=0 AND (INP(&HE8) AND &H2)=0 THEN S=1:GOSUB *FIRE
2280 IF S=0 AND (INP(&HE9) AND &H40)=0 THEN S=1:GOSUB *FIRE
2290 RETURN
2300 '
2310 '*KEYIN:
2320 IF (INP(&HE0) AND &H10)=0 THEN Z2=-2
2330 IF (INP(&HE0) AND &H40)=0 THEN Z2=+2
2340 IF S=0 AND (INP(&HE0) AND &H20)=0 THEN S=1:GOSUB *FIRE
2350 RETURN
2360 '
2370 *KEYIN.1:
2380 IF INKEY$=CHR$(&H1D) THEN Z2=-2
2390 IF INKEY$=CHR$(&H1C) THEN Z2=+2
2400 'IF S=0 AND INKEY$=CHR$(&H1E) THEN S=1:GOSUB *FIRE
2410 IF S=0 AND INKEY$=" " THEN S=1:GOSUB *FIRE
2420 RETURN
2430 '
2440 ' *** ビーム砲移動 ***
2450 '
2460 *BEAM.MOVE:
2470 X2=X2+Z2:Z2=0
2480 IF X2>(79-LEN(BEAM$)) THEN X2=79-LEN(BEAM$)
2490 IF X2<0 THEN X2=0
2500 COLOR COL:LOCATE X2,Y2:PRINT BEAM$;:COLOR 6
2510 RETURN
2520 '
2530 ' *** 発射 ***
2540 '
2550 *FIRE:
2560 X3=X2+LEN(BEAM$)\2:Y3=Y2-1
2570 LOCATE X3,Y3:PRINT SHOT$;
2580 FIRE=FIRE+1
2590 RETURN
2600 '
2610 ' *** 弾の移動 ***
2620 '
2630 *SHOT:
2640 IF U=1 THEN 2730
2650 LOCATE X3,Y3:PRINT SHOT.CLEAR$;
2660 Y3=Y3-1
2670 IF Y3<(Y1+(IMIN-1)*2) THEN S=0:MISS.SHOT=MISS.SHOT+1:GOTO 2720
2680 LOCATE X3,Y3:PRINT SHOT$;
2690 IF Y3=Y1+4 THEN A1=3: GOSUB *BOMB: GOTO 2720
2700 IF Y3=Y1+2 THEN A1=2: GOSUB *BOMB: GOTO 2720
2710 IF Y3=Y1 THEN A1=1: GOSUB *BOMB
2720 RETURN
2730 '
2740 LOCATE X3,Y3:PRINT SHOT.CLEAR$;
2750 Y3=Y3-1
2760 IF Y3<Y6 THEN S=0:MISS.SHOT=MISS.SHOT+1:GOTO 2820
2770 LOCATE X3,Y3:PRINT SHOT$;
2780 IF Y3=Y1+4 THEN A1=3: GOSUB *BOMB: GOTO 2820
2790 IF Y3=Y1+2 THEN A1=2: GOSUB *BOMB: GOTO 2820
2800 IF Y3=Y1 THEN A1=1: GOSUB *BOMB: GOTO 2820
2810 IF Y3=Y6 THEN GOSUB *BOSS.BOMB
2820 RETURN
2830 '
2840 ' *** 命中の判定 ***
2850 '
2860 *BOMB:
2870 B1=INT((X3-X1-1)/5)+1
2880 B2=(X3-X1-1)-INT((X3-X1-1)/5)*5+1
2890 IF B1<1 OR B1>8 THEN B=0:GOTO 2930
2900 IF UFO$(A1,B1)=UFO.CLEAR$ THEN B=0:GOTO 2930
2910 IF B2=2 THEN B=2
2920 IF B2=1 OR B2=3 THEN B=1
2930 RETURN
2940 '
2950 *BOSS.BOMB:
2960 C1=INT((X3-X6-1)/5)+1
2970 C2=(X3-X6-1)-INT((X3-X6-1)/5)*5+1
2980 IF C1<>1 THEN C=0:GOTO 3020
2990 IF C2=2 THEN C=8
3000 IF C2=1 OR C2=3 THEN C=4
3010 LOCATE X6,Y6:PRINT BOSS.CLEAR$:X6=0:U=0
3020 RETURN
3030 '
3040 ' *** 爆音 ***
3050 '
3060 *HIT:
3070 FOR I=0 TO 50:BEEP 1:BEEP 0:NEXT I
3080 UFO$(A1,B1)=UFO.CLEAR$
3090 GOSUB *UFO.DRAW
3100 SCORE=SCORE+B
3110 MARK=MARK+B
3120 HIT=HIT+1
3130 S=0:B=0
3140 RETURN
3150 '
3160 *BOSS.HIT:
3170 FOR I=0 TO 50:BEEP 1:BEEP 0:NEXT I
3180 SCORE=SCORE+C
3190 MARK=MARK+C
3200 HIT=HIT+1
3210 S=0:C=0
3220 RETURN
3230 '
3240 ' *** UFO 編隊 ***
3250 '
3260 *MIN.MAX:
3270 IMAX0=IMIN:IMIN0=IMAX
3280 JMAX0=JMIN:JMIN0=JMAX
3290 FOR I=IMIN TO IMAX
3300 FOR J=JMIN TO JMAX
3310 IF UFO$(I,J)=UFO.CLEAR$ THEN 3360
3320 IF IMAX0<I THEN IMAX0=I
3330 IF IMIN0>I THEN IMIN0=I
3340 IF JMAX0<J THEN JMAX0=J
3350 IF JMIN0>J THEN JMIN0=J
3360 NEXT J
3370 NEXT I
3380 IMAX=IMAX0:IMIN=IMIN0
3390 JMAX=JMAX0:JMIN=JMIN0
3400 RETURN
3410 '
3420 ' *** UFO ミサイル ***
3430 '
3440 *MISSILE.SHOT:
3450 IF MISSILE1=1 THEN 3540
3460 RD=INT(RND(1)*(JMAX-JMIN))+JMIN
3470 X4=X1+(RD-1)*5+2
3480 IF UFO$(3,RD)=UFO$ THEN Y4=Y1+5:GOTO 3520
3490 IF UFO$(2,RD)=UFO$ THEN Y4=Y1+3:GOTO 3520
3500 IF UFO$(1,RD)=UFO$ THEN Y4=Y1+1:GOTO 3520
3510 GOTO 3460
3520 LOCATE X4,Y4:PRINT MISSILE$;
3530 MISSILE1=1
3540 '
3550 IF MISSILE2=1 THEN 3640
3560 RD=INT(RND(1)*(JMAX-JMIN))+JMIN
3570 X5=X1+(RD-1)*5+2
3580 IF UFO$(3,RD)=UFO$ THEN Y5=Y1+5:GOTO 3620
3590 IF UFO$(2,RD)=UFO$ THEN Y5=Y1+3:GOTO 3620
3600 IF UFO$(1,RD)=UFO$ THEN Y5=Y1+1:GOTO 3620
3610 GOTO 3560
3620 LOCATE X5,Y5:PRINT MISSILE$;
3630 MISSILE2=1
3640 RETURN
3650 '
3660 ' *** ミサイル移動 ***
3670 '
3680 *MISSILE.MOVE:
3690 IF MISSILE1=0 THEN 3750
3700 LOCATE X4,Y4:PRINT MISSILE.CLEAR$;
3710 Y4=Y4+1
3720 IF Y4>Y2 THEN MISSILE1=0:GOTO 3750
3730 LOCATE X4,Y4:PRINT MISSILE$;
3740 IF Y4=Y2 THEN GOSUB *MISSILE1.BOMB
3750 '
3760 IF MISSILE2=0 THEN 3820
3770 LOCATE X5,Y5:PRINT MISSILE.CLEAR$;
3780 Y5=Y5+1
3790 IF Y5>Y2 THEN MISSILE2=0:GOTO 3820
3800 LOCATE X5,Y5:PRINT MISSILE$;
3810 IF Y5=Y2 THEN GOSUB *MISSILE2.BOMB
3820 RETURN
3830 '
3840 ' *** ミサイル命中 ***
3850 '
3860 *MISSILE1.BOMB:
3870 IF X4<(X2+2) THEN 3910
3880 IF X4>(X2+4) THEN 3910
3890 GOSUB *MISSILE.HIT
3900 MISSILE1=0
3910 RETURN
3920 '
3930 *MISSILE2.BOMB:
3940 IF X5<(X2+2) THEN 3980
3950 IF X5>(X2+4) THEN 3980
3960 GOSUB *MISSILE.HIT
3970 MISSILE2=0
3980 RETURN
3990 '
4000 ' *** ミサイル爆発 ***
4010 '
4020 *MISSILE.HIT:
4030 FOR I=0 TO 50:BEEP 1:BEEP 0:NEXT I
4040 DAMAGE=DAMAGE+1
4050 COL=COL-1:IF COL=0 THEN GOSUB *EXIT
4060 COLOR COL:LOCATE X2,Y2:PRINT BEAM$;:COLOR 6
4070 RETURN
4080 '
4090 ' *** 終了処理 ***
4100 '
4110 *EXIT:
4120 CLS 3
4130 COLOR 5
4140 PRINT
4150 PRINT "GAME OVER !"
4160 PRINT
4170 PRINT "TIME=";T
4180 PRINT "SCREEN=";REPEAT
4190 PRINT
4200 PRINT "FIRE=";FIRE
4210 PRINT "HIT=";FIRE-MISS.SHOT
4220 PRINT "DAMAGE=";DAMAGE
4230 PRINT
4240 PRINT "SCORE=";SCORE
4250 PRINT
4260 COLOR 7:STOP OFF
4270 WHILE INKEY$<>"":WEND
4280 RETURN 1450
(X1,Y1)はUFO編隊,(X2,Y2)ビーム砲,(X3,Y3)はビーム砲から発射された弾,(X4,Y4),(X5,Y5)はUFOからのミサイル,(X6,Y6)が一番上を飛んでいるボスUFOの位置を示す変数です.
このゲームではUFOやビーム砲が動いていますが,それらを表示するときにいっしょに空白も表示して前に表示したキャラクタを消しているのがミソです.それを繰り返すのでアニメのように画面上の位置が変化し動いているように見えるのです.また,ビーム砲を守る砦はありません,そのかわり,UFOからのミサイルの被弾が7発まではゲームオーバーしないように設定してあります(1550行).
1470行〜1490行では実行に時間がかかるようにわざと余分なFOR〜NEXTループを入れています.これを入力しない場合,UFOの移動は速すぎて目で追うこともできません.余分な時間(ラグタイム:変数名LT)を小さくすればUFOは速く動くようになります.
UFOの位置と弾の位置を比較して一致したときが命中したときです.ザコUFOのど真ん中に命中したときは2点,ひとつずれたところに命中したときは1点,また,ボスUFOのど真ん中に命中したときは8点,ひとつずれたところに命中したときは4点を得点とします.ゲームの難易度を高くするためには,1410行でクリアレベル(既定値:24)を高くしてやります.
命中の判定には整数の割り算の余りを求めるMOD関数や商を求める\を使いますが,このプログラムの場合は負の整数も扱うため\とMODを用いることはできません.負の整数除についても取り扱いを拡張するには,(I\5)の代わりにINT(I/5),(I MOD 5)にかわる命令としてI-INT(I/5)*5によって代用します.
なお,画面の右上に表示される数字は時間ではなく,正確にはFOR〜NEXTループの繰り返し回数です.FOR〜NEXTループの制御変数は整数か単精度実数を用いなければなりません.倍精度実数にするとループの管理がおかしくなってしまいます.
また,このプログラムでは4270行でキーバッファクリアを行なっています.N88-BASIC(86)にはキーバッファがあり,Ver.6以降では256バイトまでのキーの先行入力(先打ち)が可能でたいへん重宝な機能になっています.ところが,ファイルを削除する場合などでは先行入力によってファイルを不用意に削除してしまうことがあり,そうなると被害甚大です.そのため,プログラム実行中に不要な先行入力を避けたい場合には適所適所でキーバッファをクリアすることが必要です.
キーバッファは,WHILE INKEY$<>"":WENDでクリアされ,簡単に先打ちを無効にすることができます.このプログラムのようにカーソル移動キーを用いたプログラムでは適宜キーバッファをクリアしないとプログラム終了時にカーソルが予期せぬ位置に移動していることになります.
===================================