IchigoJamでズンドコキヨシ

IchigoJamで「ズンドコキヨシ」を実装してみた。

# 背景

## 「IchigoJam」とは

BASICでプログラミングができるパソコンである。

[こどもパソコン IchigoJam - はじめてのプログラミングパソコン(1500円)](https://ichigojam.net/)

※「IchigoJam」はjig.jpの登録商標

## 「ズンドコキヨシ」とは

「ズン」か「ドコ」をランダムに繰り返し出力していき、
「ズン」「ズン」「ズン」「ズン」「ドコ」の順に並んだら
「キ・ヨ・シ！」と出力して終了する、というプログラムである。

### 元ネタ

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">Javaの講義、試験が「自作関数を作り記述しなさい」って問題だったから<br>「ズン」「ドコ」のいずれかをランダムで出力し続けて「ズン」「ズン」「ズン」「ズン」「ドコ」の配列が出たら「キ・ヨ・シ！」って出力した後終了って関数作ったら満点で単位貰ってた</p>&mdash; てくも❂ (@kumiromilk) <a href="https://twitter.com/kumiromilk/status/707437861881180160?ref_src=twsrc%5Etfw">2016年3月9日</a></blockquote>

### まとめ

[ズンドコキヨシまとめ - Qiita](https://qiita.com/shunsugai@github/items/971a15461de29563bf90)

# とりあえず、コードと動作を見ていただこう

## シンプル版

普通のテキストで出力する。

```
10 'ｽﾞﾝﾄﾞｺｷﾖｼ (ｼﾝﾌﾟﾙ)
20 Z=0
30 WAIT 30
40 IF RND(2)=0 GOTO 80
50 PRINT "ｽﾞﾝ ";
60 Z=Z+1
70 GOTO 30
80 PRINT "ﾄﾞｺ ";
90 IF Z>=4 GOTO 120
100 Z=0
110 GOTO 30
120 WAIT 30
130 PRINT "ｷ･ﾖ･ｼ!"
```

実行結果 (YouTube動画)

[![シンプル版の実行結果 (YouTube)](http://img.youtube.com/vi/D9TPq3WJAO0/0.jpg)](http://www.youtube.com/watch?v=D9TPq3WJAO0)

## 豪華版

* 「ズン」「ドコ」「キ・ヨ・シ！」の出力に合わせて音を鳴らす。
* 最初、または「ドコ」の次の「ズン」の後は待ち時間を2倍にする。
* 「キ・ヨ・シ！」を大きい文字で表示する。

```
10 'ｽﾞﾝﾄﾞｺｷﾖｼ (ｵﾄﾂｷ)
20 LET[80],#B7,#D6,#BC,#A5,#21
30 CLS:?"LOADING...":LC 0,2
40 ?"[":LC 21,2:?"]":LC 1,2
50 FORI=0TO4:S=I*16:C=[80+I]*8
60 FORJ=0TO15:[S+J]=#80:NEXT
70 FORJ=0TO63:T=S+J/16*4+J%8/2
80 B=PEEK(C+J/8)>>(7-J%8)&1
90 D=(3*(J%16>7)+1)*(J%2+1)
100 [T]=[T]|B*D:IFJ%16=15?"#";
110 NEXT:NEXT:CLS:X=0:Y=0:Z=0
120 X=X+1:IFX>8:X=1:Y=Y+1
130 IFY>18:SCROLL0:Y=Y-1:LC0,Y
140 IFRND(2)=0GOTO180
150 ?"ｽﾞﾝ ";:BEEP40,7
160 WAIT30+30*(Z=0)
170 Z=Z+1:GOTO120
180 ?"ﾄﾞｺ ";:BEEP25,5:WAIT15
190 BEEP25,5:WAIT15
200 IFZ<4:Z=0:GOTO120
210 BEEP10,5:X=0:C=0:GOSUB280
220 X=4:C=48:GOSUB280:WAIT10
230 BEEP10,5:X=8:C=16:GOSUB280
240 X=12:C=48:GOSUB280:WAIT10
250 BEEP10,5:X=16:C=32:GOSUB280
260 X=20:C=64:GOSUB280:WAIT10
270 LC0,Y+5:END
280 A=#920+Y*32+X:P=C:FORI=0TO3
290 POKEA,[P],[P+1],[P+2],[P+3]
300 A=A+32:P=P+4:NEXT:RETURN
```
実行結果 (YouTube動画)

[![豪華版の実行結果 (YouTube)](http://img.youtube.com/vi/gQCJxpJK0bY/0.jpg)](http://www.youtube.com/watch?v=gQCJxpJK0bY)

# 仕組み

## 「ズンドコキヨシ」本体 (シンプル版・豪華版共通)

乱数の値に応じて「ズン」または「ドコ」を出力する。
IchigoJamの標準で出せる文字では、濁点は1文字として出力することになるため、「ズン」「ドコ」いずれも3文字である。
さらに、今回使用しているバージョンのIchigojamの画面は横32文字×縦24文字である。
そのため、空白を1文字入れ、1ワードを4文字で出力すると、きれいに表示できる。

「ズン」を表示したら、カウンタを1増やす。
「ドコ」を表示したら、カウンタの値をチェックする。
カウンタの値が4以上であれば「キ・ヨ・シ！」を出力する処理に移り、そうでなければカウンタを0に戻す。

## 大きな文字の表示 (豪華版)

### フォントを読み取り、表示用の表現に変換する

IchigoJamで扱う文字は、8×8ドットである。
`PEEK(仮想アドレス)`関数を用いることで、メモリの値(バイト)を読み取ることができる。
IchigoJamで表示する文字コード`C`の文字のフォントは、仮想アドレス`8*C`からの8バイトに格納されている。
このフォントは、最初(下位)のバイトが一番上の行、最後(上位)のバイトが一番下の行である。
各行は1バイトで表され、一番左が最上位ビット(MSB)、一番右が最下位ビット(LSB)である。
各ビットは0が黒、1が白を表す。

IchigoJamでは、文字コード`128+n` (n=0～15) が描画用の文字となっている。
これらの文字は、8×8の文字の領域が縦横各2分割されて`n`の各ビットに対応し、
下位ビットから順に左上、右上、左下、右下である。
こちらも0が黒、1が白となっている。

これらを踏まえると、フォントから描画用の文字を用いた表示用の表現に変換できる。
表示用の表現は、4文字×4文字の16文字である。

![フォントデータから表示用の表現への変換](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/3e61beb4-3456-bfba-4b20-4c41a01c9d45.png)

豪華版のコード中では、70行目～110行目で変換処理を行っている。
その中でも点の変換を行っている部分は

```
T=S+J/16*4+J%8/2
B=PEEK(C+J/8)>>(7-J%8)&1
D=(3*(J%16>7)+1)*(J%2+1)
[T]=[T]|B*D
```

である。
変換する点の情報は、`C, S, J`で表される。
`C`は、変換するフォントの先頭の仮想アドレスである。
`S`は、表示用の表現を格納する配列の先頭の添字である。
`J`は、変換する点の位置であり、上から下、行の中では左から右の順番である。
変換に用いる情報は、`T, B, D`で表される。
`T`は、表示用の表現(出力)中の変換する点がある文字の位置(添字)である。
`B`は、フォント(入力)の中の変換する点の情報である。
`D`は、表示用の表現(出力)中の文字の中の変換する点を表すビットである。
それぞれの変換を詳しく見ると、

```
T=                 変換先の位置は
    S              出力位置の指定
   +J/16*4       + 点の縦位置 (2行=16点ごとに動き、1行=4文字分ずれる)
   +J%8/2        + 点の横位置 (1行=8点周期で動き、2点で1文字ずれる)

B=                 変換元のビットは
    PEEK(C+J/8)    8点ごとに1行動く位置を用いて取得するフォントのバイトから
  >>(7-J%8)&1      8点周期で左から動く位置を用いて取得する

D=                 変換先のビットは
    (3*(J%16>7)+1) 2行セットのうち下の行なら4か8、上の行なら1か2
   *(J%2+1)        2列セットのうち左なら1か4、右なら2か8

[T]=[T]|B*D        変換元のビットが1なら、変換先にビットを加える
```

となっている。

### 表示用の表現を出力する

メモリの仮想アドレス`#900～#BFF` (十六進数の900～BFF) がVRAMであり、
ここに書き込んだ値を文字コードとして解釈することで画面に表示される文字が決定される。
`POKE 書き込み先の仮想アドレス,書き込む値[,書き込む値[,...]]`命令により、メモリに書き込むことができる。
出力を行っているのは、豪華版の280行目～300行目である。
変数`Y`に「ズン」や「ドコ」を表示している位置が格納されているため、
その1行下、すなわち32文字先から出力をする。
`A`に書き込むVRAMのアドレス、`P`に書き込むデータがある配列の添字を格納する。
1行に4文字を出力し、次の行に行く。
素早く出力できるように、1文字ずつ出力するのではなく、
連続した領域に1回で書き込める`POKE`の性質を用い、1行の4文字をまとめて書き込んでいる。

# まとめ

BASICが実行できるパソコンであるIchigoJamにおいて、「ズンドコキヨシ」を実装した。
単純にテキストで出力するだけでなく、「キ・ヨ・シ！」を大きく表示するなどの工夫をしたバージョンも作った。