メモリが少ないときは、std::mapよりstd::vectorを使用しよう

現在サウンドノベルを作成しているのだが、すでに一度通過したことがある場所は
スキップを行うことができるようにするという処理を導入する場合、スクリプト命令一つにつき
変数一つを用意して0を代入しておき、通過したら1を代入する。


スキップ処理の開始が始まったら、各変数が0か1かを判断し、1であるならばスキップ、0であるならばスキップ停止とする。
スクリプトファイルは複数あるため、定義は以下となる。

std::vector<std::vector<unsigned char> > check; // check[ファイル][行数] = 通過済みの有無

合計で、3万命令くらいあったので、必然と30kbほど持ってかれた。
ビット使えば 1/8 になるじゃん、とかあるけど今回は別の話。


そしてこの後、既読率を導入することなった。
既読率は、スクリプト命令の中から、メッセージ表示の命令のみを抜き出すわけだが
↑のcheckをそのまま使うと、メッセージ命令の身の数が把握できないため、別途、チェック用の変数を作った。

typedef unsigned char uint8;
typedef unsigned short uint16;
typedef std::map<uint16, uint8> Map1;
typedef std::map<uint16, Map1> Map2;
Map2 check2; // check2[ファイル][行数] = 既読の有無

↑のようにすることで、既読率は

int cnt = 0;
int cnt2 = 0;
Map2::iterator it = check2.begin();
for (; it != check2.end(); ++it) {
    Map1::iterator it2 = it1->second.begin();
    for (; it2 != it1->second.end(); ++it2) {
        ++cnt1;
        cnt2 += it2->second;
    }
}
double alreadyRead = (double)cnt2 / cnt1;

と、したわけです。
ちなみに、メッセージ描画命令数は約2万ほどあるのですが、これで消費したメモリの量が、700kb↑でした。
メモリ消費が少なくなるかと思いきや、増量は実に35倍!!!
びっくりですな。まぁ、内部でやっていることをよくよく考えればメモリが消費されて当然でした。


結局スキップ用のcheckの仕様を
0:通常命令、通過なし
1:メッセージ命令、通過なし
2:通常命令、通過あり
3:メッセージ命令、通過あり
と、変更することで問題なく動作しましたとさ。