見出し画像

【# 】ORANGE pico で○×ゲーム

#クリエイターフェス 1日目の記事です。

noteクリエイターフェスティバル2023

CREATOR FESTIVAL とやらが開催されているらしい。
ハッシュタグ #クリエイターフェス を付けた記事を10個投稿すると、プレゼントが当たる可能性が発生するらしい。

noteクリエイターフェスティバル2023|note(ノート)

何を書こうか考えた結果、「#クリエイターフェス」がちょうど10文字なので、それぞれにちなんだ記事を書くことにした。
題材は、あまり情報が出ていなくて流行っていなそうに思える ORANGE pico を応援するため、ORANGE pico 向けのプログラムを書くことにした。

ORANGE pico

ORANGE pico は、USB電源・コンポジット信号 (NTSC) に対応したモニター・PS/2対応キーボードを接続することで、BASIC言語によるプログラミングができる製品である。
対応インターフェイス (接続端子) の違いによりいくつかの種類があり、いずれも (記事執筆時点で) 数千円で購入することができる。(ただし完売しているために購入できない種類もあるようである)

○×ゲーム

今回のテーマは、「#クリエイターフェス」の1文字目「#」だ。
これが○×ゲームで使う枠に似ていることから、今回は○×ゲームを作ることにした。

タイトル画面

○×ゲーム タイトル画面

Qキー・Aキーで先攻の○の設定を変えることができる。
Eキー・Dキーで後攻の×の設定を変えることができる。
Sキーでゲームを開始できる。

各設定は、以下の仕様になっている。

  • MANUAL

    • 手動で操作する。盤面に表示されるキーを押すことで、そこに○や×を置くことができる。

  • CPU EASY

    • 置ける場所からランダムに置く場所を選ぶ。

  • CPU NORMAL

    • この手番で勝ちを決められるときは、決める。そうでなく、相手に次の手番で勝ちを決められそうなときは、防ぐ。どっちでもないときは、置ける場所からランダムに置く場所を選ぶ。

  • CPU HARD

    • ミニマックス法を用いた探索により置く場所を決定する。ただし、時間がかかりすぎるのを防ぐために最初の2手については探索結果を埋め込んである。

ゲーム画面

○×ゲーム ゲーム画面 (開始)

先ほどのタイトル画面でSキーを押した直後の状態。
置ける場所に対応するキーが表示されている。

○×ゲーム ゲーム画面 (途中)

Sキーを押し、真ん中に○を置いた。
相手が右上に×を置き、また自分の番が回ってきた。

○×ゲーム ゲーム画面 (結果)

ゲームを進めた結果、今回は引き分けになった。
Rキーを押すと同じ設定で再戦でき、Tキーを押すとタイトル画面に戻ることができる。

○×ゲーム ゲーム画面 (勝利)

今度は勝つことができた。

プログラム

