• タイトル
    pypyズラシ(電子工作マガジン2018年SPRING号掲載)

  • 開発環境
    IchigojamBASIC1.2.1

  • 内容
    画面のキャラクタを左右にずらし、縦横4個以上繋げて消すゲームです。
    5秒以内に4個繋がりを作ってください。
    目指せ20連鎖!
  • pypy
  • 遊び方
    RUNすると画面に5種類のキャラクタが8×8個並び、キャラクタの横に"> <"のマークが出ます。
    "> <"がある高さのキャラクタを左右にずらすことができます。
    左右にずらした時に端にあったキャラクタは反対側から現れます。
    キャラクタをずらして縦横に4個以上繋がるとキャラクタが消えます。
    一度の操作で異なる繋がりを消すと「連鎖(COMBO)」します。
    キャラクタが消えて宙に浮いたキャラクタは下に落ち、新たにキャラクタが上から落ちてきます。
    キャラクタが落ちてきて4個以上繋がった場合も「連鎖」が継続します。

    点数は「消えたキャラクタの数×連鎖回数」です。
    連鎖すればするほど高得点になります。

  • 操作方法
    [↑]キー"> <"マーク上移動
    [↓]キー"> <"マーク下移動
    [←]キー左ずらし
    [→]キー右ずらし

  • プログラムのしくみ
    機械語部分(プログラム1)とBASIC部分(プログラム2)に分かれています。
    機械語ルーチンは、繋がったキャラクタを消去する部分と、キャラクタが落ちる部分、キャラクタが消えている場所を返す部分の3つの処理が含まれています。
    BASICルーチンは、画面表示、キー入力、横ずらし、サウンド等の処理をしています。
    プログラム領域の最後(#FFC~#FFF)にハイスコアと最大連鎖を書き込んでいますので、プログラムをSAVEすることで電源を切ってもハイスコアを記憶し続けることができます。

  • 変数表
    Yハイスコア記録
    Sスコア
    Z最大連鎖数記録
    L最大連鎖数
    R連鎖数
    W連鎖の有無フラグ
    Gキャラ落ちの有無フラグ
    Aキャラの繋がり数(4以上/0=繋がり無し)
    Bキャラ種類の増分
    Hキャラ補充フラグ(0=補充無し/1=補充有り)
    Kキー入力
    X"> <"マーク位置
    C"> <"マーク表示フラグ(1=表示/0=消去)
    O,D,E,F,P,Iずらし用一時変数

    プログラム2
    1行コメント文
    2行初期化、文字表示
    3行キャラクタ画面表示
    4行キャラ落下
    5行4個繋がりの消去
    6~8行連鎖処理
    9行キャラ補充
    10行最大連鎖更新
    11行タイマクリア
    12行キー入力、時間切れチェック
    13行左右ずらし
    14~16行"> <"マーク移動
    17~18行画面キャラ表示サブルーチン
    19行"> <"マーク表示サブルーチン
    20行ゲームオーバー処理、ハイスコア更新
    21行最大連鎖記録更新
    22行記録保存

    機械語サブルーチン(プログラム1)
    USR(#700,0)4個以上の繋がり消去引数:無し/戻値:繋がって消えたキャラ数
    USR(#77C,0)キャラクタの空白位置引数:0/戻値:キャラクタの空白位置(#920からの増分)
    USR(#77C,1)キャラクタ落下引数:1/戻値:落下の有無(0=無/1=有)
  • プログラムの具体的な入力方法
    プログラム1は機械語サブルーチンになっていますので、間違えないように入力してください。
    入力間違いがあるとエラーメッセージが出ずに、IchigoJamが操作不能になってしまう可能性があります。
    ですので、プログラムを入力したら、まずSAVEしてからRUNするようにしてください。
    もしIchigoJamが操作不能になってしまった場合は電源を入れ直してください。
    (保存していないプログラムは消えてしまいます)
    また、最終行にプログラム2の保存番号を書くと(例:LRUN2)、プログラム1実行後すぐにプログラム2を読み込んで実行することができます。

  • プログラムの改造
    • プログラム1
      20行の配列は、表示するキャラクタのコード番号です。
      お気に入りキャラや見やすいキャラクタに変更する場合はコード番号を変更してください。
      自作キャラを使用する場合は、キャラクタコード#F8~#FFに設定してください。

    • プログラム2
      12行の"IFK>300"はタイマ値です。300より大きくするとタイマが長くなり、小さくすると短くなります。
      6行は連鎖時のサウンドです。自由に変更できます。
      プログラム領域の最後(#FFC~#FFF)をハイスコアと最大連鎖の保存に使用していますので、プログラムがその領域にかからないように4byte以上残しておいてください。

  • プログラム1
    10 'pypyズラシ-1
    20 CLP:[0]=#720:[1]=#728:[2]=#730:[3]=#738:[4]=#740:[5]=#748:[6]=#758:[7]=#760
    30 FORI=0TO8:COPY#7C0+I*8,[I],8:NEXT
    40 POKE #700,0,181,254,180,8,38,54,2,14,68,146,39,63,1,15,68
    50 POKE #710,0,37,1,32,48,112,117,112,0,35,124,93,248,44,28,219
    60 POKE #720,1,51,242,92,0,32,184,84,17,28,32,57,0,240,28,248
    70 POKE #730,17,28,32,49,0,240,24,248,81,30,0,240,21,248,81,28
    80 POKE #740,0,240,18,248,48,120,131,66,234,219,48,120,4,43,9,218
    90 POKE #750,49,92,124,84,1,56,251,209,48,112,1,53,255,32,40,64
    100 POKE #760,0,40,214,209,254,188,0,189,120,92,160,66,3,209,48,120
    110 POKE #770,1,48,48,112,49,84,112,71,0,0,0,0,254,180,6,28
    120 POKE #780,0,32,146,37,45,1,13,68,208,36,41,93,142,66,7,209
    130 POKE #790,31,39,39,64,8,47,14,220,0,47,12,208,32,28,12,224
    140 POKE #7A0,248,41,8,219,35,28,32,51,234,92,0,42,3,209,233,84
    150 POKE #7B0,42,85,1,32,208,36,1,60,231,209,254,188,112,71,0,0
    160 LRUN(プログラム2の保存番号)
    

    プログラム2
    1 'pypyズラシ-2
    2 CLS:CLV:COPY#8FC,#FFC,4:LC15,0:?"HI  SCORE:";Y:LC15,1:?"MAX COMBO:";Z:LC15,4:?"SCORE:0":LC15,10:?"TIME :":C=1:GSB@A
    3 @G:GSB@D
    'DAN OCHI
    4 @H:G=G|USR(#77C,1):W=0
    'SAME CHECK
    5 @L:A=USR(#700,0):IF!AGOTO@C
    6 R=R+1:S=S+A*R:LC21,4:?S:LC15,7:?R;"COMBO! ":W=1:IFR=10PLAY"T100L32O4EGO5ECDG":WAIT30ELSEIFR=20PLAY"T100L32O5FFFFRERGRF":WAIT30ELSEBEEP30-R,10
    7 IFS<25000B=S/5000
    8 WAIT30:GOTO@L
    9 @C:IFWGOTO@HELSEGSB@D:IFHGOTO@H
    10 IFR>LL=R
    11 IFGCLT:G=0:CLK:BEEP10,20
    'KEY
    12 @K:K=TICK():LC21,10:?DEC$(300-K,3):IFK>300GOTO@TELSEK=INKEY():IFK=0GOTO@K
    13 R=0:C=1:GSB@A:IFK=28||K=29O=K-28:D=1-2*O:E=O*7+1:F=8-7*O:P=SCR(E,X+1):FORI=ETOFSTEPD:LCI,X+1:?CHR$(SCR(I+D,X+1)):NEXT:LCF,X+1:?CHR$(P):GOTO@G
    14 IFK=30&&X>0C=0:GSB@A:X=X-1:C=1:GSB@A
    15 IFK=31&&X<7C=0:GSB@A:X=X+1:C=1:GSB@A
    16 GOTO@K
    'DISP
    17 @D:H=0
    18 @E:I=USR(#77C,0):IFIPOKE#920+I,RND(5)+#F8+B:H=1:CLT:GOTO@EELSERTN
    '>< DISP
    19 @A:LC0,X+1:?CHR$(C*62):LC9,X+1:?CHR$(C*60):RTN
    20 @T:LC0,10:?"GAME OVER":?:IFS>YY=S:?"HI-SCORE!",Y
    21 IFL>ZZ=L:?"MAX-COMBO!",Z
    22 COPY#FFC,#8FC,4
    

    プログラム1(アセンブラ表記)
    '--- same check
    	push	{LR}
    	push	{r1-r7}
    	mov	r6,#8
    	lsl	r6,r6,8
    	add	r6,r1	'r6=Array(#800)
    	mov	r7,#92
    	lsl	r7,r7,4
    	add	r7,r1	'r7=VRAM(#920)
    	mov	r5,#00	'check from #920
    @loop1		'a=r3,b=r4,r5=LoopCounter,[]=r6,VRAM=r7
    	mov	r0,1
    	strb	r0,[r6,0]	'[0]=1
    	strb	r5,[r6,1]	'[1]=LoopCounter
    	mov	r3,0		'r3=0	a=0
    	ldrb	r4,[r7,r5]	'b=scr(i,j)
    	cmp	r4,#FA
    	blt	@lbl1		'if b<#FA @lbl1
    @lbl2		'VRAM範囲チェックループ
    	add	r3,1		'a=a+1
    	ldrb	r2,[r6,r3]	'r2=[a]
    	mov	r0,0
    	strb	r0,[r7,r2]	'lcu,v:?chr$(0)
    	mov	r1,r2
    	sub	r1,#20		'@chk_up(r2-#20)
    	gosub	@sub1
    	mov	r1,r2
    	add	r1,#20		'@chk_dn(r2+#20)
    	gosub	@sub1
    	sub	r1,r2,#1	'@chk_L(r2-#1)
    	gosub	@sub1
    	add	r1,r2,#1	'@chk_R(r2+#1)
    	gosub	@sub1
    	ldrb	r0,[r6,0]
    	cmp	r3,r0
    	blt	@lbl2		'if a<[0] goto @lbl2
    	ldrb	r0,[r6,0]	'result(combo count)=[0]
    	cmp	r3,#4
    	bge	@lbl3		'if a>=4 @lbl3 (combo)
    @loop2		'キャラ復元
    	ldrb	r1,[r6,r0]
    	strb	r4,[r7,r1]	'poke VRAM+[[0]],b
    	sub	r0,1		'[0]=[0]-1
    	bne	@loop2
    	strb	r0,[r6,0]	'[0]=0
    @lbl1
    	add	r5,1
    	mov	r0,#FF
    	and	r0,r5
    	cmp	r0,#0		'check VRAM=#920-#A1F
    	bne	@loop1		'if r0 != #A1* @loop1
    
    @lbl3
    	pop	{r1-r7}
    	pop	{PC}		'return
    
    @sub1		'周囲同キャラチェック
    	ldrb	r0,[r7,r1]	'r0=scr(u,v-1)
    	cmp	r0,r4
    	bne	@sub_ret
    	ldrb	r0,[r6,0]
    	add	r0,1
    	strb	r0,[r6,0]	'[0]=[0]+1
    	strb	r1,[r6,r0]	'[[0]]=r1
    @sub_ret
    	ret
    '--- padding
    	nop
    	nop
    	nop
    	nop
    '--- drop	'r0=dlop flag(0=no/1=yes):r1=ochi moto:r2=ochi saki:r4=LoopCounter,r5=VRAM
    	push	{r1-r7}
    	mov	r6,r0		'1=drop/0=null search
    	mov	r0,0		'drop flag clear
    	mov	r5,#92		'#920
    	lsl	r5,r5,4
    	add	r5,r1		'r5=VRAM=#920
    	mov	r4,#D0		'loop for #920+#D0 to #920+#0
    @d_loop1
    	ldrb	r1,[r5,r4]	'r1=peek(r5+r4)
    	'-- null search
    	cmp	r6,r1		
    	bne	@d_lbl2		'if peek(r5+r4)!=0 || r6!=0 goto @d_lbl2
    	mov	r7,#1F
    	and	r7,r4
    	cmp	r7,#8
    	bgt	@d_lbl1
    	cmp	r7,0
    	beq	@d_lbl1		'if r7=0 goto @d_lbl2
    	mov	r0,r4
    	bla	@d_lbl3
    	'--
    @d_lbl2
    	cmp	r1,#FA
    	blt	@d_lbl1		'if r1<#FA goto @d_lbl1
    	mov	r3,r4
    	add	r3,#20
    	ldrb	r2,[r5,r3]	'r2=peek(r5+r4+#20)
    	cmp	r2,0
    	bne	@d_lbl1		'if r2!=0 goto @d_lbl1
    	strb	r1,[r5,r3]	'poker5+r3,r1
    	strb	r2,[r5,r4]	'poker5+r4,r2
    	mov	r0,1		'drop flag set
    	mov	r4,#D0		'loop for #920+#D0 to #920+#0
    @d_lbl1
    	sub	r4,1		'count down
    	bne	@d_loop1
    @d_lbl3
    	pop	{r1-r7}
    	ret
    

    MixJuiceでのダウンロードURLは下記になります。
    zurasi1 http://tagiyasoft.blog.jp/zurasi1.bin
    zurasi2 http://tagiyasoft.blog.jp/zurasi12.bin

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

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

  • 参考ゲーム
    ぷよぷよズラシ
  • ぷよぷよ