feat(db): body_radius_km scatter + gas giant/moon scale classes

Deterministic ±scatter on body radii seeded by body_id hash — no two
bodies share the same radius. Gas giants 40k-60k km, moons 200-2600 km,
rocky planets ±15% from class base. Oort/asteroid skip radius (NULL).
Sol system gets real planetary radii. body_radius_km exported to
star_map_data.json for client orbital diagram sizing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-03 20:11:31 +02:00
co-authored by Claude Opus 4.6
parent e8b4dc74b5
commit 29f9945291
5 changed files with 8902 additions and 5636 deletions
+35 -10
View File
@@ -1107,29 +1107,54 @@ def populate_body_radius_km(conn: sqlite3.Connection, dry_run: bool) -> int:
"super_earth": 8000.0,
"earth_like": 6371.0,
"earth": 6371.0,
"sub_earth": 4500.0,
"sub_earth": 3500.0,
"ocean_world": 6500.0,
"arid": 5800.0,
"frozen": 4500.0,
"frozen": 3500.0,
"ice_world": 3000.0,
"barren": 4500.0,
"barren": 3500.0,
"volcanic": 5500.0,
"temperate": 6371.0,
"moon": 1737.0,
}
DEFAULT_RADIUS = 6371.0
SKIP_RADIUS_TYPES = {"oort_cloud", "asteroid_belt"}
GAS_GIANT_RADIUS = {
"gas_giant": 50000.0,
"ice_giant": 25000.0,
}
GAS_GIANT_DEFAULT = 45000.0
GAS_GIANT_SCATTER = 0.20 # ±20%
rows = conn.execute(
"SELECT body_id, planet_class FROM bodies WHERE body_radius_km IS NULL"
"SELECT body_id, planet_class, body_type, mass_class FROM bodies WHERE body_radius_km IS NULL"
).fetchall()
import hashlib
SCATTER_FRACTION = 0.15 # ±15% for rocky bodies
updates = []
for body_id, planet_class in rows:
if planet_class and planet_class.lower() == "gas_giant":
continue # gas giants have no settlements; leave NULL
radius = PLANET_CLASS_RADIUS.get(
(planet_class or "").lower(), DEFAULT_RADIUS
)
for body_id, planet_class, body_type, mass_class in rows:
if body_type in SKIP_RADIUS_TYPES:
continue
h = int(hashlib.sha256(body_id.encode()).hexdigest()[:8], 16)
scatter_val = (h / 0xFFFFFFFF) * 2.0 - 1.0 # [-1.0, 1.0]
if body_type == "gas_giant":
mc = (mass_class or "").lower()
base_radius = GAS_GIANT_RADIUS.get(mc, GAS_GIANT_DEFAULT)
radius = round(base_radius * (1.0 + scatter_val * GAS_GIANT_SCATTER), 1)
elif body_type == "moon":
base_radius = 1400.0
scatter_frac = 0.86 # ±86% → ~1962604 km
radius = round(base_radius * (1.0 + scatter_val * scatter_frac), 1)
else:
base_radius = PLANET_CLASS_RADIUS.get(
(planet_class or "").lower(), DEFAULT_RADIUS
)
radius = round(base_radius * (1.0 + scatter_val * SCATTER_FRACTION), 1)
updates.append((radius, body_id))
if not dry_run and updates: