配列の並びを変えただけで、セーブデータの街が別物になった
クラッシュしないから、気づきにくいバグだった。
日本進化シミュレーション第14回 / 全16回目次
「AI自動開発で、平地に港が乱立している」という報告が届いた。
送ってもらったスクリーンショットを見ると、たしかに内陸のど真ん中に、港とおぼしき建物がいくつも並んでいる。
港は海沿いにしか建てられないはずなのに、そのルール自体が壊れたように見えた。
直前にやった作業を疑うところから始めた
ちょうど少し前に、発電所や消防といった施設に、複数の性能・コスト段階を持たせる作業をしていた。
石炭火力・水力・原子力から選べる発電所、といった具合に、同じ用途の施設を複数のバリエーションに増やす変更だ。
この作業で、施設の種類を管理している配列の途中に、新しいエントリを何個も差し込んでいた。
時期的に一番怪しいのはここだと僕は当たりをつけて、確認を始めた。
セーブデータには、建物の「種類」ではなく「配列の位置」が入っていた
調べて分かったのは、セーブデータの中で、マスに建っている施設の種類が、施設の名前ではなく配列の生のインデックス番号として保存されていたことだった。
配列の8番目が発電所だったとする。
そのセーブデータは「このマスには8番の施設が建っている」とだけ記録している。
今回の変更で、市場や港のあたりに新しいエントリを差し込んだせいで、8番目の中身が発電所から別の施設へとズレてしまっていた。
古いセーブデータを読み込むと、8番という数字だけを頼りに、新しい配列の8番目、つまり本来は港だったはずの位置を指してしまう。
中身は元々発電所だったのに、新しい配列では港として再解釈される。
発電所は元々内陸に建つ施設なので、「港が内陸に乱立している」という、一見まったく無関係に見える症状として現れていた。
クラッシュしないから、気づきにくい
このバグの一番厄介なところは、エラーにならないことだった。
8番目という位置は配列の中にちゃんと存在するので、参照そのものは成功する。
ただ、指している中身の意味が変わっているだけ。
プログラムは何も間違えていないと思い込んだまま、正常に動き続ける。
外から見た結果だけが、静かにおかしくなっていく。
この手のバグは、テストが通っていても防げない。テストは「動くこと」は確認できても、「意味が変わっていないこと」までは確認してくれないからだ。
対応は、バージョン番号と変換表
セーブデータに、施設配列の版数を表す番号を追加した。
古い版数のまま保存されたデータを読み込む時だけ、旧配列の位置から新配列の位置への対応表を通して、正しい位置に変換し直す。
対応表は、旧22種類の施設が、値が完全に一致する新しい段階のどれに当たるかを、一つずつ手で確認して作った。
地味な作業だったけれど、ここを機械的に済ませようとすると、また別の思い込みでズレを作りかねないと思い、あえて一つずつ目で確認した。
もう二度と踏まない、とは言い切れない
今後もし、この配列の並びをまた変えることがあれば、必ず版数を上げて対応表も更新する。
そう決めて運用しているけれど、正直に言うと、これは「気をつける」という人間の注意力に頼った対策でしかない。
本当は、配列の生の位置ではなく、施設ごとに固有のID文字列のようなものをセーブに使うべきなのかもしれない。
そこまでの作り替えは、今回はまだ手をつけていない。
次に同じ種類の変更をするときに、改めて考えたい。
※運営者が個人で書いているnoteです。