概要
Minecraft内でQRコードを作成できるdatapackを作りました.この記事は作成記です.
この記事はQRコードの仕組み等を解説するものではありません. QRコードの仕様については他サイトを参照してください.
QRコードは株式会社デンソーウェーブの登録商標です.
データパック
細かいところの実装は不十分です (エスケープ文字など).気が向いたら詰めます
できること
String型NBTからQRコードを作成できます.それだけです.
作成にあたって
実装にあたってはQR Code Tutorial - Thonky.comを全面的に参考にしました.
まずは普通のプログラミング言語で実装したものをコマンドでも実装しやすいような処理に書き換え,それを移植する方針でやりました.
コマンドで実装する上での一番の問題点はコマンド実行数上限です.そもそも QR コード自体が最大で $177\times 177=31329$ マスになるというどうしようもない制約があるので,ある程度は諦めて実装しやすさを優先し,なんとかなりそうなところはコマンド数削減を図りました.
QR コード生成のステップ
QR コード生成に必要な処理は大まかには次のようになります.
- モード判定
- 大きさ判定
- データエンコード
- 誤り訂正符号生成
- QR コード生成
- マスク適用
モード判定
QR コードは次のモードが主に用いられます.
- 数字モード:
0-9
のみ. - 英数字モード:
0-9A-Z $%*+-./:
のみ. - バイトモード:バイナリを扱える.今回は UTF-8 でエンコードした.
- 漢字モード:Shift-JIS で一定の範囲にある文字を扱える.
今回は実装が面倒で漢字モードを諦めました.
数字モード・英数字モードが使えるかの判定は一文字ずつ見ていけば比較的容易です(データエンコードと同様です).
なおコマンド上では半角空白が2つ以上連続していると1つに縮約されることに注意が必要です.またバイトモードでは\
や"
や'
は別に処理する必要があります.
大きさ判定
各サイズでの最大文字数などのパラメータは全部埋め込んでいるのでそれを確認します.
データエンコード
文字列を 01 列に変換する必要があります.
- あらかじめ
{"A":[...],"B":[...],...}
といった形の辞書データを準備しておきます. - 文字列が空でない間,次のことを繰り返します.
-
data modify
のset string <source> [<sourcePath>] 0 1
で先頭の1文字を切り出します. - マクロを用いてその文字に対応する辞書のデータを読み出します.
-
data modify
のset string <source> [<sourcePath>] 1
で先頭1文字を削除します.
-
数字モード・英数字モードでは変換する文字列を何文字かごとに区切り,そこをまとめて変換する必要があります.1文字ずつ見てもいいですが,面倒なのでありうる文字の組を全て埋め込みました.
バイトモードでは各文字の文字コードを取得しなければいけません.全て埋め込むことは現実的でないので,デフォルトで使用可能な文字をある程度限定した上で外部から対応文字を追加できるようにしました.
誤り訂正符号生成
誤り訂正符号の生成には,ガロア体 $GF(256)$ での多項式除算を行う必要があります.
$GF(256)$ の演算は埋め込みました.一応の工夫として $0,\dots,255$ ではなく $-128,\dots,127$ で値を持つことで byte 型で扱えるようにしました.List で負の index も使用できるの圧倒的感謝.
多項式除算については,誤り訂正符号生成においては割る方の多項式は入力データに依存しません.それらを埋め込んで筆算でもよいですが実装が若干面倒な気がしたので,あらかじめそれらで $x^0,x^1,x^2,\dots\in GF(256)[x]$ を割った結果を埋め込んでおき,その結果を線型結合することで実装しました.
QR コード生成 / マスク適用
固定のパターンや生成したデータを順番通り並べるだけです.データを並べる時にはループをいい感じに回さないといけないので面倒といえば面倒ですが他のパートよりは圧倒的に楽です.
またマスクはデータの部分だけ適用しなければいけないので,今回はコード生成してからマスク適用するのではなく,マスクを適用しながらコードを生成することにしました.
最善マスク判定
やることは単純ですがコマンド数がすごいことになるので今回は実装しませんでした.
感想
実際に QR コードが表示できるまではデバッグはひたすら数列との睨めっこなので苦しかったです……ただ表示できて実際に読み込めるとかなり嬉しさがあってよかったです(こなみ)
コマンド数がすごいことになるので実用性は怪しいです.もしかしたらシェーダーでも出来る?