地形生成レポートの読み方
数値は stats/terrain.yaml にあります。
tests/diagnostics/terrainStatsReport.test.ts が、定義(src/assets/world-codex/*.yaml)から
生成した島だけから計算したものです。terrain_generation.yaml を変更したら再生成します。
npm run stats:terrain
この文書は手書きで、再生成しても書き換わりません。 持つのは読み方——何を測ったか、どこに線を 引いたか、何を数えていないか——だけです。数値そのものは1行も書きません(書けば、再生成した YAMLとずれます)。
YAMLの節
unit は、そのレコードの測定値(mean〜max・share)の単位です。件数(n・seeds・
islands)は単位を持ちません。1つのレコードが違う量を並べて持つ節では、unit を置かずに
キーの名前へ単位を入れています(round_trip_minutes・present_percent など)。
base は、そのレコードがどの拠点から見た値かです(選び方は「島の広さ」節)。
分布のレコードは mean・min・p5(5%ile)・p95・max・sd(標準偏差)・n(標本数)を
持ち、標本が足りずに決まらない数は null です。
| 節 | 中身 |
|---|---|
meta |
回した種の数 |
island |
島1つあたりの分布(metric が測った項目) |
location_type_counts |
土地の型ごとの、出現する島の割合と1島あたりの個数 |
site_degree |
土地1つあたりの次数(全島の全土地をまとめた分布) |
site_degree_histogram |
同じものの割合(or_more: true の行は「その本数以上」) |
site_elevation |
土地の海抜(group が土地の組) |
site_elevation_by_location |
同じものを土地の型ごとに分けたもの |
path_discovery |
その土地の道が見つかるまでの探索時間 |
path_discovery_by_degree |
同じものを道の本数ごとに分けたもの |
edge |
道1本あたりの距離・両端の高低差・移動時間 |
base_one_way |
拠点から他の土地への片道 |
base_farthest_round_trip |
拠点から最も遠い土地までの往復 |
daily_budget |
1日の枠の割り付けと、そこから出る日帰りの上限 |
work_piles |
1周回に積む山1つずつの量 |
work_piles_by_system |
同じものを系統ごとにまとめた合計 |
work_piles_total |
山の合計と、屋外・拠点への割り |
exploration_phase |
探索の局面(島を開き切るまで)の分布 |
exploration_day_trip_islands |
日帰りだけで開き切れる島の割合 |
steady_phase |
定常の局面(開き切った後)の1日の分布 |
steady_phase_islands |
定常の局面が日帰りで成立する島の割合 |
steady_phase_by_work_share |
山の配分ごとの内訳 |
cycle |
局面を積んだ1周回の日数 |
この表とYAMLが食い違うと npm test が赤くなります。 表に挙げた節がYAMLに在って空でないことと、
表に無い節がYAMLに無いことの両方を、生成元のテストが見ます。
計測方法
- 次数 = その土地に繋がっている道の本数。道は無向で、辺1本が両端の次数を1ずつ増やす。
- 余分な道(
extra_edge_count)= 道の本数 − (土地数 − 1)。全土地を繋ぐのに最低限必要な本数(MST)を 超えた分。extra_edge_ratioはそれを土地数で割った割合。 - 標準偏差は標本標準偏差(n-1)、5%ile/95%ileは最近隣法(nearest-rank)。
土地の種類ごと
同じ地形は環境も発見物も見た目も同じなので、並べても島は広くならない。個数は
max_sites_per_type で頭打ちにし、そこへ届く前から crowding_penalty で他の型へ譲らせている
(TerrainGeneration.md 3.4節)。
location_type_counts の mean_per_island は出なかった島も0個として数えた平均、
mean_when_present はその型が出た島だけでの平均。island の location_types は、
島1つに出た型の数(同じ型がいくつあっても1と数える)。
道ごと
移動時間は「距離 ÷ 歩く速さ × 両端のmove_costの平均 + 高低差 ÷ 登り下りの速さ」
(TerrainGeneration.md 3.5節)。距離も高低差も現実の長さで、縮尺と速さは
generation_scopes.island が別々に宣言している。
土地の高さ
site_elevation の group は土地の組で、all(全部)・coast_band(coastal_distance が
coast_band 以下=海に接する土地)・inland(残り)。location_type ではなく軸の値で分ける
——砂浜と岸壁を分ける高さ(TerrainGeneration.md 3.5.3節)は、型が選べるかの条件として標高軸の上に
引く線で、切り分けているのは型が決まる前の海岸帯の高さだから。
site_elevation_by_location は同じものを型ごとに分けたもの。海抜は軸の値を
elevation_top_meters ÷ 軸の値域 でメートルへ直したもので、島の最低点は必ず0m、最高点は必ず
elevation_top_meters(同3.5節)。
道が見つかるまで
path_discovery は、その土地に居続けたときに、道が見つかるまでに費やす探索時間。通う移動は
含まない。first_path/last_path はその土地の最初/最後の道、gap は隣り合う道どうしの間隔
(道が1本だけの土地は標本に入らないので、n が2本以上の土地の道の隙間の数)、full_exploration
はその土地を探索率100%まで開くまで——1本目が早いかどうかを読む物差しで、道の話ではない。
path_discovery_by_degree は同じものを道の本数ごとに分けたもの。本数の側は出た分だけ行が増える
(上限で畳まない)ので、site_degree_histogram に出る本数がそのまま並ぶ。
割り当てそのものは ExplorationSystem.md 3.2節で、時刻表を引くのは
src/analysis/pathDiscovery.ts(実体化する側と同じ割り当てを見る)。
島の広さ
base_one_way は、拠点から他の土地への片道(最短経路)の平均。拠点を選ぶと縮む——プレイヤーは
拠点を選べるので、1周回で実際に払うのは base: shortest_mean(他の土地への片道が平均で最も短い
土地)のほうで、base: any はどの土地を拠点にしてもよいときの分布。
base_farthest_round_trip は、同じ2つの拠点の採り方で見た最も遠い土地への往復。平均ではなく
最も遠い1つを見るので、補給を持たずに出られる範囲が島の広さで決まるかに答える
(GameEndings.md 9.2節)。比べる先は daily_budget の day_trip_one_way の往復ぶん。
1周回に積む山
work_piles は、ContentSkeleton.md 4節が「1日以上の山」として数えているもの1つずつ。何を山と
数えるかは宣言(src/analysis/dailyPhases.ts の WORK_PILES)で、量の大小からは決まらない
——磨いた石器のように、労働は要るのに開けるものが無いものは山に立たない(同節)。
objects が量の出どころ。型の名前の並びならそれらを1つずつ手に入れる総労働の合計
(BalanceStats.md の object_costs)、null なら置いた日数(仮置き)。同じ型が2回以上並ぶのは、
積んで段へ届かせる山——里心を止める設えのように、タグを名乗る型を並べて段へ届かせる山は、
いちばん安い積み方がそのまま並ぶ。
この並びは遊び方の推奨ではない。 安さは object_costs の総労働で測っていて、そこには前提の道具が
入らない(BalanceStats.md)ので、道具の要る型ほど安く見える。プレイヤーがどう積むかは自由で、
この量は積み方の真ん中ではなく下限——いちばん安い積み方そのものなので、実際に払う手間はこれ以上に
なる(Characters.md ホームシック節)。days と minutes は同じ量の別の書き方で、
換算は daily_budget.surplus(object_costs の days と同じ分母)。
work_piles_total は合計と、それを屋外(採取・伐採・運搬)と拠点(加工)へ割ったもの。割合は
ContentSkeleton.md 8.3節の仮置きで、base_days は拠点の加工が daily_budget.night_craft の枠で
何日ぶんかを示す(律速が屋外であることの確認用で、1周回の日数には足さない)。
局面ごとの1日
拠点を出て仕事をして帰る1日を、局面ごとに数える(ContentSkeleton.md 8.2節・8.3節)。
計算はsrc/analysis/dailyPhases.ts。
数えるのは「base: shortest_mean の土地に住み着いた1人の1日」。 局面の節のレコードはどれも
この base を鍵として持つ——島ごとにこの拠点1つだけを標本にしていて、全土地を順に拠点として
測っているのは base_one_way の base: any だけ。
全土地を拠点と見なした平均を採らないのは、それが誰の1日でもないから。 プレイヤーは拠点を選べる
ので、山頂に住んだ人の1日と浜辺に住んだ人の1日を混ぜた値は、遊びのどの場面にも現れない。1人に決める
なら2つの局面で同じ拠点でなければならない(同じ1周回の話なので)から、探索の局面が報いる土地
——他の土地への片道が平均で最も短い土地——を採る。定常の1日の実入りだけで選び直すとwork_per_dayは
わずかに上がるが、その拠点は片道が伸びるぶん探索の局面が長くなる。
全拠点の平均を出す列(base: any)は置かない。 この値を持ち込む先は1周回の見積もりで、そこに
要るのは1人ぶんの1日だから。
数え方は局面をまたいで1つだけ。
その日その土地で進む仕事(分)
= min(outdoor_window − 往復の移動 − survival_gathering, その土地でその仕事ができる時間)
daily_budget.outdoor_window= 屋外の枠。太陽が出ている12時間(明るさの側で移動のしきい値を 満たす時間)から、屋外が嵐で閉ざされる時間を引いたもの。嵐は往復の移動も止める (ContentSkeleton.md 8.1.4節)ので、風雨は下の頭打ちだけでなくこの枠にも入る。引く割合は拠点でも 行き先でもなく島全体の値(同 8.2節)。night_craftも同じ割合で縮み、引いたぶんがstorm_stop——outdoor_window・night_craft・storm_stop・sleepの和が24時間になる。daily_budget.survival_gathering= 1日を賄う生存の採取(BalanceStats.mdの最小労働からsleepを引いた分)。surplusはその最小労働を払って残る自由時間で、山の量を日数へ直す分母は こちら。拠点での加工が当たっているのはnight_craftの枠(1日の割り付けは ContentSkeleton.md 8.3節)。- その土地でその仕事ができる時間 = ClimateSystemStats.md「土地×季節ごとの活動時間」の
outdoor_searchの季節平均で、どちらの局面も同じ列を見る——採取と探索は明るさも風雨も同じ線で 閉じるので、頭打ちが局面で分かれることはない(ContentSkeleton.md 8.1.3節)。 遠さは移動の項として、暗さは頭打ちとして、風雨は屋外の枠と頭打ちの両方として、同じ1行に入る。handwork(手元の細かい作業)の列は見ない——この式が割っているのは屋外の枠で、手元の作業が 当たっているのはnight_craftのほう(ContentSkeleton.md 8.3節)だから。 - 1日は1つの土地で使う(往復1回)。余った時間は次の土地へ繰り越さない。
- 土地の間は最短経路をたどる。
探索の局面(島を開き切るまで)
未踏の土地を、拠点から近い順に探索率100%まで開いていく行程。遠い土地へ着くのに要る道は、 手前の土地を開く過程で必ず出るので、開く順は移動時間の小さい順に採れる (ExplorationSystem.md 3.2節)。
泊まりがけは、滞在中の生存の採取を現地で払わない(補給を持ち込む行程、 GameEndings.md 9.2節)。1日に進む探索がその土地で探索できる時間を超えられないことと、往復の移動も 屋外の枠から出ることの2つだけで縛る。
day_trip_window_per_day は、その行程の1日に探索へ使える枠(outdoor_window − 往復 −
survival_gathering)を日数で重み付けした平均で、day_trip_spare_per_day はそこから実際に進んだ
探索(day_trip_exploration_per_day)を引いた余り。探索の局面には山を1分も乗せていないので、
この余りがそのまま「1周回が下へ振れる材料」になる。
day_trip_ で始まる項目は日帰りだけで開き切る行程のもので、成立しない島は標本に入らない
——その島数の割合が exploration_day_trip_islands。成立しない島は、往復で枠が尽きる土地を
1つ以上持つ。mixed_days は土地ごとに安いほうを採ったときの日数、stay_over_sites はそのうち
泊まりを選んだ土地の数。
泊まりがけは遊びの側には入れない(ContentSkeleton.md 8.3.1節)。どちらも残っているのは、 入れたときに何日浮くか——つまり島がどれだけ広いか——を測るためで、行程としての泊まりを 見込んだ数ではない。
定常の局面(開き切った後の1日)
探索は終わっていて、山(ContentSkeleton.md 4節)だけを進める1日。行き先は山の土地の配分 が決め、その組の中ではその日の実入りが最も多い土地を選ぶ(同じなら近いほう)。 島に無い組の配分は、ある組へ按分する。
配分は仕事の量の配分であって、日数の配分ではない。 1日は1つの土地で使うので、ある組へ
費やす日数はその組の仕事量をその土地の1日の実入りで割ったものになり、work_minutes_per_day は
その日数で重み付けした平均になる。steady_phase_by_work_share の islands_percent は、その組の
土地があって定常の局面が成立した島の割合(その島だけを数えているので、他の列はその範囲の平均)。
泊まりがけは入れない。 探索と違って山は終わりのある仕事ではないので、滞在の長さを決めるものが
無い。そのため島にある組へ日帰りで届かない拠点は、定常の局面を持たない——その組の山は他の組へ
按分しない(無いのではなく届かないだけで、山はそこに残る)。その拠点を持つ島は
steady_phase・steady_phase_by_work_share の標本に入らず、残った島数の割合が
steady_phase_islands。
これは島の不具合ではない。 往復で枠が尽きるのは片道が daily_budget の day_trip_one_way を
超えたときで、条件の悪い土地に住めば届かない組が出る。どの土地がそうかは、この節からは出ない
(base: any は拠点ごとの値を1本にまとめた分布で、土地の型を持たない。同
base_farthest_round_trip)。数えていないのは
「その拠点から日帰りで回す1日」であって島そのものではないので、steady_phase の標本から落ちるのは
最も条件の良い拠点(base: shortest_mean)でさえ届かない島だけ。
この節から日数を出さない。 日数は cycle が持つ。
1周回(cycle)
work_piles_total.outdoor_minutes を定常の局面で消化し、そこへ探索の局面
(exploration_phase.day_trip_days)を足したもの。両方の局面が成立する島だけを数えるので、n が
その島数。
島ごとに日数を出してから平均する。 1周回の山の量はどの島でも同じなので、steady_phase の
work_per_day の平均で割ると日数は短く出る(平均の逆数と逆数の平均は違う)。