• タイトル
    91X(電子工作マガジン2018年AUTUMN号掲載)

  • 開発環境
    IchigojamBASIC1.2.1

  • 内容
    マーカー(自機)を動かし、自分の領域を増やしていく陣取りゲームです。

  • 遊び方
    マーカーは矢印キーで移動し、自分のエリア(濃いアミカケ)内を自由に移動することができます。
    スペースキーを押しながら矢印キーを押すと、自分のエリア外にライン(薄いアミカケ)を引きながら移動することができます。
    再度自分のエリアに戻ってくると、ラインで囲った領域が新たに自分のエリアとなります。
    マーカーが敵に触れたり、作成中のラインに敵が触れるとゲームオーバーです。
    1回のラインで多くのエリアを確保すると得られる得点がアップします。

  • qix
  • 操作方法
    [↑]キー上移動
    [↓]キー下移動
    [←]キー左移動
    [→]キー右移動
    [SPACE]キーラインを引く

    画面の「S」はスコア、「A」は確保したエリア、「T」は残り時間です。

  • プログラムのしくみ
    機械語部分(プログラム1)とBASIC部分(プログラム2)に分かれています。
    機械語ルーチンは、初期画面作成、敵キャラクタの移動、塗りつぶしの3つの処理が含まれています。
    BASICルーチンは、キー入力、マーカー移動、サウンド等の処理をしています。

    変数表
    E,F,G頻出数字
    I,Jループ用一時変数
    A確保領域
    M自分の位置
    N自分の位置に元々あったキャラクタ
    C自分または敵の移動先キャラクタ
    V自分または敵の移動方向
    Q敵の頭の位置
    O敵の尾の位置
    P敵の長さ
    D線描画フラグ
    Kキー入力
    B新たに確保した領域
    Sスコア
    Wウエイト用

    機械語サブルーチン(プログラム1)
    USR(#700,0)
    塗りつぶし
    引数:無し
    戻値:領域数
    USR(#774,0)
    枠描画
    引数:無し
    戻値:無し
    USR(#77C,1)
    敵移動
    引数:上位4bit=キャラクタ(RND(14))+下位4bit=方向(RND(4))
    戻値:FF=GameOver/FE=retry_RND(4)/FD=error/00=no_error

  • プログラムの具体的な入力方法
    プログラム1は機械語プログラムですので、間違えないように入力してください。
    入力間違いがあるとエラーメッセージが出ずに、IchigoJamが操作不能になってしまう可能性があります。
    ですので、プログラムを入力したら、まずSAVEしてからRUNするようにしてください。
    もしIchigoJamが操作不能になってしまった場合は電源を入れ直してください。
    (保存していないプログラムは消えてしまいます)
    また、6行の「END」を、「(例)LRUN2」のようにプログラム2の保存番号に変更すると、プログラム1を実行後すぐにプログラム2を読み込んで実行することができます。
    プログラム1は通常のPOKE文だとメモリ容量を超えてしまうため、BASE16というアルゴリズムで圧縮してあります。
    (正確にはバイナリ→テキスト変換。POKE文を利用したプログラムに対して圧縮の意味)

  • プログラムの改造
    プログラム2のPに4を加えた数が敵の初期の長さになります。長くすると難しくなります。(短くすると正しく動作しません)
    Wは全体の動きを遅くするための数値です。初期値5から1面クリアごとに小さく(=早く)なります。増減させて難易度を変更できます。
    7行の9999は制限時間です。増減させて難易度を変更できます。

  • 91X(プログラム1)
    1 'QIX1
    2 Z="ONKEI@B@@@@ADGAHBNBFCF@AB@BB@ACBKBDBALMLM@EMB@BH@CM@HABHOGMKHNBHOEMLMAAIB@CI@@BC@@O@@JOHAOBC@@O@@GOHBABC@@O@@DOHD@BC@@O@@AOHNFNGLHEL@@BH@@M@G@DGB@B@LHEDMNNG@@B@":Y=#700:GSB8
    3 Z="B@BBB@BDMAEM@KAK@GM@@CBI@CM@@DBI@AM@@@BI@BMA@AC@@CBCMCEE@ACBKBDBO@MKONKMONKD@FB@I@BGCO@AGOAHKNBFCF@AGFAHB@BB@ACJM@EEI@EEOKMACMDFAOCEFNALBLBBAB@AE@EEI@EEB@CJOKME":Y=#750:GSB8
    4 Z="@CB@GNALBABALHEEHHEEB@CALHEEHHEEONKLG@DG@@KE@BKD@ODF@HBFCF@BOLCFCNDDKEAL@B@II@DF@CBBA@D@@@BBJLEJB@CLCLDDDAAN@FM@AOBA@BBH@CM@BABA@CBH@@M@D@BAOOB@FBEL@DBJ@FMAHOBB":Y=#7A0:GSB8
    5 Z="FBEDDBDFHACBB@BAFBEDDAN@ONB@@@BJCNMAFCAHB@CK@@BA@@O@CMOH@@BHCGMAAOBA@@O@CHOH@@BHCBMABABA@@O@CCOH@@BHBMMAD@BA@@O@BNOH@@BHBHMADADFHACAB@CDBAG@B@CCMKAK@@BBJKEBKCEJ":Y=#7F0:GSB8
    6 Z="CKDDB@CK@@BA@@O@ANOH@@BHA@MAAOBA@@O@AIOH@@BH@KMABABA@@O@ADOH@@BH@FMAD@BA@@O@@OOH@@BH@AMAOMB@@GN@@@B@AJDFB@CBA@G@@KDDMKAK@@BBKCEB@BKL@@KMG@DG@@B@EJELH@BJ@BMMHOBJ":Y=#840:GSB8
    7 Z="@@MJONB@G@DG":Y=#890:GSB8:END
    8 W=Y+LEN(Z)/2-1:FORX=YTOW:POKEX,PEEK(Z)&15<<4+PEEK(Z+1)&15:Z=Z+2:NEXT:RTN
    

    91X(プログラム2)
    1 'QIX2
    '全体初期設定
    2 E=143:F=32:G=23:s=0:p=0:W=5
    '面初期設定
    3 CLS:A=USR(#774,0):A=0:LC21,G:?"T:";:M=#921:N=3:V=1:P=P+4:W=W-1:PLAY"T700EREDRDRDE2REFRFGR0R0"
    'QIX配置
    4 Z=#9A0+RND(512):IFPEEK(Z)GOTO4ELSEPOKEZ,134:Y=Z:FORI=0TOP:Y=Y+V:IFY<#960Y=Y+F:V=1:I=I-1ELSEIFPEEK(Y)Y=Y+31:IFPEEK(Y)Y=Y-33:IFPEEK(Y)Y=Y+1:V=-F:I=I-1
    5 POKEY,134:NEXT:CLT:C=3:N=4:V=0:wait120:GOTOG
    'QIX移動
    6 J=J+1:IFJ>9J=Y:Y=Z:Z=J:J=0:POKEZ,E:GOTO6
    7 a=usr(#7B4,rnd(14)<<4+rnd(4)):IFa=#FF||TICK()>9999POKEZ+V,E:POKEZ,E:GOTOFelseifa=#FEgoto6
    10 J=0:LCG,G:?9999-TICK();:WAITW
    '自移動
    11 V=0:D=0:K=PEEK(#1002):IF!KGOTO6ELSEIFK&16D=1
    12 IFK&1V=-1ELSEIFK&2V=1ELSEIFK&4V=-FELSEIFK&8V=F
    13 C=PEEK(M+V):IFD&&(C>128&&C74LC12,10:?" CLEAR ";:play"t999erer9grgr9brb":WAITE:GOTO3
    24 IFC=3POKEM,N:M=M+V:N=PEEK(M):POKEM,42
    25 IF!C&&DPOKEM,N:M=M+V:N=4:POKEM,42
    26 GOTO6
    32 lc9,9:?"GAME OVER":play"t500fr9fgfrfgedc":LC0,0:OK
    

    91X(プログラム1のアセンブラリスト)
    '塗りつぶし	引数:無し/戻値:領域数
    push	{r1-r7,LR}
    mov	r0,#90
    lsl	r0,r0,4		'仮想LC0,0(#900)
    add	r7,r0,r1	'R7=実VRAM
    mov	r6,#2E		'#BE0-#900=#2E0
    lsl	r6,r6,4		'R6=仮想LC0,23(#BE0)
    @VRAMTOP		'敵側塗りつぶし(#20)	R2=カウンタ
    mov	r2,#20					
    @LOOP1			'敵側探索
    add	r2,1
    cmp	r2,r6
    bgt	@FILL		'塗りつぶし
    ldrb	r0,[r2,r7]				
    cmp	r0,#20					
    beq	@LBL1					
    cmp	r0,#81					
    blt	@LOOP1
    cmp	r0,#8E
    bgt	@LOOP1
    @LBL1			'!= ,!=O,!=o
    add	r1,r2,r7
    sub	r1,#20		'R1=チェックVRAM
    mov	r3,#00		'R3=R1の上
    gosub	@CHKNULL				
    mov	r3,#1F		'R3=R1の左
    gosub	@CHKNULL			
    mov	r3,#21		'R3=R1の右
    gosub	@CHKNULL				
    mov	r3,#40		'R3=R1の下
    gosub	@CHKNULL				
    bla	@LOOP1					
    @CHKNULL
    ldrb	r0,[r1,r3]
    cmp	r0,#00
    beq	@PUTSPC
    ret
    @PUTSPC
    mov	r0,#20		'R0=CHR$(#20)=SPACE
    strb	r0,[r1,r3]
    bla	@VRAMTOP
    @FILL			'自領域塗りつぶし(#00)
    mov	r0,#00		'R0=領域数(戻値)
    mov	r2,#20		'R2=カウンタ
    mov	r4,#20
    @LOOP2
    ldrb	r1,[r2,r7]				
    sub	r3,r1,r4
    beq	@LBL3					
    cmp	r1,#03
    beq	@LBL2
    cmp	r1,#04
    beq	@LBL2
    cmp	r1,#00
    bne	@LBL4
    @LBL2
    add	r0,#01					
    mov	r3,#03
    @LBL3
    strb	r3,[r2,r7]				
    @LBL4
    add	r2,1
    cmp	r2,r6					
    blt	@LOOP2					
    pop	{r1-r7,PC}
    
    'nop
    'nop
    
    '--枠描画
    '枠	引数:無し/戻値:無し
    push	{r1-r7}
    mov	r0,#0,6
    mov	r7,#90
    lsl	r7,r7,4		'仮想LC0,0(#900)
    add	r7,r7,r1	'R7=実LC0,0
    mov	r6,#BE
    lsl	r6,r6,4		'仮想LC0,23(#BE0)
    add	r6,r6,r1	'R6=実LC0,23
    mov	r2,#20		'R2=カウンタ
    @KABELOOP1
    sub	r2,#01
    strb	r0,[r2,r7]	'上枠
    strb	r0,[r2,r6]	'下枠
    bne	@KABELOOP1
    mov	r5,r7
    add	r5,#1F		'#91F
    add	r6,r5,1		'#920
    mov	r2,#2C		'R2=カウンタ(#2C0)
    lsl	r2,r2,4
    @KABELOOP2
    strb	r0,[r2,r5]	'右枠
    strb	r0,[r2,r6]	'左枠
    sub	r2,#20
    bpl	@KABELOOP2	'r2>#00(=r2+r5>#900)
    mov	r0,#03
    add	r6,r7,#01
    mov	r1,#21
    strb	r0,[r1,r7]
    strb	r0,[r1,r6]
    add	r1,#20
    strb	r0,[r1,r7]
    'mov	r0,#2A		'#2A="*"
    strb	r0,[r1,r6]
    pop	{r1-r7}
    ret
    
    'nop
    'nop
    
    '--QIX移動
    '使用変数:q,o
    '引数(R0)	上位4bit=キャラクタ(RND(14))
    '		下位4bit=方向(RND(4))
    '戻値(R0)	FF=GameOver/FE=retry_RND(4)/FD=error/00=no error
    push	{LR}
    push	{r1-r10}
    mov	r7,r1		'R7=実VRAM先頭アドレス
    mov	r6,#08
    lsl	r6,r6,#08
    add	r6,#FC
    add	r6,r7		'R6=#8FC=Y(=o)
    add	r5,r6,#02	'R5=#8FE=Z(=q)
    lsr	r2,r0,#04
    mov	r8,r2		'R8=キャラクタ(RND(14))
    mov	r2,#03
    and	r0,r2
    'mov	r9,r0		'R9=方向(RND(4))
    mov	r2,#00
    ldrh	r4,[r5,r2]	
    sub	r4,#20		
    add	r4,r7
    sub	r1,r0,#1	'RND=1	上
    beq	@Q_EAT		'R1=0
    mov	r1,#1F
    cmp	r0,#02		'RND=2	左
    beq	@Q_EAT		'R1=31
    mov	r1,#21
    cmp	r0,#03		'RND=3	右
    beq	@Q_EAT		'R1=33
    mov	r1,#40		'R1=64 RND=0	下
    @Q_EAT
    mov	r0,#FF
    ldrb	r2,[r4,r1]	'R2=Q+V
    cmp	r2,#04
    bne	@Q_NL_CK		
    mov	r2,#8F
    strb	r2,[r4,r1]		
    mov	r2,r8
    add	r2,#81
    mov	r1,#20
    strb	r2,[r4,r1]		
    bla	@Q_EXIT
    
    @Q_NL_CK
    mov	r0,#FE
    cmp	r2,#00
    bne	@Q_EXIT			
    add	r3,r4,r1
    sub	r3,#20		
    mov	r1,#00
    gosub	@Q_CHECK
    cmp	r0,#00
    bne	@Q_EXIT
    mov	r1,#1F
    gosub	@Q_CHECK
    cmp	r0,#00
    bne	@Q_EXIT
    mov	r1,#21
    gosub	@Q_CHECK
    cmp	r0,#00
    bne	@Q_EXIT
    mov	r1,#40
    gosub	@Q_CHECK
    cmp	r0,#00
    bne	@Q_EXIT
    mov	r1,r8		'R8=キャラクタ(RND(14))
    add	r1,#81
    add	r4,#20
    strb	r1,[r4,#00]		
    add	r3,#20		
    sub	r3,r3,r7
    mov	r2,#00
    strh	r3,[r5,r2]		
    
    ldrh	r3,[r6,r2]		
    add	r3,r7
    sub	r3,#20		
    
    mov	r1,#00
    gosub	@Q_CHECK
    cmp	r0,#00
    bne	@Q_TAIL
    mov	r1,#1F
    gosub	@Q_CHECK
    cmp	r0,#00
    bne	@Q_TAIL
    mov	r1,#21
    gosub	@Q_CHECK	
    cmp	r0,#00
    bne	@Q_TAIL
    mov	r1,#40
    gosub	@Q_CHECK
    cmp	r0,#00
    bne	@Q_TAIL
    mov	r0,#FD		'error
    BLA	@Q_EXIT
    @Q_TAIL
    mov	r0,#00
    mov	r2,r3
    add	r2,#20
    strb	r0,[r2,#00]	
    add	r3,r1
    sub	r3,r3,r7
    mov	r2,#00
    strh	r3,[r6,r2]	'O=O+[I]
    @Q_EXIT
    pop	{r1-r10}
    pop	{PC}
    ret
    'sub
    @Q_CHECK
    mov	r0,#00
    ldrb	r2,[r3,r1]	'R2=Q+V-r1	
    cmp	r2,#80
    ble	@Q_CHK_RET		
    cmp	r2,#8F
    bge	@Q_CHK_RET		
    mov	r0,#FE		'rnd(4) retry
    @Q_CHK_RET
    ret
    


    MixJuiceでのダウンロードURLは下記になります。
    91x(1) http://tagiyasoft.blog.jp/91x1.bin
    91x(2) http://tagiyasoft.blog.jp/91x2.bin

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

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

  • 参考ゲーム
    QIX

タブレット(orスマホ)でmts形式のビデオファイルを結合することができたので、その方法を紹介します
**注意**
今回紹介する方法でmtsファイルの結合をすると、以後、ビデオカメラがそのmicroSDを認識しなくなってしまうので、結合は専用のmicroSDでやってください。

(認識しなくなったmicroSDはフォーマットすることで、再度、ビデオカメラで使用できます)

  1. 結論
  2. 「方法だけ解れば自分でやるよ」って人向けに結論から。
    "Termux" で 'cat hoge.mts fuga.mts > piyo.mts' で出来たよ。
    でも"Termux"でそれをやると、ビデオカメラがそのmicroSDを認識しなくなっちゃうから、専用のmicroSDでやってね。
    …という話を、以下くどくどと書きます。

  3. 経緯
  4. 知人よりビデオファイル(mtsファイル)の結合が簡単にできないか相談されました。

    やりたい事は、「スポーツ観戦で前半の試合を録画した後に一旦ビデオを停止し、そのあと後半の試合を録画しているが、それらを結合して1試合が1ファイルになるようにしたい」ということでした。
    なんでも、youtubeにアップするのに1ファイルの方が都合が良いとか。

    最初は自分で検索して、「DOSコマンドで"COPY a.mts b.mts > c.mts"とすると結合できるらしいんだけど、それをバッチファイルにして欲しい」というのでバッチファイルを書いてあげて、それを実行していました。

    そしたら「早くyoutubeにアップしたいので、試合会場、もしくは帰宅する車内で結合したい」ということで、ノートPCを車内に持ち込むようになりました。

    そのうち、「ノートPCを持ち歩くの面倒。なんとかして」という経緯。

    俺もそんな事にいちいち関わるのも面倒なので、しばらくスルーしていたのですが、ふと「スマホ(android)ってlinuxじゃん」と気がつきまして。
    ちょっと面白そうなので(←コレ重要)、androidでビデオファイルの結合ができるかやってみることにしました。

    まず、面倒な事はやりたくないので、rootを取らずにlinuxのシェルを実行できるアプリがあるのか探してみると"Termux"というアプリを発見。
    色々やってみたら、見事、ファイルを結合することができたので、そのやり方の報告です。

  5. 使用端末
  6. 今回使用したのは、ASUS MEMO Pad7(K013 ME176C)で、Android5.0。
    タブレットだと、裏カバーを開けなくてもmicroSDを挿せるから便利。
    microSDをUSBポートに接続できるアダプタや変換ケーブルでもOK。
    (その場合、ディレクトリがexternal-2になる(後述))

  7. "Termux"の環境作り
  8. 凡例
    ""で囲まれた文字列は固有名詞
    ''で囲まれた文字列はキーボードからの入力
    [Enter]:Enterボタン

    *入力は大文字と小文字を区別するので表記通り入力してください。

    "Termux"アプリをインストールして実行します。
    https://play.google.com/store/apps/details?id=com.termux
    次に、'Termux-setup-storage'[Enter]と入力、実行します。
    'ls'[Enter]で、"storage"ディレクトリが作られた事を確認します。
    ('ls'コマンドは、MS-DOSで言うところの'dir'です)

    "~/storage/external-1/"が、今回使用するディレクトリになります。
    上記はandroidの、"/Removable/MicroSD/Android/data/com.terumux/files/"にリンクしています。

    毎回結合コマンドを手打ちするのも面倒なのでスクリプトを作成します。
    viが使えるので、以下のスクリプトを作成し、適当な名前(例:mtsmts)で、"~/"(ホームディレクトリ)下に保存します。
    (下記の 00000.mts、00001.mts、01.mts はサンプル名ですので適宜変更してください)

    cd ~/storage/external-1
    cat 00000.mts 00001.mts > 01.mts
    ls -l *.mts
    cd ~/
    

    chmodで実行権限を与えます。(例:chmod 755 mtsmts)

    上記のスクリプトの内容は、「00000.mtsと00001.mtsを結合して、01.mtsという名前で保存」という内容です。
    2ファイル以上のファイルの結合は、cat 文の > の前に列挙してください。

    コマンドの最後にファイル一覧を表示するので、結合に成功していれば、結合後のファイルが表示されるはずです。

  9. MTSビデオファイルを結合する
    1. ビデオのメモリカード(microSD等)をタブレット(orスマホ)に挿入します。
    2. 結合したいmtsファイルを"Termux"で読み書きできるディクトリにコピーします。
      ファイルマネージャを起動します。
      "/Removable/MicroSD/PRIVATE/AVCHD/BDMV/STREAM/"にある、*.mtsファイルをコピーし、
      "/Removable/MicroSD/Android/data/com.terumux/files/"以下に貼り付けます。
      多分、コピーに時間がかかると思うので、放置しておきます。
    3. コピーしたら、ファイル名を「3.」で指定したファイル名に変更します。
      "Termux"を起動します。
      先程作成したファイル結合スクリプトを実行します。
      (例:'./mtsmts')
      結合もそれなりに時間がかかると思うので、またまた放置。
    以上。

  10. 注意
  11. 今回紹介する方法でmtsファイルの結合をすると、以後、ビデオカメラがそのmicroSDを認識しなくなってしまうので、結合は専用のmicroSDでやってください。
    (認識しなくなったmicroSDはフォーマットすることで、再度、ビデオカメラで使用できます)

    知人は毎回フォーマットしているそうですが、マスターファイルを保存しておきたい場合は、内部ストレージにコピーして結合するとか、USBに外部ストレージを付けてそこにコピーして結合するなりしてください。
    その場合は、スクリプト内のディレクトリの場所の記述が変わりますので、ユーザーの環境に合わせて変更してください。

  12. 変換ケーブルについて
  13. 最初は試験的に変換ケーブルで試しました。
    SODIAL(TM) 2x Micro USB OTG Host Cable

    使ったケーブルはメモリ専用ではなく、USB_C-A変換ケーブルに、USB-microSD変換アダプタを繋いだもの。
    ケーブルだかアダプタだかが遅くて、ファイルコピーにえらく時間がかかったので、結局microSDをスロットに直接挿して使う事にしました。
    アクセスが早いアダプタを使えば快適になるかは不明。

    また、上記ケーブルでAndroid7.0のスマホで試したところ外部ストレージ(external-2)として認識しませんでした。
    これも問題がケーブルにあるのか、"Termux"にあるのかは検証してません。

  14. スクリプトファイル
  15. スクリプトファイルを作る際にエディタ作業が必要になりますが、viエディタの使い方を知らない場合は、エディタアプリをインストールするのが一番ラクかもしれません。

    アプリをインストールしたくないのであれば、一言一句間違えない自信があなら、'echo pwd >> mtsmts'[Enter]、'echo cd ~/storage/external-1 >> mtsmts'[Enter]、と一行一行打ち込んでいくこともできます。

    また、PCでスクリプトファイルを作成したものをスマホ(orタブレット)でD/Lして、"Termux"のディレクトリに移動することで使用できます。(実行権限を与えるのを忘れずに)
    「スクリプトファイルをD/Lする」とは、例えばどこかのクラウドにU/Lするとか、自分宛に添付メールするとか、自分のブログにU/Lするとかです。

    色々やり方は考えられますが、vi覚えるのが最短かと。

  1. 目的
  2. 素数をグラフ化するとどうなるのか疑問に思ったので、自由研究課題として素数のレーダーグラフを作成した。
    使用ソフト:LibreOffice

  3. 方法
  4. まず素数を用意するために、下記のマクロプログラムを作成した。
    Sub Main
    dim	sheet as object
    dim	cell as object
    sheet = thiscomponent.sheets(1)
    for x = 2 to 10000
    	for i = 2 to sqr(x)
    		if( (x mod i )=0 ) then 
    			i=0
    			exit for
    		endif
    	next
    	if( i<>0) then
    		cell = sheet.getCellByPosition(0,y)
    		cell.value = x
    		y=y+1
    	endif
    next
    End Sub
    上記のプログラムにより、2以上、10000以下の素数を作成した。
    (2,3,5 ... 9949,9967,9973 : データ数1229個)

  5. 結果
  6. 結果を下記に示す。
    比較のため、対数、平方数についても同様のグラフを作成した。
    (こちらはデータ数を100個とした)



  7. 考察
  8. これらの各グラフを比較すると、素数グラフが最も美しい螺旋形グラフとなった。
    螺旋の形状としては、黄金比を用いた黄金螺旋にも似ている。

    今回はデータを10000以下としたが、時間をかければもっと大きな素数まで作成することができる。もっと多くの素数においても、極端に形状が変形することなく螺旋が続くのか興味深い。

↑このページのトップヘ