• タイトル
    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の場合は、メニューの[ファイル]-[ファイル送信]で当該ファイルを送信します)

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

  • タイトル
    マインスイーパーlatte (電子工作マガジン2017年WINTER号掲載)

  • 開発環境
    IchigoJamBASIC1.2.1

  • 内容
    マインスイーパーです。

  • マインスイーパーlatte
  • 遊び方
    フィールドの中から爆弾を探すゲームです。 爆弾に隣接しているマスは隣接している爆弾の数が表示されるので、それをヒントに全てのマスを開けてください。

  • 操作方法
    横方向(X軸)と縦方向(Y軸)を入力してマスを開きます。 それぞれ1~8の数字を入力し、Enterします。 全て開けられれば成功、爆弾を開けてしまうと失敗です。 最後にかかった時間が表示されます。

  • プログラムのしくみ

    各関数の説明
    bm.clrフィールド用メモリクリア
    bm.set爆弾配置
    bm.disp画面表示
    引数 0:爆弾を伏せて表示 1:爆弾を表示
    返値 開いていないマスの数
    kyinキー入力
    引数 xy:"X"または"Y"の文字 pos:文字表示Y座標
    返値 入力された数値
    searchマスを開く
    引数 入力したX,Y座標
    返値 0:爆弾以外を開いた 0以外:爆弾を開いた
    main初期設定、画面表示
    残りマス=爆弾数、もしくは爆弾を開いてしまうまでループ
    結果表示

    変数表(グローバル変数のみ)
    B爆弾の数
    Tゲーム開始時のタイム
    mメモリ(配列)先頭アドレス
    x,y入力した座標
    n残りマス数
    s入力座標が爆弾かどうか

  • プログラムの具体的な入力方法
    可読性を良くするためスペースでインデントしていますが、行頭のスペースは入力しなくても動作します。

  • プログラムの改造
    変数"B"は爆弾の数です。増減して難易度を変更することができます。

  • (プログラム1)
    var B=6;
    function bm(f){
     this.clr=function(){
      var i=0;
      while(i<100 ){
       if((i>10)*(i<89 )*((i%10)%9!=0)){ mem(m+i,0xF4); }
       else{ mem(m+i,0); }
       i=i+1;
      }
     };
     this.set=function(){
      var i=B, r;
      while(i){
       r=(rnd(8)+1)*10+rnd(8)+1;
       if(mem(m+r)==0xF4){
        mem(m+r,0xF6);
        i=i-1;
       }
      }
     };
     this.disp=function(f){
      var i=1, c, n=0;
      cls();
      log("\\X12345678\nY\n");
      while(i<9){
       var j=0;
       log(i);
       while(j<9){
        c=mem(m+i*10+j);
        if((c>0)*(c<9 )){ c=c+0x30; }
        else{
         if((c>9)*(f==0)){ c=0xF4; }
        }
        log(chr(c));
        if(c==0xF4){ n=n+1; }
        j=j+1;
       }
       log("\n");
       i=i+1;
      }
      return(n);
     };
    }
    
    function kyin(xy,pos){
     lc(0,pos);
     log(xy,"= ");
     var k=input();
     if((k<1 )*(k>8)){ k=0; }
     return(k);
    }
    
    function search(u,v){
     var sp=m+100;	//stack pointer
     var src=v*10+u;	//search position
     var z=mem(m+src);	//search position char
     if(((u%10)%9==0)*((v%10)%9==0)){ return(0); }	//out side
     if(z<=9){ return(0); }	//number
     if(z==0xF6){ return(z); }	//bomb
    
     var indx=0;
     mem(sp,1);	//[0]=1
     mem(sp+1,src);	//[[0]]=[1]=src
    
     var x, y, z, j, count=0;
     while(indx9){
          mem(sp, mem(sp)+1);
          mem(sp+mem(sp),j);
         }
         if(z==0xF4){ mem(m+j,0); }
         x=x+1;
        }	//while(x
        y=y+1;
       } 	//while(y
      }
      mem(m+src,count);
     }	//while(co
     return(0);
    }
    
    //main
    var T=tick();
    var m=mem(" ");
    var bomb=new bm();
    var x=0, y=0, n=1, s=0;
    bomb.clr();
    bomb.set();
    n=bomb.disp(0);
    while((n!=B)*(s==0)){
     x=kyin("X",12);
     y=kyin("Y",13); 
     if(x*y){
      s=search(x,y);
     }
     n=bomb.disp(0);
    }
    bomb.disp(1);
    if(s){ log("\n\nGAME OVER\n"); }
    if(n==B){ log("\n\nCONGRATULATION!\n\n"); }
    log("TIME: ",(tick()-T)/1000,"sec\n");
    

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

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

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

  • 参考ゲーム
    マインスイーパー

cpuemu - Alpha1 *このエミュレータはblogの仕様により、現在、正常に動作しません。
下記の場所のエミュレータをお使いください。
http://tagiyasoft.blog.jp/cpuemu-Alpha1.html




レジスタ直接入力(16進数を入力)

使い方

  • 使えるマシン語一覧:
    Cortex-M0 Armマシン語表(抜粋)(GitHub版)
    Cortex-M0 Armマシン語表(抜粋)(tagiyasoft版)
  • 下記のサイト等でbinaryーコードを作成し、テキストエリアにコピーします。
    Assembler for IchigoJam(GitHub版)
    Assembler for IchigoJam(tagiyasoft版)
  • [START]もしくは[STEP]ボタンで実行します。
  • コンソールには、実行したアセンブラの命令が表示されます。
  • テキストボックスに値(16進数)を入力して[SET]ボタンを押すと、指定したレジスタに値が直接入力されます。
  • プログラム内で一度も使われていないアドレスからのロード命令が実行されると実行が一時中断し、レジスタに値をセットするよう促されます。
  • プログラムカウンタはR15ですので、実行位置の変更(条件分岐先の変更など)はR15に直接値を入力してください。
  • テキストエリア内のプログラムを変更した場合は、[RESET]ボタンを押してください。

更新

  • 2017/12/31 対応命令追加、フラグ追加、コンソール表示追加、その他追加
cpuemu a1 (for IchigoJam)
APP: CC BY fukuno.jig.jp

↑このページのトップヘ