カテゴリ: IchigoJam

  • タイトル
    インベーダー

  • 開発環境
    IchigojamBASIC1.2.1

  • 内容
    宇宙からインベーダーが大挙して攻めてきます。
    あなたは地球を守るためインベーダーを迎撃しなくてはなりません。
    invader
  • 遊び方
    画面上方から徐々に侵略してくるインベーダーを、画面下部の砲台よりミサイルを打って撃墜してください。
    インベーダーの攻撃に当たる、もしくはインベーダーが地上に着いて地球侵略された時点でゲームオーバーです。

  • 操作方法
    [1]キー 左移動
    [2]キー 右移動
    [スペース]キー ミサイル発射

  • プログラムのしくみ
    機械語部分(プログラム1)とBASIC部分(プログラム2)に分かれています。

    プログラム1の2行目はキャラクタ設定を行っています。

    機械語部分はBASE16というエンコード方法で変換されています。
    (8bitのうち上位4bitと下位4bitをそれぞれ@~Oの文字に変換)

    インベーダーの動き、インベーダーのミサイル、自機のミサイルなど、処理速度が必要な部分を機械語で処理しています。
    画面描画、自機の動き、UFOの発生、得点、サウンドなど比較的処理速度の必要でない部分をBASICで処理しています。

    変数については、変数領域の半分くらいまで機械語プログラムが書き込まれているため、変数の後半(Z~W)のみを使用しています。


  • 機械語プログラム(プログラム1)
    機械語ルーチンへの渡し値
    #770-#771自機ミサイル位置
    #77E面クリアフラグ
    #77Fインベーダー移動方向
    機械語ルーチンから戻り値(USR関数)
    1Invader撃墜
    2UFO撃墜
    #FF自機被弾

    キャラクタ表
    #E0上段インベーダー
    #E1中段インベーダー
    #E2下段インベーダー
    #E3敵ミサイル
    #E4自ミサイル
    #E5砲台
    #E6UFO
    #E7爆発

    画面構成
    #900-#91FSCORE
    #920-#93FUFO
    #920-BE0Invaders
    #BE0-BFFSHIP

    BASICプログラム(プログラム2)
    変数一覧表
    Z点数
    Y得点(1or2)またはゲームオーバーフラグ(=#FF)
    X自機の位置
    Wループ用


    各行の処理
    10行コメント行
    20行キャラクタ定義
    30行点数クリア
    40行初期設定()
    50行初期画面描画
    60行インベーダー移動
    70行面クリア判定
    80行インベーダーのミサイル移動
    90行自機のミサイル移動
    100行キー入力:ミサイル発射
    110行自機左右移動
    120行自機描画
    130行インベーダーのミサイル発生
    140行UFO出現
    150行繰り返し
    160行ゲームオーバー判定:加点処理

    機械語処理については、機械語プログラムのコメントを参照してください。

  • (5)プログラムの具体的な入力方法
    機械語部分は入力を間違えると操作不能になってしまうので、間違えないようにしてください。
    もしプログラムを実行して操作不能になってしまった場合は、一度IchigoJamの電源を切ってから再度電源を入れ直してください。

    まずプログラム1を入力して保存、次にプログラム2を入力してしてください。
    遊ぶ時は、まずプログラム1をロードして実行します。するとメモリ内に機械語プログラムが書き込まれます。
    次にプログラム2をロードして実行しするとゲームが始まります。
    プログラム1の8行目のendを「LRUN(プログラム2の保存番号)」に変更すると、プログラム1を実行後に自動でプログラム2を読み込み実行させることができます。

  • プログラムの改造
    プログラム2(BASICプログラム)の数値の変更による難易度変更は下記の通りです。

    80行のFOR文のループ数を大きくすると、自機ミサイルの速度が上がります。
    同じく80行のWAIT文の式を変更するとインベーダーの移動速度が変わります。(現在は点数に連動)
    120行のWの値を変えるとインベーダーのミサイルの発生率が変わります。
    130行のWの値を変えるとUFOの発生率が変わります。

    他の改造については、BASIC部分にメモリの余裕があるので改造しやすいと思います。
    (例:自機数を増やす、面ごとにインベーダーの初期描画位置を下げるなど)

    変数領域まで機械語プログラムが書き込まれているため、改造の際は使用する変数をK以後にしてください。
インベーダー(プログラム1)
1'invader1
2CLS:CLP:CLV:W=#50:LET[0],#0B,#EC,#ED,#F2,#1E,#F0,#F1,#F4:FORZ=0TO7:COPY(#E0+Z)*8,[Z]*8,8:NEXT
3Z="G@KD@@BFIABDBD@A@OCDFCAHAJGHN@BJ@AMKNBBJA@MMEJGHN@BJ@AMKNBBJ@KMMB@CDBE@IKOBMO@MKGGBDBD@A@OCDFBEL@@BJBAM@@ABJCFM@KOBDBD@AFEAHBJGHN@BJ@KMKNBBJ@IMLBC@IKLBKABMJ@@BC":Y=#780:GSB9
4Z="BKG@B@CEBKGHNEBK@LM@BJG@@ACLBE@II@BMNKMAGGBDBD@A@OCDFBEL@ABCEJD@FBEDMINGOOB@BLN@KOBDBD@AFDAHBBGHN@BJ@JMKNBBJ@HMLAFALFCGHNDBK@AMA@AB@@@BBFBG@@@BBBBG@@ACLFCAJAK@J":Y=#7D0:GSB9
5Z="@HBKNLMAAEN@IBBDBD@AFDAHFBGHN@BJ@JMKNBBJ@HMLAFALBCGHNDBK@AMA@AB@@@BBBBG@@@BBFBG@@ACDFCAJAK@IKOBKNLMAGGBBAB@A@NCBEFEDG@KLG@DG@@@@C@KDB@BEKOBDBD@A@OCDFDAHBBGHNCBJ":Y=#820:GSB9
6Z="@LMA@@BCBCG@FCAJAK@IKNBK@FMJFCEM@@BK@BM@NEBK@AMAOOB@FBEE@ACLFCAJAK@IIABKNJMAC@KLG@DG@@@@@@@@@@@@G@KDGGBEBM@AFLEJ@@BLAEM@@@BFFFEDB@CLBBDFBC@IIBBK@NMKNDBCFBEL@BB@":Y=#870:GSB9
7Z="NFBJ@FM@@@B@BFDFN@BJ@DMKNCBJ@BML@AB@@@BC@@BFFCEDFNEBG@KLG@DG":Y=#8C0:W=#1E:GSB9
8END
9FORX=YTOY+W-1:POKEX,PEEK(Z)&15<<4+PEEK(Z+1)&15:Z=Z+2:?"#";HEX$(X),HEX$(PEEK(X)):NEXT:RTN

インベーダー(プログラム2)
10 'invader2
20 POKE#E0*8,#42,#24,#7E,#DB,#FF,#BD,#24,#42,#3C,#7E,#FF,#99,#FF,#FF,#66,#DB,#18,#3C,#7E,#DB,#FF,#5A,#81,#42
30 Z=0
40 CLS:?"SCORE:":LC8,0:?Z:POKE#770,0,0:POKE#77E,0,0:X=#BF0:POKEX,#E5
50 FORW=0TO4:FORY=0TO7:LCY*3+1,8-W*2+1:?CHR$(#E0+W/2):NEXT:POKE#B40+3+W*6,1,1,1:NEXT
60 Y=USR(#780,0):GSB160:BEEP255,1:IFYPOKE#770,0,0
70 IFPEEK(#77E)=0LC10,10:?"CLEAR":PLAY"O4BO5GB":WAIT60:GOTO40
80 Y=USR(#860,0):GSB160
90 FORW=0TO4:Y=USR(#8A0,0):GSB160:WAIT(100-Z)/10
100 Y=INKEY()-50:POKE#1003,0:IFY=-18ANDPEEK(#771)=0THENPOKE#770,#C0+(X-#BE0),#0B:GOTO120
110 IFABS(Y)=1POKEX,0:X=X+Y:IFX<#BE0ORX>#BFFX=X-Y
120 POKEX,#E5:NEXT
130 W=3:Y=RND(#60*W):IFY%WIFPEEK(#A40+Y/W)=0POKE#A40+Y/W,#E3
140 W=#10:Y=RND(#20*W):IFPEEK(#920+Y/W)=#E6POKE#920+Y/W,0ELSEIFNOT(Y%W)IFPEEK(#920+Y/W)=0POKE#920+Y/W,#E6
150 GOTO60
160 IFYIFY=#FFPOKEX,#E7:LC10,10:?"GAME OVER":PLAY"C02EDC":ENDELSEZ=Z+Y:LC8,0:?Z
170 RTN

プログラム1のアセンブラリスト
'インベーダー移動	usr(#780,0)
'左端、右端チェック処理
push	{r4,r5,r6}
mov	r6,0		'敵存在フラグクリア
mov	r4,#91
lsl	r4,r4,4
add	r4,#f		'探索VRAM=#91F:右端
@lr_loop_down
add	r3,r4,r1	'R3=実VRAM
ldrb	r2,[r3,0]	'右端キャラ
cmp	r2,#e0
blt	@l_chk_down	'R2<#E0なら左端をチェック
cmp	r2,#e2
ble	@vector_down	'R2<=#E2なら1段下げ処理へ
@l_chk_down
ldrb	r2,[r3,1]	'左端キャラ
cmp	r2,#e0
blt	@chk_add_down	'R2<#E0なら1行下チェックへ
cmp	r2,#e2
ble	@vector_down	'R2<=#E2なら1段下げ処理へ
@chk_add_down
add	r4,#20		'1行下
lsr	r5,r4,4
cmp	r5,#bf
blt	@lr_loop_down	'R4<#BF*ならループ

'左右移動に分岐処理
@lr_move
mov	r4,#77
lsl	r4,r4,4
add	r4,#f
ldrb	r2,[r4,r1]	'#7FF=インベーダー移動方向
cmp	r2,0		'0=右/1=左
beq	@inv_r_move	'右移動処理へ
cmp	r2,1
beq	@inv_l_move	'左移動処理へ

'1段下げる処理
@vector_down
mov	r4,#bf		'開始VRAM=#BF0
lsl	r4,r4,4
@loop_down		'1段下げループ
add	r5,r4,r1	'R5=実VRAM
ldrb	r2,[r5,0]
cmp	r2,#e0
blt	@add_down	'R2<#E0なら左隣チェックへ
cmp	r2,#e2
bgt	@add_down	'R2>#E2なら左隣アドレスへ
lsr	r3,r4,4	
cmp	r3,#bc		'#BC*=最下行
bge	@game_over	'R3>=#BC*ならゲームオーバー処理
mov	r3,0
strb	r3,[r5,0]	'元位置クリア
add	r5,#20
ldrb	r3,[r5,0]	'1段下のキャラ
cmp	r3,#e5
beq	@game_over	'1段下が砲台ならゲームオーバー処理
strb	r2,[r5,0]	'1段下にインベーダー描画
@add_down
sub	r4,1		'左隣のアドレス
lsr	r5,r4,4		'アドレス#90*
cmp	r5,#90
bne	@loop_down	'R5!=#90なら1段下げループへ

'進行方向逆転
mov	r4,#77
lsl	r4,r4,4
add	r4,#f
ldrb	r2,[r4,r1]	'#7FF=インベーダー移動方向
mov	r3,1		'0=右/1=左
eor	r2,r3		'0,1を反転
strb	r2,[r4,r1]
bla	@lr_move	'左右移動に分岐処理

'ゲームオーバー処理
@game_over
mov	r0,#FF		'ゲームオーバーフラグ
bla	@end

'右移動
@inv_r_move
mov	r4,#bf		'開始VRAM=#BF0
lsl	r4,r4,4
add	r4,r4,r1	'R4=実VRAM
@loop_rmov		'ループ開始
ldrb	r2,[r4,0]	'移動元のキャラクタ
cmp	r2,#e0
blt	@add_rmov	'R2<#E0なら左隣アドレスへ
cmp	r2,#e2
bgt	@add_rmov	'R2>#E2なら左隣アドレスへ
mov	r6,r2		'敵存在フラグ
ldrb	r3,[r4,1]	'移動先のキャラクタ
cmp	r3,#e4		'自弾
bne	@hit_rmov	'R3!=#E4ならキャラクタ移動へ
mov	r0,1		'撃墜フラグセット
mov	r2,0		'インベーダー消去
@hit_rmov
strb	r2,[r4,1]	'キャラクタを移動先に
mov	r2,0
strb	r2,[r4,0]	'元位置をクリア
@add_rmov
sub	r4,1		'左隣のアドレス
sub	r3,r4,r1
lsr	r3,r3,8
cmp	r3,8
bne	@loop_rmov	'R3!=#8**ならループへ
bla	@end

@inv_l_move
mov	r4,#92		'開始VRAM=#920
lsl	r4,r4,4
add	r4,r4,r1	'R4=実VRAM
@loop_lmov		'ループ開始
ldrb	r2,[r4,1]	'移動元のキャラクタ
cmp	r2,#e0
blt	@add_lmov	'R2<#E0なら右隣アドレスへ
cmp	r2,#e2
bgt	@add_lmov	'R2>#E2なら右隣アドレスへ
mov	r6,r2		'敵存在フラグ
ldrb	r3,[r4,0]	'移動先のキャラクタ
cmp	r3,#e4		'自弾
bne	@hit_lmov	'R3!=#E4ならキャラクタ移動へ
mov	r0,1		'撃墜フラグセット
mov	r2,0		'インベーダー消去
@hit_lmov
strb	r2,[r4,0]	'キャラクタを移動先に
mov	r2,0
strb	r2,[r4,1]	'元位置をクリア
@add_lmov
add	r4,1		'右隣のアドレス
sub	r3,r4,r1
lsr	r3,r3,4
cmp	r3,#bf
bne	@loop_lmov	'R3!=#BF*ならループへ

@end			'インベーダー移動終了処
mov	r2,#77
lsl	r2,r2,4
add	r2,#e		
strb	r6,[r2,r1]	'敵存在フラグ=#77E
pop	{r4,r5,r6}
ret

nop

'敵弾(全走査)		usr(#860,0)
push	{r4,r5}
mov	r5,#20		'1行のアドレス増分
mov	r4,#bf
lsl	r4,r4,4
add	r4,#f		'開始VRAM=#BFF
add	r4,r4,r1	'R4=実VRAM
@loop_bomb
ldrb	r2,[r4,0]	'移動元のキャラクタ
cmp	r2,#e3		'敵弾
bne	@no_bomb	'R2!=#E3なら左隣のアドレスへ
mov	r3,0
strb	r3,[r4,0]	'元位置クリア
sub	r3,r4,r1
lsr	r3,r3,4
cmp	r3,#be
bge	@no_bomb	'R3>=#BE*なら左隣のアドレスへ
ldrb	r3,[r4,r5]	'移動先のキャラ
cmp	r3,0
beq	@mov_bomb	'空白なら敵弾移動
cmp	r3,#e5		'砲台
bne	@no_bomb	'R3!=#E5なら左隣のアドレスへ
mov	r0,#FF		'ゲームオーバーフラグ
@mov_bomb
strb	r2,[r4,r5]	'敵弾移動
@no_bomb
sub	r4,1		'左隣のアドレス
sub	r3,r4,r1
lsr	r3,r3,4
cmp	r3,#91		'アドレス#91*
bne	@loop_bomb	'R3!=#91ならループへ
pop	{r4,r5}
ret

nop
nop
nop

'自弾(自位置=#770)	usr(#8A0,0)
push	{r4,r5,r6}
mov	r5,#77		'自弾位置ポインタ=#770
lsl	r5,r5,4
ldrh	r4,[r5,r1]	'自弾位置
cmp	r4,0		'自弾無し
beq	@exit_msl	'r4==0処理終了
mov	r6,0
strb	r6,[r4,r1]	'元位置クリア
sub	r4,#20		'1行上
cpy	r2,r4		'自弾1行上位置コピー
lsr	r3,r4,4
cmp	r3,#92		'VRAM=#920
blt	@exit_msl	'R3<=#920なら処理終了
mov	r3,#e4		'自弾キャラクタ
ldrb	r2,[r4,r1]	'1行上キャラクタ
mov	r0,2		'UFO=2pts
cmp	r2,#e6		'UFO=#E6
beq	@clr_msl	'R2==#E6なら自弾クリアへ
mov	r0,0		'notUFO=0pts
cpy	r6,r4
cmp	r2,#e0
blt	@mov_msl	'R2<#E0なら自弾移動へ
cmp	r2,#e3
bgt	@mov_msl	'R2>#E3なら自弾移動へ
mov	r0,1		'Invader=1pts
@clr_msl
mov	r3,0		'自弾クリア
mov	r6,0		'自弾位置クリア
@mov_msl
strb	r3,[r4,r1]	'1行上に自弾orクリア
@exit_msl		'処理終了
strh	r6,[r5,r1]	'自弾位置保存
pop	{r4,r5,r6}
ret
MixJuiceでのダウンロードURLは下記になります。
インベーダー1 http://tagiyasoft.blog.jp/invader1.bin
インベーダー2 http://tagiyasoft.blog.jp/invader2.bin

以下のように入力してD/Lしてください。
NEW
? MJ GET tagiyasoft.blog.jp/invader1.bin
? MJ GET tagiyasoft.blog.jp/invader2.bin

ブラウザでD/LしてIchigoJamに転送する場合は、通信ソフトでバイナリ送信をしてください。
(例:TeraTermの場合は、メニューの[ファイル]-[ファイル送信]で当該ファイルを送信します)

  • 題名
    JOLTSZX (電子工作マガジン2016年WINTER号掲載)

  • 開発環境
    IchigoJamBASIC1.1.1

  • 内容
    テトリスもどきゲームです。TETRIS

  • 遊び方
    キー操作で落ちてくるピースを操作して底から積み上げていきます。
    1列全て揃うとその段が消えて、段が詰まります。
    最上段まで積み上がってしまうとゲームオーバーです。

  • 操作方法
    テンキーでピースを操作します。

    [1]:左移動
    [2]:回転
    [3]:右移動

    回転方向は時計回りのみで、落下はありません。

  • プログラムのしくみ


  • 変数表
    A現位置のピース形状(復帰用に保存)
    B現位置のピース形状
    C移動後のピース形状
    D回転後のピース形状
    Kピースの高さ
    Pピース種類
    Qピースの向き
    R回転後のピースの向き
    U移動後のピースの位置
    V現在のピースの位置
    L入力キー
    Sスコア
    I,Jループ用
    W頻出数=32
    [0]~[27]ピース形状
    <br/>
    各行の処理
    10行コメント行
    20行機械語サブルーチン、初期画面作成
    30行ピース形状
    40行ピースの出現、キー入力
    50行ピースが移動できるか?
    60行回転前のピースを消去
    70行移動前のピースを消去
    80行移動後のピースを描画
    90行積み上がったらピースのキャラクタを変更
    100行1段揃ったか?
    110行1段落とす
    120行ピース出現に戻る


    1段落ちの処理はBASICだと処理が遅いので機械語にしました。

    各ピースは下記の形状をしており、1バイトで表され、配列変数に納められます。
    画面表示の時に、左下から右上にかけて、1bit~8bitの順に展開されます。
    ○は常に空マスで、ピースの描画基点となります。
    3x3マスで表示するため、オリジナルのテトリスにある「I」形状は無く、代わりに「+」形状が使われています。

    各ビットを展開した時の並び方
     123
    1■■○
    2■■
    3
     #D8
    
     123 123
    1  ○ ■ ○
    2 ■■ ■■
    3■■   ■ 
     #33	 #5A
    
     123 123
    1  ○  ■○ 
    2■■  ■■ 
    3 ■■ ■  
     #1E	 #99
    
     123 123 123 123
    1■■○   ○  ■○   ○
    2■   ■■■  ■  ■
    3■     ■ ■■  ■■■
     #C9	 #3C	 #93	 #0F
    
     123 123 123 123
    1  ○  ■○   ○ ■■○
    2■■■  ■    ■  ■
    3■    ■■ ■■■  ■
     #39	 #96	 #27	 #D2
    
     123 123 123 123
    1  ○  ■○  ■○  ■○ 
    2■■■ ■■  ■■■  ■■ 
    3 ■   ■       ■  
     #3A	 #9A	 #B8	 #B2
    
     123 123 123
    1 ■○
    2■ ■
    3 ■
     #AA
    
    

  • プログラムの具体的な入力方法
    20行めは機械語サブルーチンになっていますので、間違えないように入力してください。
    入力間違いがあるとエラーメッセージが出ずに、IchigoJamが操作不能になってしまう可能性があります。
    ですので、プログラムを入力したら、まずSAVEしてからRUNするようにしてください。
    もしIchigoJamが操作不能になってしまった場合は電源を入れ直してください。
    (保存していないプログラムは消えてしまいます)

  • プログラムの改造
    40行の「P=RND(7)」を「P=RND(6)」にすると「+」のピースが出現しなくなるので少しだけ簡単になります。


  • JOLTSZX
    10 'テトリス
    20 CLS:CLV:W=32:poke#8A0,3,70,202,92,32,51,202,84,64,59,26,10,8,42,248,209,1,48,2,70,15,35,26,64,11,42,240,209,112,71:LC15,0:?"SCORE:":FORI=0TO19:POKE#900+I*W,2:POKE#90B+I*W,2:IFI<12POKE#B80+I,2
    30 NEXT:LET[0],216,216,216,216,51,90,51,90,30,153,30,153,201,60,147,15,57,150,39,210,58,154,184,178,170,170,170,170
    40 V=#925:P=RND(7):Q=RND(4):R=Q:FORK=0TO18:U=V+W:L=INKEY():IFLL=(L-1)%3-1:IFL=0R=(Q+1)%4ELSEU=V+W+L
    50 A=[P*4+R]:B=A:FORI=0TO2:FORJ=0TO2:IFB&1ANDPEEK(U-I*W+J)=2IFK=0LC15,5:?"GAME OVER":ENDELSEI=3:J=3:IFQ<>RR=Q:NEXT:NEXT:GOTO50ELSEIFLU=U-L:L=0:NEXT:NEXT:GOTO50ELSEU=U-W:K=18
    60 B=B>>1:NEXT:NEXT:B=A:C=B:D=[P*4+Q]:FORI=0TO2:FORJ=0TO2:IFD&1POKEV-I*W+J,0
    70 IFB&1POKEV-I*W+J,0
    80 IFC&1POKEU-I*W+J,1
    90 B=B>>1:C=C>>1:D=D>>1:NEXT:NEXT:V=U:Q=R:NEXT:B=A:FORI=0TO2:FORJ=0TO2:IFB&1POKEV-I*W+J,2
    100 B=B>>1:NEXT:NEXT:FORI=0TO19:FORJ=0TO9:IFPEEK(#B61-I*W+J)=0J=20
    110 NEXT:IFJ=9S=S+1:LC23,0:?S:FORJ=0TO9:POKE(#B61-I*W+J),0:NEXT:J=USR(#8A0,#B40-I*W):I=-1
    120 NEXT:GOTO40
    


    機械語サブルーチン(一段落ち)
    USR(#8A0,*)
    引数:消えた行の1行上のアドレス/戻値:無し(不定)
    @LBL1
    cpy	R3,R0		'R3=R0		'R3=転送元アドレス(USR引数)
    @LBL2
    ldrb	R2,[R1,R3]	'R2=[R1+R3]	'キャラクタ=[実アドレス+転送元アドレス]
    add	r3,#20		'R3+=#20	'R3=転送先アドレス
    strb	r2,[r1,r3]	'[R1+R3]=R2	'[実アドレス+転送元アドレス]=キャラクタ
    sub	r3,#40		'R3-=#40	'R3=転送元アドレスを1行上
    lsr	r2,r3,8		'R2=R3>>8	'R2=転送元アドレスの上位バイト
    cmp	r2,#8		'R2-8		'R2が8か?(転送元アドレスが#8**か?)
    bne	@LBL2		'IF!0GOTO @LBL2	'偽なら@LBL2へ
    add	r0,#1		'R0+=1		'転送元アドレスを隣の列へ
    cpy	r2,r0		'R2=R0		'R2=転送元アドレス
    mov	r3,#f		'R3=#0F		'マスク
    and	r2,r3		'R2&=R3		'R2の下8bit
    cmp	r2,#b		'R2-#0B		'11列めか?
    bne	@LBL1		'IF!0GOTO @LBL1	'偽なら@LBL1へ
    ret			'RET
    
MixJuiceでのダウンロードURLは下記になります。
TETRIS http://tagiyasoft.blog.jp/tetris.bin

以下のように入力してD/Lしてください。
NEW
? MJ GET tagiyasoft.blog.jp/tetris.bin

ブラウザでD/LしてIchigoJamに転送する場合は、通信ソフトでバイナリ送信をしてください。
(例:TeraTermの場合は、メニューの[ファイル]-[ファイル送信]で当該ファイルを送信します)

  • タイトル
    ソリティアゴルフ (電子工作マガジン2016年SPRING号掲載)

  • 内容
    ソリティアゴルフというトランプゲームです。
    山札に場札を重ねていき、全ての場札を山札に重ねるゲームです。

  • solitairegolf

  • 遊び方
    表向きに置かれた山札よりも数字が1つ大きいか小さいカードを重ねていきます。
    重ねられるのは各列の最下段にあるカードのみです。
    Jは11、Qは12、Kは13と表示されます。
    AとKは繋がっています。(例:K-A-2や、2-A-Kのように繋げられる)
    重ねられるカードがなくなったら山札から1枚引いて表向きに置き、再び場札のカードを重ねていきます。
    場のカードと山札がすべて無くなったらゲームクリアです。
    場にカードが残った状態で山札が無くなってしまったら失敗です。
    ゲームが終了すると、かかった時間が表示されます。

  • 操作方法
    カード列上部にある[0]~[6]の数字を入力すると、その列の最下段のカードが山札に重ねられます。
    [-1]を入力すると、新たに山札から1枚めくられ表向きに置かれます。
    残りのカードが0枚以下になるとゲーム終了です。

  • プログラムのしくみ

  • 各行の処理
    1行コメント(ファイル名)
    2行カードをランダムに配列に収める
    3~4行場札を並べて表示
    5行山札表示
    6行ゲーム終了判定
    7行移動するカードを入力
    8行列の最下段サーチ
    9行場札±1のカードか判定
    10行場札から山札にカード移動
    11~13行カードの枠線描画
    14行入力待ちに戻る
    20行山札の枠線描画
    21行カードのマーク、数字、枠線描画

    変数表
    Iループ用
    J各種計算用一時変数
    Xカードのインデックス
    Y山札のインデックス
    T山札の数
    C選んだ場札の列
    B選んだ場札の数
    K選んだ場札のインデックス
    X動かした場札のインデックス
    Nカードの数字
    R描画したカードの数字
    Uカード描画X座標
    Vカード描画Y座標
    Pカード下部描画X座標
    Qカード下部描画Y座標

    [0]~[51]の配列に、ランダムに0~51の数字(カード)が収まります。
    カードは、0~12がスペード、13~25がハート、26~38がクラブ、39~51がダイヤになります。
    配列に入っている数を13で割った商がマークになり、余りが数字となります。

  • プログラムの具体的な入力方法
    プログラムリスト中の「□」はスペース1個です。(例:「□□□」はスペース3個)
    カードの枠線は「左ALT+SHIFT+キー」で入力します。
    ━ 左ALT+SHIFT+H
    ┃ 左ALT+SHIFT+I
    ┏ 左ALT+SHIFT+O(オー)
    ┓ 左ALT+SHIFT+P
    ┗ 左ALT+SHIFT+Q
    ┛ 左ALT+SHIFT+R

  • プログラムの改造
    ルールによってはAとKが繋がらないルールもあり、その場合は難易度が上がります。
    AとKを繋がらないルールにするには、9行めのIF文の判別式を下記のように変更します。
    ABS(N-T)%11<>1 → ABS(N-T)<>1

ソリティアゴルフ
1 'ソリティアゴルフ
2 CLV:CLT:Y=35:FORI=0TO51:J=RND(52):IF[J]I=I-1ELSE[J]=I:CLS:?I
3 NEXT:CLS:FORI=0TO34:U=I/5*4:V=(6-(I%5))*2-2:X=[I]:GOSUB21:IFI<7LCI*4+1,0:?"[";I;"]":LCI*4,12:?"┃":LCI*4,13:?"┗━━━":IFI<5LC28,I*2+3:?"┃"
4 NEXT:LC28,12:?"┃":LC28,13:?"┛":LC0,16:?"[-1]":[52]=[51]
5 LC8,18:?CHR$(12),"ノコリ ";51-Y;"マイ":X=[Y]:U=0:V=18:GOSUB20:?"□":T=R
6 IFY=52LC10,22:?"TIME=";TICK()/60;"sec":LC10,20:IFZ=35?"Congratulations!":ENDELSE?"GAME OVER.":END
7 LC4,19:?"┃":LC10,20:?CHR$(24);:INPUT"CARD=",C:IFC<0Y=Y+1:GOTO5
8 FORI=0TO4:K=(C%7)*5+I:B=[K]:IFB>=0:I=5:N=B%13+1ELSEN=T
9 NEXT:LC10,22:?CHR$(24);:IFABS(N-T)%11<>1?"ウゴカセマセン":GOTO7
10 U=0:V=18:X=B:GOSUB20:T=N:[Y]=[K]:[K]=-1:Z=Z+1:?"□":P=K/5*4:Q=(6-(K%5))*2:LCP,Q-2:?"┃□□□":LCP,Q-1:?"┗━━━":LCP,Q:?"┃□□□":LCP,Q+1:?"┃□□□"
11 IFC>0IF[K-5]>=0GOTO13
12 LCP,Q:?"□":LCP,Q+1:?"□"
13 IFC=6OR[K+5]<0LCP+4,Q-2:?"┃":LCP+4,Q:?"□":LCP+4,Q+1:?"□"
14 GOTO6
20 LCU+4,V+1:?"┃":LCU,V+2:?"┃□□□┃":LCU,V+3:?"┗━━━┛"
21 R=X%13+1:LCU,V:?"┏━━━┓":LCU,V+1:?"┃";CHR$(X/13+228);R;:RETURN

MixJuiceでのダウンロードURLは下記になります。
ソリティアゴルフ http://tagiyasoft.blog.jp/solitaire_golf.bin

以下のように入力してD/Lしてください。
NEW
? MJ GET tagiyasoft.blog.jp/solitaire_golf.bin

ブラウザでD/LしてIchigoJamに転送する場合は、通信ソフトでバイナリ送信をしてください。
(例:TeraTermの場合は、メニューの[ファイル]-[ファイル送信]で当該ファイルを送信します)

  • タイトル
    人工無脳おいちょかぶ (電子工作マガジン2016年SPRING号掲載)

  • 開発環境
    IchigoJamBASIC1.1.0

  • 内容
    今から30年くらい前のことですが、ふと「『思考』とは、『過去の経験』に基づき、『判断』すること」ではないだろうか、という仮説を立てました。
    そこで、過去の勝敗経験を勝負に反映させられるようなゲームを作ってみました。
    当時N88BASICで作ったプログラムを、記憶を元にIchigoJam向けに簡素化して移植しました。
    ちなみに、AIと言っても人工知能(artificial intelligence)ではなく、このプログラムにおいては人工無脳(artificial idiot)ですのでお間違いなく。

  • 楽しみ方
    このゲームは勝敗を楽しむのではなく、マイコンの勝敗経験の蓄積と、経験の積み重ねによって少しずつマイコンが強くなっていく過程を温かく見守るゲームです。
    人間とマイコンで勝負を続けて育てるのも良し、友達が育てたデータと対戦してみたり、友達が育てたデータとあなたが育てたデータを足してみるのも良いかと思います。
    大体、50試合ぐらい勝負すると(教育すると)、だんだんとCOM側に「勝ちパターン」が反映してきます。

  • 操作方法
    ルールは「おいちょかぶ」とほぼ同じです。
    1枚もしくは2枚のカードを合計した数が大きい方が勝ちです。ただし、合計数が10を超えた場合は1の位の数字だけで勝負します。
    よって、0が最も弱く、9が最も強い数になります。

    1. まず、それぞれにカードが1枚配られます。
    2. ユーザーは配られた数を見て、もう1枚取るか、そのまま勝負するかを決めてください。
    3. 次にマイコンが、過去の勝敗経験から2枚目のカードを取るか判断します。
    4. プレイヤーとマイコンの数を比較し勝敗が決定します。
    5. マイコンは勝負の結果を記録し、画面下に一覧を出力します。

  • プログラムのしくみ
    50行目のR=RND(20)はマイコンの「気まぐれ」の発生です。
    AIや遺伝的プログラムには「突然変異」を加味しないとデータに偏りが出てしまうので、このプログラムでは1/20の確率で「気まぐれ」を起こすようにしています。
    #FE0(4064)以後の領域は、マイコンの勝敗データの記録エリアで、POKE文により勝敗データを記録しています。
    なお、勝敗記録は1バイト単位になっていますので、255回以上勝つ(または負ける)と、データが0に戻ってしまいます。

  • プログラムの具体的な入力方法
    110行目の「SAVE(保存番号):END」は、ゲーム終了時にプログラムリストと一緒に勝敗記録を保存するための命令です。
    これにより次回LOADした時にプログラムリストと一緒に勝敗記録が読み込まれます。
    上書きされますので、保存先プログラム番号は適宜変更してください。

  • 勝敗データのメンテナンス
    130行目は、勝敗データを表示あるいは手入力するためのプログラム部分です。
    もし何らかの原因で勝敗データが消えてしまった場合や、新たにデータを記憶させたい時(プログラムを改造した時や、友達が育てたデータを使ってみたい時など)に使用してください。
    「GOTO130」とすると、「DATA Read=1/Write=0」と聞いてくるので、勝敗データを表示させたい場合は「1」、勝敗データを手入力する時は「0」と入力してください。
    データの入力順番は「使用メモリ表」の通りです。

  • 改造注意!
    このプログラムは、プログラム領域にデータを保存しているため、改造等でプログラムが大きくなりすぎるとデータを破壊し、あるいはプログラム自身を破壊してしまいます。
    ?FREE()で、残り25バイト程度を上限にしておいた方が無難です。

  • プログラムの改造
    勝敗判定のうち「引き分け」は「勝ち」として記録していますので、これを「負け」として記録するように変更すると、用心深い性格(?)に変わります。
    また50行目のR=RND(20)の数値で「気まぐれ」の発生率を決めていますので、この数値を小さくすると気まぐれな性格になり、この数値を大きくすると慎重な性格になります。

変数表>
T良く使う数字(10)
Iループ用
X,Yプレイヤーのカードの数
Zプレイヤーが勝負する数
Mプレイヤーがもう1枚取るか
C,Dマイコンのカードの数
Eマイコンが勝負する数
W勝負する数でマイコンが勝った回数
L勝負する数でマイコンが負けた回数
K勝負する数でマイコンが勝つ確率
R気まぐれ確率
Uデ-タ表示/入力選択
Sデ-タ手入力用変数
Aデータ収納アドレス(A-1のアドレスは試合回数)

使用メモリ表(合計21バイト)
#FE0-1総試合数
#FE0+10の時に勝った回数
#FE0+99の時に勝った回数
#FE0+100の時に負けた回数
#FE0+199の時に負けた回数

人工無脳おいちょかぶ
10 'aiオイチョカブ
20 CLV:T=10:A=#FE1
30 CLS:X=RND(T):?"YOU",X:Y=0:C=RND(T):?"COM",C:D=0:LC0,5:INPUT"モウ 1マイ トリマスカ?(Yes=1/No=0) ",M:IFMY=RND(T):LCT,0:?Y
40 Z=(X+Y)%T:W=PEEK(A+C):L=PEEK(A+T+C):K=W*100/(W+L+(W+L=0))
50 WAIT60:LC0,8:?C,"ノ ショウリツ=";K;"%":?:WAIT60:R=RND(20):IFK<50?"モウ 1マイ";:IFR>0GOTO70ELSEWAIT60:?" ...ヤメタ":GOTO80
60 ?"イラナイ";:IFR>0GOTO80ELSEWAIT60:?" ...ヤッパリ トル"
70 WAIT60:D=RND(T):LCT,1:?D
80 E=(C+D)%T:POKEA-1,PEEK(A-1)+1:LC0,12:IFE<Z?"COM ノ マケ":I=A+T+E:POKEI,PEEK(I)+1:GOTO100
90 I=A+E:POKEI,PEEK(I)+1:IFE=Z?"ヒキワケ"ELSE?"COM ノ カチ"
100 LC0,16:?"シアイスウ=";PEEK(A-1),"(データアドレス=";HEX$(A-1);")":?"カズ":?"カチ":?"マケ":FORI=0TO9:LC3+I*3,17:?I;:LC3+I*3,18:?PEEK(A+I);:LC3+I*3,19:?PEEK(A+T+I);:NEXT:?:?:INPUT"ツヅケマスカ?(Yes=1/No=0)",S:IFSGOTO30
110 SAVE(保存番号):END
120'メンテナンス
130 CLS:?"メンテナンス モード":A=#FE1:INPUT"DATA Read=1/Write=0:",U:?"データアドレス=";HEX$(A-1):FORI=-1TO19:?I;"=";:IFU?PEEK(A+I):NEXTELSEINPUTS:POKEA+I,S:NEXT
140 END

MixJuiceでのダウンロードURLは下記になります。
人工無脳おいちょかぶ http://tagiyasoft.blog.jp/ai_oicho.bin

以下のように入力してD/Lしてください。
NEW
? MJ GET tagiyasoft.blog.jp/ai_oicho.bin

ブラウザでD/LしてIchigoJamに転送する場合は、通信ソフトでバイナリ送信をしてください。
(例:TeraTermの場合は、メニューの[ファイル]-[ファイル送信]で当該ファイルを送信します)

  • IchigoJamのスクリーンショットを撮りたい

 IchigoJam の実行画面のスクリーンショットを撮りたい時があります。

もちろん、 IchigoJam の実行画面をPCで表示し、PCのスクリーンショット機能を使用するのですが、POKE命令を使用して画面表示を行っているプログラムのスクリーンショットは難しいものがありました。

そこでPOKE命令を使用したプログラムのスクリーンショットを撮る方法について色々と試行錯誤した結果、とりあえず期待する成果を得られたので報告します。

  • その1

fig03まずは、画面の表示にPRINT命令だけを使用したプログラムの場合ですが、IchogoJam用シリアルキーボードアプリ IJKB を使用すれば、特に難しくなくスクリーンショットを撮ることができます。

 IchigoJam で実行中のプログラムを IJKB で表示し、それを[Alt]+[PrintScreen]キーでスクリーンショットを撮り、"Paint"等のソフトにて保存します。

ただし、CHR$による画面制御コードが使用されている場合、画面表示が乱れることがあります。

  • その2

次にPOKE命令で画面表示をしているプログラムの場合ですが、 IJKB では正確に画面表示されずスクリーンショットを撮ることができません。
そこで VirtualBox を使用することにしました。
(これがこの記事のメインとなります)
virtualbox02
まずは VirtualBox をインストールし、そこに IchigoJam PC をインストールします。
これで、Windwosの操作で IchigoJam PC のスクリーンショットを撮る環境が整いました。

しかし、スクリーンショットを撮るにはプログラムを入力しなければなりません。(当然ですが)
例え1KBとは言え、 IchigoJam に入力したプログラムを、再度 IchigoJam PC に入力するなんて無駄な労力は払いたくありません。

なんとかラクはできないものかと探してみたら、 com0com というヌルモデムエミュレータが使えそうな感じでした。
ホストコンピュータ(私の環境ではWindows7)から、ゲストコンピュータ(IchigoJam on VirtualBox)に、仮想シリアルポートを通じてプログラムの転送が行えそうです。

 com0com をインストールし、 VirtualBox のシリアルポートの設定を仮想COMポートにし、 TeraTerm の接続先に VirtualBox の仮想シリアルポートとペアになるポートを選んで接続してみたところ、見事にプログラムを転送することができました。

これで VirtualBox 上で IchigoJam のプログラムを実行し、そのスクリーンショットを撮ることができました。

  • 実作業

以下は、各ソフトウェアのインストールおよび設定の説明になります。

  1. まずは VirtualBox をインストール virtulabox01
    インストール作業は、基本的に「Next >」を押していくだけです。
    私は何も考えずにデフォルトのファイル構成でインストールしました。



  2. VirtualBoxにIchigoJamをインストール virtualbox03
    イチゴジャムレシピのサイトの説明にあるように、初めて起動する場合は、”IchigoJam.vbox ”をクリックすると IchigJamPC がVirtualBox内で起動します。

    うまく起動できなかった場合は、VirtualBoxの「とげとげアイコン(新規)」(あるいは[仮想マシン]-[新規]メニュー)より、仮想IchigoJamマシンを作成します。
    • 「名前」欄は、適当に(私はIchigoJamPCとしました)
    • 「タイプ」欄は、"Other"
    • 「バージョン」欄は、"DOS"
    • 「メモリーサイズ」は、"4MB"
    • 「仮想ハードディスクを追加しない」にチェック
    上記の設定にすると最小構成で仮想マシンを作成することができます。
    次に「歯車アイコン(設定)」(あるいは[仮想マシン]-[新規]メニュー)を選びます。
    「ストレージ」の項目より、空のフロッピーディスクを選び、"IchigoJam.img"を選んでください。
    (仮想CD-ROMを使用する場合は、空のCD-ROMを選び、"IchigoJam.iso"を選んでください)
    以上で、 IchigJamPC がインストールできました。
    「→アイコン(起動)」(あるいは[仮想マシン]-[起動]-[通常起動]メニュー)でIchigoJamPCを実行することができます。

  3. com0comをインストールcom0com01
    Windowsに com0com をインストールします。
    インストール後、[スタート]メニューの、[com0com]-[seup]を選び、作成された仮想シリアルポートを確認しておきます。
    (右図では、COM4とCOM5が割り当てられています。)

  4. VirtualBoxのシリアル設定virtualbox04
    VirtualBox内のIchigoJamPCにシリアルポートを割り当てます。
    VirtualBoxの「歯車アイコン(設定)」から、「シリアルポート」を選び、「ポート1」のタブより、
    • 「シリアルポートを有効化」を、チェック
    • 「ポート番号」は、"COM1"
    • 「ポートモード」は、"ホストデバイス"
    • 「パス/アドレス」は、com0comで割り当てられたポート名(私の場合はCOM4)
    と設定します。

  5. TeraTermの設定teraterm01
    [設定]-[端末]メニューより、端末設定を行います。
    私は右図のような設定にしています。

    次に[設定]-[シリアルポート]メニューより、シリアルポートの設定を行います。teraterm02
    私は右図のような設定にしています。

  6. IchigoJamPCの設定
    最後にIchigoJamPCのUART設定をします。
    IchigoJamPCはデフォルトでUART0(出力しない)になっているので、"UART1"と入力して通信可能とします。

  • 最後に

solitairegolf以上で、VirtualBoxにIchigoJamPCをインストールし、TeraTermを用いてプログラムを転送できるようになりました。

右は約1KBあるプログラムを転送して実行した画面のスクリーンショットです。

これで機械語プログラムも実行できると完璧なんだけどなぁ。

↑このページのトップヘ