【マイレース開発記録(11)】zone判定の設計崩壊
ここまでの開発で、
「うさぎの速さ」と「ジャンプの高さ」は計算できるようになりました。
しかし、ここで大きな問題が残っていました。
その結果を、どう意味づけるのか。
レースが動くだけでは、ただのアニメーションです。
「今日はどういう日なのか」を表すための、
ゾーン(流れの質)を設計する必要がありました。
マイレースにおける「ゾーン」とは
マイレースでは、
レース結果をただ順位として表示するだけではなく、
その日の「流れの質」を
ゾーン(Zone)として表現しています。
現在の設計では、ゾーンは次の4種類です。
- 追い風ゾーン(外の流れも内側のリズムも良い)
- 慎重ゾーン(流れはあるが無理は禁物)
- 楽しさ重視ゾーン(気分や好奇心を優先)
- 整えるゾーン(休息・回復を優先)
それぞれのゾーンは、
- 外側の流れ(スピード)
- 内側のリズム(ジャンプ)
この2つの組み合わせから決まります。
最初の設計:かなり複雑だった
最初は、かなり単純に考えていました。
ゾーンは次の2つの要素で決めることにしました。
- スピード(外側の流れ)
- ジャンプ(内側のリズム)
つまり
速い × 跳ねる → 追い風
速い × 跳ねない → 慎重
遅い × 跳ねる → 楽しさ
遅い × 跳ねない → 整える
コードとしては、こんな形です。
Python
def detect_zone(is_fast: bool, is_jump: bool) -> str:
if is_fast and is_jump:
return "tailwind"
if is_fast and not is_jump:
return "steady"
if not is_fast and is_jump:
return "playful"
return "rest"
一見、問題はなさそうに見えます。
しかし、ここから問題が起き始めました。
なぜかゾーンが偏る
アプリを動かしてみると、すぐに違和感が出てきました。
ユーザーの入力を変えても、
ゾーンがやたらと偏るのです。
特定のゾーンばかりが出る。
別のゾーンはほとんど出ない。
これは占いとしても、UIとしてもかなり不自然でした。
原因は「スピード判定」
調べてみると、
問題は is_fast の判定方法にありました。
最初の実装では、
平均スピードより速いかどうか
で判定していました。
JavaScript側ではこう書いていました。
JavaScript
const avg = rs.map(x=>st.t[x.k]).reduce((a,b)=>a+b,0) / rs.length;
const isFast = st.t["work"] <= avg;
つまり、
平均より速いかどうか
だけで判定していたのです。
しかしこれには大きな問題がありました。
平均値トラップ
レースには5匹のうさぎがいます。
平均値を使うと、
必ず
- 速い側
- 遅い側
が生まれます。
つまり、
「普通」という状態が存在しない
のです。
結果として、ゾーン判定がかなり極端になりました。
AIとのデバッグ
ここでAIと一緒にコードを整理しました。
まず行ったのは、
状態を分解することです。
- スピード
- ジャンプ
- フェーズ
をそれぞれログに出して確認しました。
この段階で初めて、「どこが歪んでいるか」が見えてきました。
発達特性とデバッグ
私は開発の中で、
- 状態が複雑になる
- 複数の条件が絡む
という場面になると、
どこが原因なのか分からなくなる
ことがあります。
今回のゾーン問題も、最初は完全に混乱していました。
ですがAIとの対話を通して、
- 条件を一つずつ分離する
- ログを出して確認する
- 仮説を立てて検証する
という手順を整理することができました。
このプロセスは、私にとって非常に大きな助けになっています。
設計の見直し
最終的に、ゾーン判定は
2つの軸
で整理することにしました。
外側の流れ
天体トランジット → スピード
内側のリズム
位相フェーズ → ジャンプ
この2つの軸を掛け合わせることで、4つのゾーンが自然に分かれる形になりました。
設計が崩れるのは普通
今回のゾーン問題は、完全に設計ミスから始まりました。
しかしこの経験を通して実感したのは、設計は最初から正解にならない
ということです。
実装して
動かして
崩れて
修正する。
その繰り返しで
やっと形になっていきます。
次回予告
ゾーン判定を整理したあと、今度は別の問題が起きました。
コードの中に、同じ関数が2回定義されているというバグです。
しかもその関数は、今回のゾーン判定の中心でした。
次の記事は、
として、
バックエンドとフロントのロジックが衝突した話を書きます。


