IchigoJam で13日の金曜日を探す

[IchigoJam](https://ichigojam.net/) で「13日の金曜日」を探してみた。
前後2年、合計5年分の13日の曜日を表示し、金曜日ならハイライトする。
表示する範囲は移動できる。

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

# プログラム

```
10 ' 13 ﾆﾁ ﾉ ｷﾝﾖｳﾋﾞ
20 N=2023
30 IF!NPOKE#7FE,#0A:IFI2CR(#51,#7FE,1,#7FF,1)N=2023ELSED=PEEK(#7FF):N=2000+D/16*10+D%16
40 POKE#700,16,16,124,16,16,16,254,0,126,66,66,126,66,66,126,0,62,34,62,34,62,66,134,0,16,16,84,88,16,40,198,0,16,18,244,56,84,146,48,0,16,254,16,56,84,146,16,0,16,40,254,16,254,84,254,0
50 POKE#700+8*7,64,126,144,124,80,254,16,0,136,190,136,136,184,204,186,0,62,66,222,86,94,66,70,0,30,234,190,228,174,252,14,0
60 FORI=0TO8*11-1:POKE#780+I,~PEEK(8*#30+I):NEXT:FORI=0TO7:POKE#780+8*11+I,~PEEK(8*#E2+I):POKE#780+8*12+I,~PEEK(8*#E6+I):NEXT
70 CLS:?13;CHR$(#E1,#E8,#E9,#EA,#E1);"?":FORD=-2TO2:Y=N+D:LOCATE(Y<1000)+(Y<100)+(Y<10),11+4*D:?Y;CHR$(#E7):FORM=1TO12:L=M:X=Y:IFL<3X=X-1:L=L+12
80 C=X/100:Z=X%100:G=5*C+C/4:H=(13+26*(L+1)/10+Z+Z/4+G)%7:K=H=6:LOCATE6+(M-1)%4*6,11+4*D+(M-1)/4:IFM<10?CHR$(#20+#6F*K);
90 IFKANDM>9?CHR$(#F0+M/10);
100 IFK?CHR$(#F0+M%10);ELSE?M;
110 ?CHR$(#E2+#19*K,#3A+#C0*K,(#E0+H)*!K+#FC*K):NEXT:NEXT
120 K=INKEY():D=(K=DOWNORK|#20=#61)-(K=UPORK|#20=#71):IFDN=N+D:GOTO70ELSEGOTO120
```

このプログラムは、[CC0 1.0](https://creativecommons.org/publicdomain/zero/1.0/deed.ja) でライセンスする。

```
20 N=2023
```

により、表示範囲の中央を設定している。この行を

```
20 N=0
```

とすると、[GROVE - 高精度RTC](https://www.switch-science.com/products/3134) から年を取得し、取得した年を表示範囲の中央の初期値とする。
取得を試みて失敗判定となった (`I2CR` が非零を返した) 場合は初期値を2023年に設定するが、I2C 機器を全く接続していない場合に `I2CR` がフリーズするケースがあったため、20行目により取得の試み自体を行わない設定にできるようにした。

# 操作方法

* `Q` キー / 矢印上キー：表示範囲を過去に移動する
* `A` キー / 矢印下キー：表示範囲を未来に移動する

UART経由でも操作しやすいよう、矢印キーに加えてアルファベットキーでも操作できるようにした。

# 実行結果例

![実行結果例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/ef174a6c-bd5f-9077-2037-c3682c32da73.png)

# 解説

## 10行目：タイトル

`FILES` 対応のタイトル行である。

## 20～30行目：表示範囲の初期値設定

20行目で、表示範囲 `N` の初期値を設定する。
ここで `0` に設定した場合、30行目のRTCから年を取得して初期値に反映する処理を実行する。

## 40～60行目：フォントの設定

40行目・50行目で、[美咲フォント](https://littlelimit.net/misaki.htm) (美咲ゴシック第2) のサブセットをキャラクターパターンRAMに書き込む。
今回用いる「土日月火水木金年は何曜」に対応するパターンを順に書き込んでいる。

60行目で、数字 (0～9)、コロン、「月」「金」に対応するパターンをそれぞれ白黒反転したパターンを作成する。

## 70～110行目：曜日の計算と描画

> ```
> 70 CLS:?13;CHR$(#E1,#E8,#E9,#EA,#E1);"?"
> ```

画面をクリアし、「13日は何曜日？」を描画する。

> ```
> FORD=-2TO2:Y=N+D
> ```

表示範囲の中央 `N` の前後2年の範囲を描画する。
中央との差 `D` を具体的な年 `Y` に変換する。

> ```
> LOCATE(Y<1000)+(Y<100)+(Y<10),11+4*D:?Y;CHR$(#E7)
> ```

何年かを描画する。4桁未満の場合は描画位置を調整して「年」を揃える。
0年未満や9999年超には対応していない。

> ```
> FORM=1TO12
> ```

それぞれの月 `M` に関する描画を行う。

> ```
> L=M:X=Y:IFL<3X=X-1:L=L+12
> 80 C=X/100:Z=X%100:G=5*C+C/4:H=(13+26*(L+1)/10+Z+Z/4+G)%7:K=H=6
> ```

[ツェラーの公式](https://ja.wikipedia.org/wiki/%E3%83%84%E3%82%A7%E3%83%A9%E3%83%BC%E3%81%AE%E5%85%AC%E5%BC%8F) により、それぞれの月の13日の曜日 `H` を求める。
さらに、それが金曜日かを判定し、変数 `K` に格納する。

> ```
> LOCATE6+(M-1)%4*6,11+4*D+(M-1)/4
> ```

それぞれの月の描画位置にカーソルを移動する。

> ```
> IFM<10?CHR$(#20+#6F*K);
> ```

月が1桁の場合、空白を出力して描画位置を合わせる。
金曜日の場合は白い空白 `#8F` を、そうでない場合は黒い空白 `#20` を出力する。

> ```
> 90 IFKANDM>9?CHR$(#F0+M/10);
> ```

金曜日の場合、かつ月が2桁の場合、月の十の位を白黒反転した数字で描画する。

> ```
> 100 IFK?CHR$(#F0+M%10);ELSE?M;
> ```

金曜日の場合、月の一の位を白黒反転した数字で描画する。
それ以外の場合、月を普通の数字で描画する。(存在すれば十の位も含む)

> ```
> 110 ?CHR$(#E2+#19*K,#3A+#C0*K,(#E0+H)*!K+#FC*K)
> ```

「月：」および曜日を出力する。
金曜日の場合は白黒反転した文字を、そうでない場合は普通の文字を用いる。

> ```
> NEXT:NEXT
> ```

月のループ、および年のループを進める。

## 120行目：操作受付

入力されたキーに応じて、変数 `D` に描画範囲の移動幅を書き込む。
この移動幅が非零になったら、描画範囲に反映し、描画処理を実行する。
キーの値と `#20` の論理和をとることで、入力がアルファベットである場合小文字に変換し、小文字のコードとの比較のみをすればよいようにした。