ステージデータ

スクリプト内でのステージデータを保持方法についてメモしておきます。

9x9のフィールドデータ部分は、横3マスをASCII文字1Byteで表現しており、81マスで27文字使います。
これに、敵と赤ポーションの数を示す1文字を付けた構造で、1ステージ分を正味28バイトの文字列データとします。
エンコードの際、各マスについて取りうる4値を、空白:0、魔法陣:1、紫魔石:8、赤魔石:9 と置き、
1マス毎に1ビットシフトした値をORして 0〜63 とし、63でなければ+64して文字コードにします。
これで"@"(64)〜"~"(126)と"?"(63)の文字コードが得られます。
元が63の場合は+64すると制御コードのDEL(127)になってしまうのでそのまま63→"?"で扱っています。
ポーションの個数(0〜7)と敵の数(0〜7)については、敵の数×8+赤ポーションの数 で0〜63の値を作り、
同様に1文字のコードに変換しています。


スクリプト内での変数代入については、{"〜"}による文字列データ複数行表記を使って1面1行で記述。
各面の区切りがCR+LFになるので、メモリーノートパッド関連の命令が使えます。
スクリプトの都合上、ステージ1の前にCR+LFが1つ、最終ステージの後にNUL終端の1文字を要するので、
30面で(2+28)*30+1=901Bytesとなります。1面あたり30Bytesのデータ量です。
デコード時、取り出したフィールドデータは、シフトしながらマスク値9でAndして、各マスの種類にします。


ここでのポイントその1
「オフセットが+64、元の値が63のときにはオフセットしない」という変化ルールは一見複雑ですが、
デコード処理の視点で考えると、下位6Bitが不変なのでオフセットを気にせずシフト&マスクできます。
簡単に+63のオフセットで"?"〜"~"とすることもできますが、その場合、デコードの際にもシフト&マスク
の前に-63(もしくは+1)しなければならず、かえってコストがかかります。


ポイントその2
マスの4値を0,1,2,3とせずに0,1,8,9としたのは、cntで操作するマスを進めつつ、フィールドデータの方はcntを3で
割った余りでシフトさせたかったので、シフト量とマス操作が一致している方が都合が良いからです。
0,1,2,3は2進で00〜11なので1マス分のマスク値は3(2進数で11)となりますが、連続したビットを使っているため
有効ビットが被らないようにORを行なうには、2ビットずつシフトする必要があります。
3マスに割り当てるビットをAa,Bb,Ccで表現するとCcBbAaです。シフト量を2倍する際の掛け算で8バイト使うのはもったいない。
これに対し、2,3の代わりに8,9を使えば、マスク値は9(2進数で1001)が使えるため、有効ビットが被らないように
ORを行う場合に1ビットずつのシフトでOKとなります。(CBAcbaのビット割当)