本文へスキップ
alzy.kr
開発日誌

解放の線を引き上げた日、すでに越えていた人の分だけは残した

タヌビの仲間は、遊んだ累計点で順に開きます。この日、私はいちばん奥に置いてあったキツネの解放ラインを引き上げました。理由は一行で書けます。最後の一人が、最後らしくなかったからです。ただ、解放条件というのは設定ファイルの数字であると同時に、すでにその数字を越えて仲間を手に入れた人の記録でもあります。線だけ動かすと、昨日までキツネを使っていた人が次にページを開いたとき、キツネが閉じている——そういうことが起こります。この記事は、線を引き上げると決めた判断と、すでに越えていた人の分をどう残したか、そしてその「残す」を思い込みで終わらせないためにどんなテストを書いたかの記録です。数字そのものは今のゲーム画面の値とは違います。ここに書くのは二〇二六年七月二十五日時点の話で、その後さらに引き上げているためです。その事情は最後の節に書きます。

記録日: 2026-07-25

最後の一人が、最後らしくなかった

キツネは、当時の並びでいちばん奥にいる仲間でした。壁に張りついて滑り、逆側へ蹴って登る——他の誰も持っていない動き方をします。集めていく遊びで最後に置かれるものには、そこへ着いたこと自体が出来事になってほしい、と私は思っています。長く走った末にやっと開くから、開いた瞬間に意味が出る。順番の最後にいることと、最後らしい重さを持っていることは、別のことです。

このとき手元にあったのは、その二つが一致していないという私の見立てだけでした。何人がどのくらいでキツネに届いていたかを数えて確かめたわけではありません。だから、これは計測に裏づけられた結論ではなく、設計の意図から出た判断です。そのうえで、最後の一人を「特別な最後」にするために線を引き上げる、と決めました。判断の根拠が薄いと自覚しているぶん、あとで戻せる形にしておくこと、そして戻せないもの——人がすでに手に入れたもの——には触れないことを、同時に条件にしました。

難易度や解放条件の調整は、コードとしてはいちばん安い変更です。定数を一つ書き換えるだけで終わる。安いのは書く側にとってだけで、その変更の代金は、たまたまその線の近くに立っていた人が払います。今回で言えば、旧い線は越えているが新しい線には届いていない人です。安い変更ほど、代金を誰が払うのかを先に数えたほうがいい——この件で私がいちばん強く思ったのはそこでした。

線を動かすと、すでに越えた人の足元が動く

解放の判定は、その時点では「累計点が今の閾値以上か」という一本の式でした。この形だと、閾値を上げた瞬間に過去の判定までさかのぼって書き換わります。累計点は減らないので本人の記録は何も失われていないのに、判定式の右辺が変わったせいで結果だけがひっくり返る。旧い線と新しい線のあいだにいる人にとっては、自分は何もしていないのに持ち物が消えたのと同じです。

このとき私が怖かったのは、返ってくる苦情ではなく、返ってこないほうでした。ページを開いて、いたはずのキツネが閉じていて、何かの間違いだろうかと少し考えて、そのまま閉じる。こちらには何も届きません。集めるという遊びは、集めたものが積み上がり続けるという前提の上に成り立っています。その前提を一度でも破ると、次に開くものへ向かう理由まで一緒に薄くなる——これは私の考えで、測って確かめたことではありませんが、集めた側の立場で考えれば十分にありそうなことだと思っています。

そこで、この変更には二つの部品が要ることになりました。一つは新しい線。もう一つは、旧い線をすでに越えていた人の分を、新しい線の外側に安全に置いておく場所です。後者がないなら、前者は入れないほうがましだと考えました。

持っているものは、取り上げない

置き場所として作ったのは、進行データの中の「永久解放リスト」です。ここに入った仲間は、累計点がいくつであっても開いたままになります。解放の判定は一本の式から、「永久解放リストに入っているか、または今の閾値を越えているか」という二段構えに変わりました。点数はこれまでどおり誰でも開ける道として残り、そこにもう一本、過ぎたことは取り消さないという道が並んだ形です。