10 dim board(9):dim work(9):color=rgb(255,255,255):okind=0:xkind=2
20 cls
30 locate 16,4:print "OX GAME"
40 locate 7,7:print "O (1st)"
50 locate 4,9:print "Q^"
60 locate 4,16:print "Av"
70 locate 24,7:print "X (2nd)"
80 locate 21,9:print "E^"
90 locate 21,16:print "Dv"
100 for i=0 to 1
110 x=7+17*i
120 locate x,11:print "MANUAL"
130 locate x,12:print "CPU EASY"
140 locate x,13:print "CPU NORMAL"
150 locate x,14:print "CPU HARD"
160 next
170 locate 12,19:print "PRESS S TO START"
180 locate 5,11+okind:print "*"
190 locate 22,11+xkind:print "*"
200 key=instr("qaeds",chr$(inkey()|&H20))
210 if key=1 then locate 5,11+okind:print " ":okind=(okind+3)%4:goto 180
220 if key=2 then locate 5,11+okind:print " ":okind=(okind+1)%4:goto 180
230 if key=3 then locate 22,11+xkind:print " ":xkind=(xkind+3)%4:goto 180
240 if key=4 then locate 22,11+xkind:print " ":xkind=(xkind+1)%4:goto 180
250 if key=5 then goto 270
260 goto 200
270 player=1
280 for i=0 to 8
290 board(i)=0
300 next
310 cls
320 line 70,70,250,70,color:line 70,130,250,130,color
330 line 130,10,130,190,color:line 190,10,190,190,color
340 if player=1 then engine=okind else engine=xkind
350 for i=0 to 2
360 for j=0 to 2
370 status=board(i*3+j):x=100+60*j:y=40+60*i
380 if status=0 and engine=0 then gprint x-4,y-4,mid$("QWEASDZXC",i*3+j+1,1),color
390 if status=1 then circle x,y,20,color
400 if status=2 then line x-20,y-20,x+20,y+20,color:line x+20,y-20,x-20,y+20,color
410 next
420 next
430 gosub 1000
440 judge=pop()
450 if judge=1 then gprint 31,88,"O",color:gprint 19,104,"WIN!",color:goto 580
460 if judge=2 then gprint 281,88,"X",color:gprint 269,104,"WIN!",color:goto 580
470 if judge=-1 then gprint 15,96,"DRAW!",color:gprint 265,96,"DRAW!",color:goto 580
480 if player=1 then gprint 23,88,"O's",color:gprint 19,104,"TURN",color
490 if player=2 then gprint 273,88,"X's",color:gprint 269,104,"TURN",color
500 if engine=0 then gosub 2000
510 if engine=1 then gosub 3000
520 if engine=2 then gosub 4000
530 if engine=3 then gosub 5000
540 place=pop()
550 board(place)=player
560 player=player%2+1
570 goto 310
580 gprint 7,146,"R:RETRY",color
590 gprint 257,146,"T:TITLE",color
600 key=inkey()|&H20
610 if key=asc("r") then goto 270
620 if key=asc("t") then goto 20
630 goto 600

1000 ' JUDGE
1010 if board(0)=0 then goto 1050
1020 if board(0)=board(1) and board(0)=board(2) then return board(0)
1030 if board(0)=board(3) and board(0)=board(6) then return board(0)
1040 if board(0)=board(4) and board(0)=board(8) then return board(0)
1050 if board(4)=0 then goto 1090
1060 if board(4)=board(1) and board(4)=board(7) then return board(4)
1070 if board(4)=board(3) and board(4)=board(5) then return board(4)
1080 if board(4)=board(2) and board(4)=board(6) then return board(4)
1090 if board(8)=0 then goto 1120
1100 if board(8)=board(5) and board(8)=board(2) then return board(8)
1110 if board(8)=board(7) and board(8)=board(6) then return board(8)
1120 result=-1
1130 for check=0 to 8
1140 if board(check)=0 then result=0
1150 next
1160 return result

2000 ' MANUAL
2010 key=instr("qweasdzxc",chr$(inkey()|&H20))-1
2020 if key<0 then goto 2010
2030 if board(key)<>0 then goto 2010
2040 return key

3000 ' CPU EASY
3010 cnt=0
3020 for i=0 to 8
3030 if board(i)=0 then work(cnt)=i:cnt=cnt+1
3040 next
3050 pause 500
3060 return work(rnd(cnt))

