子どもの頃に地面やアスファルトに書いて遊んだ人が多いと思う「三目並べ」を作ってみました。
遊び方
- プログラムを動かすと、3×3のます目が表示されます。自分(YOU)かコンピュータ(CPU)か、ランダムにどちらかが先手になります。
- 自分(YOU)の手の時は、上下左右の矢印キーでカーソルを移動して、スペースキーで打ってください。自分の手は「○」(丸)で表示されます。
- コンピュータ(CPU)の手の時は、プログラムが自動で考えて手を打ってきます。コンピュータの手は「×」で表示されます。
- どちらかの手が、縦・横・斜めのどこかで三目そろうと、そのプレイヤーの勝利(WIN)です。どちらもそろわずに9手が終わった場合は引き分け(DRAW)です。
プログラム
1 '*3MOKU 2 CLV:VIDEO 5:CLS 3 LET [10],7,3,11,3,15,3,11,3,7 4 FOR N=1 TO 3:?"...":NEXT 5 IF RND(2) GOTO 14 6 LC 0,3:?"YOU" 7 X=X-BTN(28)*(X>0)+BTN(29)*(X<2) 8 Y=Y-BTN(30)*(Y>0)+BTN(31)*(Y<2) 9 LC X,Y,1:Z=X+Y*3:WAIT 5 10 IF !BTN(32) OR [Z]!=0 GOTO 7 11 [Z]=1:LC X,Y:?"O":S=S+1:BEEP 12 T=1:GSB 30 13 IF E=3 OR S=9 GOTO 26 14 LC 0,3:?"CPU" 15 G=0:H=0:T=-1 16 FOR Y=0 TO 2 17 FOR X=0 TO 2 18 GSB 30 19 W=[Z+10]+E*E*20+F*F*10 20 IF W>H && [Z]=0 G=Z:H=W 21 NEXT:NEXT 22 Z=G:X=Z%3:Y=Z/3 23 [Z]=-1:LC X,Y:?"X":S=S+1:BEEP 30 24 T=-1:GSB 30 25 IF E!=3 && S!=9 GOTO 6 26 LC 4,3 27 IF E=3 ?"WIN!";:BEEP 10,30 28 IF S=9 ?"DRAW";:BEEP 30,30 29 CLK:END 30 Z=X+Y*3:L=[Z+10]:E=0:F=0 31 FOR M=0 TO 3 32 C=0:D=0 33 IF L&(1<<M) GSB LINE()+4+M*3 34 IF C>E E=C 35 IF D>F F=D 36 NEXT:RTN 37 FOR U=0 TO 2 38 A=[U+Y*3]:GSB 49 39 NEXT:RTN 40 FOR V=0 TO 2 41 A=[X+V*3]:GSB 49 42 NEXT:RTN 43 FOR U=0 TO 2 44 A=[U*4]:GSB 49 45 NEXT:RTN 46 FOR U=0 TO 2 47 A=[2+U*2]:GSB 49 48 NEXT:RTN 49 C=C+(A=T):D=D+(A=-T):RTN
ネットを検索して調べると、「三目並べ」はプログラミングの課題として有名なようで、再帰呼び出しで全ての手(パターン)を調べてコストを計算して…とCPUの最善手を考えるようです。
このプログラムのCPUは、人間と同様に「縦・横・斜めの列の可能性が多い所へ打つ」「自分が3個そろいそうな所へ打つ」「相手が3個そろいそうだったら止める」という思考で、何とか1kバイトに収めました。
CPUもかなり完璧に考えるので、人間が真剣にプレイすると全てのゲームがドローになります。そうか、それでつまらないから、IchigoJamの三目並べのプログラムが今まで無かったんだな…(^_^;)
プログラム説明追記
IJUtilitiesで行番号追加・ラベル削除する前のリストを掲載します。
思考系ゲームを作る方の参考になれば嬉しいです。
'*3MOKU CLV:VIDEO 5:CLS LET [10],7,3,11,3,15,3,11,3,7 FOR N=1 TO 3:?"...":NEXT IF RND(2) GOTO @CPU @YOU LC 0,3:?"YOU" @YLOOP X=X-BTN(28)*(X>0)+BTN(29)*(X<2) Y=Y-BTN(30)*(Y>0)+BTN(31)*(Y<2) LC X,Y,1:Z=X+Y*3:WAIT 5 IF !BTN(32) OR [Z]!=0 GOTO @YLOOP [Z]=1:LC X,Y:?"O":S=S+1:BEEP T=1:GSB @CHK IF E=3 OR S=9 GOTO @GEND @CPU LC 0,3:?"CPU" G=0:H=0:T=-1 FOR Y=0 TO 2 FOR X=0 TO 2 GSB @CHK W=[Z+10]+E*E*20+F*F*10 IF W>H && [Z]=0 G=Z:H=W NEXT:NEXT Z=G:X=Z%3:Y=Z/3 [Z]=-1:LC X,Y:?"X":S=S+1:BEEP 30 T=-1:GSB @CHK IF E!=3 && S!=9 GOTO @YOU @GEND LC 4,3 IF E=3 ?"WIN!";:BEEP 10,30 IF S=9 ?"DRAW";:BEEP 30,30 CLK:END @CHK Z=X+Y*3:L=[Z+10]:E=0:F=0 FOR M=0 TO 3 C=0:D=0 IF L&(1<<M) GSB LINE()+4+M*3 IF C>E E=C IF D>F F=D NEXT:RTN @CHKX FOR U=0 TO 2 A=[U+Y*3]:GSB @CHKT NEXT:RTN @CHKY FOR V=0 TO 2 A=[X+V*3]:GSB @CHKT NEXT:RTN @CHKXY FOR U=0 TO 2 A=[U*4]:GSB @CHKT NEXT:RTN @CHKYX FOR U=0 TO 2 A=[2+U*2]:GSB @CHKT NEXT:RTN @CHKT C=C+(A=T):D=D+(A=-T):RTN
配列変数[0]~[8]で、9個のマスの値を記憶します。(0=打たれていない、1=YOU、-1=CPU)
012
345
678
3行目のLETでの配列値の設定は、各マス目(0~8、添字は+10)の横(X)・縦(Y)・斜め(XY・YX)の列判定方向を表します。それぞれビット0・1・2・3です。
@CPUからの10数行がCPU思考部分です。9マスそれぞれで@CHKからの重み付け計算ルーチンを呼び出し、計算した重みに列判定配列の値も加算。最終的に重みが一番大きいマスへ打ちます。
@CHKからのマス目重み付け計算ルーチンでは、上記の列判定配列値を元に、@CHKX(横)、@CHKY(縦)、@CHKXY・@CHKYX(斜め)のサブルーチンを呼び出し、それぞれの列でYOUの石とCPUの石をカウントして、その最大値を返します。
この@CHK以下のルーチンは、両者の手を打った後の勝利判定にも共用していて、それで何とか1kバイトに収めています。