IchigoJam + Ichigo-ice で読み上げ機能つきビンゴマシン

年末年始にかけて、パーティーなどをやる人も居るかもしれない。
パーティーといえば、やっぱりビンゴゲームが定番かな。

ということで、[IchigoJam](https://ichigojam.net/) を用いてビンゴマシンを作ってみた。
今回は、[Ichigo-ice](https://hello002.stores.jp/items/5d5ca76b3a7e96562c1a3589) と連携して出た数字を自動で読み上げる。

※IchigoJamはjig.jpの登録商標です。

# プログラム

```
10 ' ﾖﾐｱｹﾞ ﾋﾞﾝｺﾞ
20 A=#2E
30 COPY#8A0,"karappo/dayo.",13:[86]=[86]|#0D00:COPY#8B4,"<NUMK VAL=",10:[96]=#0D3E
40 CLS:FORI=0TO74:LOCATEI%10*3+3,I/10:?"･":[I]=I:NEXT:N=75:S=0
50 K=INKEY():IFK=0WAIT1:GOTO50
60 IFK=32:S=S+1:IFS>4GOTO20ELSEGOTO50
70 S=0:IFK<>10GOTO50
80 FORI=24TO40:DRAW16,I,47,I,0:NEXT:DRAW16,30,16,43:DRAW16,43,47,43:FORI=0TO11:DRAW28+SIN(I*30)/25,31+COS(I*30)/25,28+SIN(I*30+30)/25,31+COS(I*30+30)/25:NEXT
90 FORI=0TO12:DRAW28,31,28+SIN(I*30-30)/42,31+COS(I*30-30)/42,0:DRAW28,31,28+SIN(I*30)/42,31+COS(I*30)/42:WAIT3:NEXT
100 IFN<1IFAA=A*!I2CW(A,#8A0,14):GOTO50ELSEGOTO50
110 LOCATE21,20:?CHR$(#8F):WAIT60:C=RND(N):V=[C]+1:N=N-1:[C]=[N]:F=(#180+V/10*8)*(V>9):G=#180+V%10*8:IFV>9[95]=V/10+V%10<<8+#3030:ELSE[95]=V+#2030
120 FORI=18TO43:DRAW16,I,47,I,0:NEXT
130 IFAA=A*!I2CW(A,#8B4,14)
140 FORI=0TO7:LOCATE8,12+I:P=PEEK(F+I):FORJ=0TO7:?CHR$(P>>(7-J)&1*#8F);:NEXT:NEXT:FORI=0TO7:LOCATE12+4*(V>9),12+I:P=PEEK(G+I):FORJ=0TO7:?CHR$(P>>(7-J)&1*#8F);:NEXT:NEXT
150 LOCATE(V-1)%10*3+2,(V-1)/10:?DEC$(V,2)
160 GOTO50
```

* [OneFiveCrowd で実行](https://onefivecrowd.mikecat.work/#text=RUN%0A&prg=CgAOJyDW0LG53iDL3t263gAAFAAGQT0jMkUAAB4AUENPUFkjOEEwLCJrYXJhcHBvL2RheW8uIiwxMzpbODZdPVs4Nl18IzBEMDA6Q09QWSM4QjQsIjxOVU1LIFZBTD0iLDEwOls5Nl09IzBEM0UAACgAPENMUzpGT1JJPTBUTzc0OkxPQ0FURUklMTAqMyszLEkvMTA6PyKlIjpbSV09STpORVhUOk49NzU6Uz0wAAAyABxLPUlOS0VZKCk6SUZLPTBXQUlUMTpHT1RPNTAAADwAIklGSz0zMjpTPVMrMTpJRlM-NEdPVE8yMEVMU0VHT1RPNTAARgASUz0wOklGSzw-MTBHT1RPNTAAAFAAmkZPUkk9MjRUTzQwOkRSQVcxNixJLDQ3LEksMDpORVhUOkRSQVcxNiwzMCwxNiw0MzpEUkFXMTYsNDMsNDcsNDM6Rk9SST0wVE8xMTpEUkFXMjgrU0lOKEkqMzApLzI1LDMxK0NPUyhJKjMwKS8yNSwyOCtTSU4oSSozMCszMCkvMjUsMzErQ09TKEkqMzArMzApLzI1Ok5FWFQAWgByRk9SST0wVE8xMjpEUkFXMjgsMzEsMjgrU0lOKEkqMzAtMzApLzQyLDMxK0NPUyhJKjMwLTMwKS80MiwwOkRSQVcyOCwzMSwyOCtTSU4oSSozMCkvNDIsMzErQ09TKEkqMzApLzQyOldBSVQzOk5FWFQAAGQALklGTjwxSUZBQT1BKiFJMkNXKEEsIzhBMCwxNCk6R09UTzUwRUxTRUdPVE81MAAAbgCOTE9DQVRFMjEsMjA6P0NIUiQoIzhGKTpXQUlUNjA6Qz1STkQoTik6Vj1bQ10rMTpOPU4tMTpbQ109W05dOkY9KCMxODArVi8xMCo4KSooVj45KTpHPSMxODArViUxMCo4OklGVj45Wzk1XT1WLzEwK1YlMTA8PDgrIzMwMzA6RUxTRVs5NV09VisjMjAzMAB4ACBGT1JJPTE4VE80MzpEUkFXMTYsSSw0NyxJLDA6TkVYVACCABhJRkFBPUEqIUkyQ1coQSwjOEI0LDE0KQAAjACkRk9SST0wVE83OkxPQ0FURTgsMTIrSTpQPVBFRUsoRitJKTpGT1JKPTBUTzc6P0NIUiQoUD4-KDctSikmMSojOEYpOzpORVhUOk5FWFQ6Rk9SST0wVE83OkxPQ0FURTEyKzQqKFY-OSksMTIrSTpQPVBFRUsoRytJKTpGT1JKPTBUTzc6P0NIUiQoUD4-KDctSikmMSojOEYpOzpORVhUOk5FWFQAlgAmTE9DQVRFKFYtMSklMTAqMysyLChWLTEpLzEwOj9ERUMkKFYsMikAoAAGR09UTzUw&drawAlgorithm=bresenham) (非公式、高速、高品質な描画)
* [IchigoJam web で実行](https://fukuno.jig.jp/app/IchigoJam/#10%20%27%20%EF%BE%96%EF%BE%90%EF%BD%B1%EF%BD%B9%EF%BE%9E%20%EF%BE%8B%EF%BE%9E%EF%BE%9D%EF%BD%BA%EF%BE%9E%0A20%20A%3D%232E%0A30%20COPY%238A0%2C%22karappo%2Fdayo.%22%2C13%3A%5B86%5D%3D%5B86%5D%7C%230D00%3ACOPY%238B4%2C%22%3CNUMK%20VAL%3D%22%2C10%3A%5B96%5D%3D%230D3E%0A40%20CLS%3AFORI%3D0TO74%3ALOCATEI%2510%2A3%2B3%2CI%2F10%3A%3F%22%EF%BD%A5%22%3A%5BI%5D%3DI%3ANEXT%3AN%3D75%3AS%3D0%0A50%20K%3DINKEY%28%29%3AIFK%3D0WAIT1%3AGOTO50%0A60%20IFK%3D32%3AS%3DS%2B1%3AIFS%3E4GOTO20ELSEGOTO50%0A70%20S%3D0%3AIFK%3C%3E10GOTO50%0A80%20FORI%3D24TO40%3ADRAW16%2CI%2C47%2CI%2C0%3ANEXT%3ADRAW16%2C30%2C16%2C43%3ADRAW16%2C43%2C47%2C43%3AFORI%3D0TO11%3ADRAW28%2BSIN%28I%2A30%29%2F25%2C31%2BCOS%28I%2A30%29%2F25%2C28%2BSIN%28I%2A30%2B30%29%2F25%2C31%2BCOS%28I%2A30%2B30%29%2F25%3ANEXT%0A90%20FORI%3D0TO12%3ADRAW28%2C31%2C28%2BSIN%28I%2A30-30%29%2F42%2C31%2BCOS%28I%2A30-30%29%2F42%2C0%3ADRAW28%2C31%2C28%2BSIN%28I%2A30%29%2F42%2C31%2BCOS%28I%2A30%29%2F42%3AWAIT3%3ANEXT%0A100%20IFN%3C1IFAA%3DA%2A!I2CW%28A%2C%238A0%2C14%29%3AGOTO50ELSEGOTO50%0A110%20LOCATE21%2C20%3A%3FCHR%24%28%238F%29%3AWAIT60%3AC%3DRND%28N%29%3AV%3D%5BC%5D%2B1%3AN%3DN-1%3A%5BC%5D%3D%5BN%5D%3AF%3D%28%23180%2BV%2F10%2A8%29%2A%28V%3E9%29%3AG%3D%23180%2BV%2510%2A8%3AIFV%3E9%5B95%5D%3DV%2F10%2BV%2510%3C%3C8%2B%233030%3AELSE%5B95%5D%3DV%2B%232030%0A120%20FORI%3D18TO43%3ADRAW16%2CI%2C47%2CI%2C0%3ANEXT%0A130%20IFAA%3DA%2A!I2CW%28A%2C%238B4%2C14%29%0A140%20FORI%3D0TO7%3ALOCATE8%2C12%2BI%3AP%3DPEEK%28F%2BI%29%3AFORJ%3D0TO7%3A%3FCHR%24%28P%3E%3E%287-J%29%261%2A%238F%29%3B%3ANEXT%3ANEXT%3AFORI%3D0TO7%3ALOCATE12%2B4%2A%28V%3E9%29%2C12%2BI%3AP%3DPEEK%28G%2BI%29%3AFORJ%3D0TO7%3A%3FCHR%24%28P%3E%3E%287-J%29%261%2A%238F%29%3B%3ANEXT%3ANEXT%0A150%20LOCATE%28V-1%29%2510%2A3%2B2%2C%28V-1%29%2F10%3A%3FDEC%24%28V%2C2%29%0A160%20GOTO50%0ARUN%0A) (公式、低速)

# 操作方法

|キー|役割|
|---|---|
|Enter|次の抽選を行う|
|スペース|5回連続で押すことで、状態をリセットする|

# 実行結果例

<iframe width="560" height="420" src="https://www.youtube.com/embed/Z2g0XNYBZNA?si=WxKDAdqIvEHHVQaY" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

起動。

![起動直後](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/7a07f2a3-d90f-a7ad-a0fa-3629ed2b5f4e.png)

Enter キーを押すと、抽選器が回転する演出が入り…
~~しかし実機だと丸のつもりの図形が汚いなあ…~~

![抽選演出](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/2898b545-4b57-67fb-049c-d790034526f7.png)

抽選器から玉が出て…

![玉が出た](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/33657471-439a-8021-c74b-9fd6bbd7c6d0.png)

選ばれた数字が表示されるとともに、読み上げられる。

![数字の表示](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/7d7b9310-821c-482e-2809-28253d6f51e1.png)

再び Enter キーを押すと、次の数字の抽選を開始する。

![次の数字の抽選](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/42a37f7b-1bfe-4415-6642-ee341a53cbc6.png)

選ばれた数字は、画面上部に表示される。

![選ばれた数字が増えてきた](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/ba0073e6-19a1-f086-6642-9d9b295630e0.png)

# 解説

## タイトル

```text
10 ' ﾖﾐｱｹﾞ ﾋﾞﾝｺﾞ
```

慣例に沿って、最初の行にタイトルを入れている。

## 画面と状態の初期化

```text
40 CLS:FORI=0TO74:LOCATEI%10*3+3,I/10:?"･":[I]=I:NEXT:N=75:S=0
```

画面をクリアし、出た数字を描画するエリアに「・」を描画する。
ついでに、`[0]`～`[74]` で管理している残りの玉の状態を初期化する。
また、残りの玉の数 `N` を 75 に、スペースキーを押した回数 `S` を 0 に初期化する。

## キー入力の受け付け

```text
50 K=INKEY():IFK=0WAIT1:GOTO50
60 IFK=32:S=S+1:IFS>4GOTO20ELSEGOTO50
70 S=0:IFK<>10GOTO50
```

キー入力を受け付ける。
スペースキーが押されたら、回数をカウントし、5回になったら状態をリセットする。
スペースキー以外が押されたら、スペースキーが押された回数を0に戻す。
エンターキーが押されたら次の処理に進むが、それ以外のキーが押されたときはキー入力の受付に戻る。

## 抽選器の描画

```text
80 FORI=24TO40:DRAW16,I,47,I,0:NEXT:
   DRAW16,30,16,43:DRAW16,43,47,43:
   FORI=0TO11:
     DRAW28+SIN(I*30)/25,31+COS(I*30)/25,28+SIN(I*30+30)/25,31+COS(I*30+30)/25:
   NEXT
90 FORI=0TO12:
     DRAW28,31,28+SIN(I*30-30)/42,31+COS(I*30-30)/42,0:
     DRAW28,31,28+SIN(I*30)/42,31+COS(I*30)/42:
     WAIT3:
   NEXT
110 LOCATE21,20:?CHR$(#8F):WAIT60:
```

まず、数字が描かれる領域を黒く塗りつぶす。
抽選器の左と下の枠を描画する。
三角関数を用いて円を描画する。
ハンドルのアニメーションを行う。前に描いたハンドルの位置を黒く塗った後、今のハンドルの位置を描画する。
最後に、抽選器から出た玉を描画する。

## 抽選の実行

```text
(110) C=RND(N):V=[C]+1:N=N-1:[C]=[N]:
      F=(#180+V/10*8)*(V>9):G=#180+V%10*8:
      IFV>9[95]=V/10+V%10<<8+#3030:ELSE[95]=V+#2030
```

残っている玉からどれを出すか `C` をランダムに選ぶ。
選んだ玉 `V` を出す。
残っている玉の数 `N` を減らし、出した玉の場所に最後の玉を入れる。
出た数字の十の位のキャラクターパターンのアドレスを `F` に、一の位のキャラクターパターンのアドレスを `G` に格納する。ただし、出た数字が一桁の場合、十の位は空白とする。
出た数字を読み上げ用の表現にして、`[95]` に格納する。

## 数字の描画

```text
120 FORI=18TO43:DRAW16,I,47,I,0:NEXT
140 FORI=0TO7:
      LOCATE8,12+I:P=PEEK(F+I):FORJ=0TO7:?CHR$(P>>(7-J)&1*#8F);:NEXT:
    NEXT:
    FORI=0TO7:
      LOCATE12+4*(V>9),12+I:P=PEEK(G+I):FORJ=0TO7:?CHR$(P>>(7-J)&1*#8F);:NEXT:
    NEXT
150 LOCATE(V-1)%10*3+2,(V-1)/10:?DEC$(V,2)
160 GOTO50
```

抽選器の絵の領域を黒く塗りつぶす。
`F` および `G` に格納したアドレスを用いて、出た数字の十の位と一の位をそれぞれ描画する。
出た数字が一桁の場合は、一の位を真ん中に描画する。
最後に、出た数字を画面上部に描画し、キー入力の受け付けに戻る。

## 数字の読み上げ

```text
20 A=#2E
30 COPY#8A0,"karappo/dayo.",13:[86]=[86]|#0D00:COPY#8B4,"<NUMK VAL=",10:[96]=#0D3E
100 IFN<1IFAA=A*!I2CW(A,#8A0,14):GOTO50ELSEGOTO50
130 IFAA=A*!I2CW(A,#8B4,14)
```

まず、Ichigo-ice の 7bit I2C アドレスを `A` に格納する。読み上げ機能を無効にする場合は、`A` を 0 にする。
読み上げ用の記号列を、配列の玉で使わない部分に格納する。ここで終端の CR も含めておく。
抽選後、I2C アドレスが有効であれば、読み上げ用の記号列を送信する。このとき、送信に失敗した場合はアドレスを 0 に設定し、以降の読み上げを無効にする。

# 他のビンゴマシン

IchigoJam を用いたビンゴマシンは他にもいくつか公開されているが、数字の読み上げ機能を持つものは見つけられなかった。

* [★ネットで挑戦★ ビンゴマシンを作ろう](http://www.white.umic.jp/jypc/files/ichigojam-bingo.pdf)
* [2015-04-10 ビンゴゲームVer.2](https://www.ichigojaman.jp/entries/2015/04/10)