4000 ' CPU NORMAL
4010 score=0
4020 cnt=0
4030 for i=0 to 2
4040 for j=0 to 2
4050 if board(i*3+j)<>0 then goto 4260
4060 sa=0:sb=0:sc=0:sd=0
4070 for k=-2 to 2
4080 if i+k<0 or 2<i+k then goto 4100
4090 cur=board((i+k)*3+j):sa=sa+(cur=player)-(cur<>0)*(cur<>player)
4100 if j+k<0 or 2<j+k then goto 4120
4110 cur=board(i*3+(j+k)):sb=sb+(cur=player)-(cur<>0)*(cur<>player)
4120 if i+k<0 or 2<i+k or j+k<0 or 2<j+k then goto 4140
4130 cur=board((i+k)*3+(j+k)):sc=sc+(cur=player)-(cur<>0)*(cur<>player)
4140 if i+k<0 or 2<i+k or j-k<0 or 2<j-k then goto 4160
4150 cur=board((i+k)*3+(j-k)):sd=sd+(cur=player)-(cur<>0)*(cur<>player)
4160 next
4170 if sa<2 and sb<2 and sc<2 and sd<2 then goto 4200
4180 if score<2 then score=2:cnt=0
4190 goto 4250
4200 if score>1 then goto 4260
4210 if sa>-2 and sb>-2 and sc>-2 and sd>-2 then goto 4240
4220 if score<1 then score=1:cnt=0
4230 goto 4250
4240 if score>0 then goto 4260
4250 work(cnt)=i*3+j:cnt=cnt+1
4260 next
4270 next
4280 pause 500
4290 return work(rnd(cnt))

5000 ' CPU HARD
5010 score=-1
5020 cnt=0
5030 for i=0 to 8
5040 if board(i)<>0 then cnt=cnt+1
5050 next
5060 if cnt<2 goto 5380
5070 for i=0 to 8
5080 if board(i)<>0 then goto 5160
5090 board(i)=player
5100 gosub 5190,player%2+1
5110 res=-pop()
5120 board(i)=0
5130 if res<score then goto 5160
5140 if res>score then score=res:cnt=0
5150 work(cnt)=i:cnt=cnt+1
5160 next
5170 pause 500
5180 return work(rnd(cnt))
5190 me=pop()
5200 gosub 1000
5210 judge=pop()
5220 if judge=me then return 1
5230 if judge>0 then return -1
5240 if judge<0 then return 0
5250 maxscore=-1
5260 for h=0 to 8
5270 if maxscore=1 then goto 5360
5280 if board(h)<>0 then goto 5360
5290 board(h)=me
5300 push me:push maxscore:push h
5310 gosub 5190,me%2+1
5320 res=-pop()
5330 h=pop():maxscore=pop():me=pop()
5340 board(h)=0
5350 if res>maxscore then maxscore=res
5360 next
5370 return maxscore
5380 if cnt>0 then goto 5430
5390 for i=0 to 8
5400 work(i)=i
5410 next
5420 cnt=9:goto 5170
5430 if board(0)=0 and board(2)=0 and board(6)=0 and board(8)=0 then goto 5450
5440 work(0)=4:cnt=1:goto 5170
5450 if board(4)=0 then goto 5470
5460 work(0)=0:work(1)=2:work(2)=6:work(3)=8:cnt=4:goto 5170
5470 if board(1)=0 then goto 5490
5480 work(0)=0:work(1)=2:work(2)=4:work(3)=7:cnt=4:goto 5170
5490 if board(3)=0 then goto 5510
5500 work(0)=0:work(1)=4:work(2)=5:work(3)=6:cnt=4:goto 5170
5510 if board(5)=0 then goto 5530
5520 work(0)=2:work(1)=3:work(2)=4:work(3)=8:cnt=4:goto 5170
5530 work(0)=1:work(1)=4:work(2)=6:work(3)=8:cnt=4:goto 5170

改造のヒント

このプログラムには、まだ改良の余地があるだろう。
たとえば、以下のものが考えられる。

  • タイトル画面をテキスト画面ではなくグラフィック画面で表現する (TFT液晶対応)

  • 勝利時に揃ったラインをハイライトする

  • 通信対戦に対応する

  • 対戦終了時、キーを押さなくても自動で再戦できるようにする (フルオート鑑賞モード)

  • 効果音をつける

これらは読者への宿題とする。

ライセンス

今回のプログラムと解説 (「○×ゲーム」節の内容) は、CC BY 4.0 でライセンスする。


この記事が気に入ったらサポートをしてみませんか?