旧い線を越えていた人をそのリストへ移す作業は、一度だけ走ります。実装では、引き上げ前の閾値を別の定数として残しておき、初回の読み込み時に、そのときの累計点が旧い線に届いていれば対象の仲間をリストへ入れて保存する。済んだかどうかは進行データの中のフラグで覚えます。フラグが立っていれば以後は何もしません。取り込みが走る場所は、進行データを読む三つの入口——ハブ・ゲーム本体・図鑑——のすべてです。どこから入ってきても同じ結果になってほしかったからで、入口ごとに違う顔を見せる救済は、救済として信用できないと思っています。

合わせて、次の目標を指す表示のほうも直しました。永久解放で持っている仲間を「次に開くもの」として提示してしまうと、すでに使っている相手に向かって進捗バーが伸びるという、意味の通らない画面になります。救済はデータの中で静かに終わるだけでは足りなくて、画面に出ている言葉と食い違わないところまでが仕事でした。この解放まわりは端末側に置いている情報で、地形の生成やスコアの判定、順位表には触れていません。手が届く範囲を最初から狭くしておくと、間違えたときに壊れる範囲も狭くなります。

「取り上げない」をテストに変える

無損失というのは、言うだけならただの意気込みです。意気込みは半年後のリファクタリングで消えます。だから同じPRの中で、この約束をそのままの形でテストに書き写しました。日本語で書けば、「旧い線を越えていた人はこの先どうなってもキツネを持っている」「新しく始めた人は旧い線に届いた程度では開かない」の二つです。

検査として置いたのは、その二つを含む一組です。旧い線ちょうどの累計点を持つ既存の記録は取り込まれて開いたままになること。まったく同じ累計点でも、新しく始めた人は開かず、新しい線まで貯めて初めて開くこと。取り込みが二度走っても結果が変わらないこと——一度済んだ記録を再び通すと、変更なしとして同じものが返ります。境界も両側から当てました。旧い線ちょうどは取り込まれ、そこから一点足りない記録は取り込まれない。そして保存です。取り込んだあとに読み直しても残っていること、さらにその後で累計点が失われても、キツネは開いたままであること。主の保存と予備の保存を突き合わせたときに片方でしか取り込みが済んでいなくても、合わせた結果は持っているものが減らない側——両方の和——へ倒れます。

書いてみて分かったのは、これらのテストが機能の説明ではないということです。閾値がいくつかも、リストがどんな形かも、いつか変わります。ここに固定したのは「一度手に入れたものは減らない」という一つの約束で、テストの名前もそう読めるように付けました。あとから来た誰かがこの検査を赤くしたなら、その人が壊したのは実装ではなく約束のほうです。仕様書に書いた文章は読まれないかもしれませんが、赤くなったテストはそれよりずっと目に入りやすいはずだと思っています。

残っている限界と、この記事の時点

ここまでが二〇二六年七月二十五日の話です。今のタヌビでキツネの解放に必要な点は、この記事が扱っている数字より高くなっています。この記事の少しあとに、遊べる範囲そのものの見直しがあり、そこでキツネの線はさらに上——5500まで引き上げられました。今の値と各キャラクターの解放順は攻略記事のほうに揃えてあるので、今日の目標として読みたい方はそちらを見てください。この記事はあくまで、線を引き上げると決めた日の判断の記録です。

そしてその二度目の引き上げで、今回の設計の弱いところが表に出ました。取り込みは「済んだか」を一つのフラグだけで覚えています。ところが二度目の引き上げが来ると、一度目でフラグを使い切っている人には、二度目のぶんの救済が自動では走りません。フラグを引き上げごとに分けて持つ形に作り直せば直りますが、それは進行データの構造に手を入れる話なので、別の作業として置いてあります。今のところ、その限界はソースのコメントに書き残してあるだけです。

書いておきたいのは、これが実装の抜けというより、私の見通しの誤りだったということです。一度きりの救済として作れば一度きりしか効かない。二度目があると分かっていれば、最初から回数を数えられる形にしていました。調整は一度で終わるという前提のほうが、この場合の間違いでした。

最後に、確かめられていないことも書いておきます。あの日の取り込みで実際に何人が救われたのかを、私は知りません。解放の記録は端末の中にあり、こちらから数えに行く仕組みを作っていないからです。だからこの仕事の成果は、誰も何にも気づかなかったという形でしか現れません。何も起きなかったことを確認する手立てがないまま、それでも入れる価値はあったと考えています。手に入れたものが黙って消える体験は、一度で十分だからです。

タヌビ(Tanubi)