Files
2026-09-19 20:21:47 +02:00

92 lines
2.0 KiB
Go

package world
import (
"wh/config"
"wh/fixed"
"wh/rng"
)
// Ore identifies a raw material.
type Ore int
const (
Iron Ore = iota
Nickel
Ice
Platinum
NumOre
)
func (o Ore) String() string {
return [...]string{"iron", "nickel", "ice", "platinum"}[o]
}
type Asteroid struct {
ID int64
Orbit Orbit
Ore [NumOre]int64 // remaining kilograms of each ore
}
func (a *Asteroid) TotalOre() int64 {
var t int64
for _, v := range a.Ore {
t += v
}
return t
}
// Station is the dropoff point, on a circular orbit in the ecliptic plane.
type Station struct {
Orbit Orbit
}
// Stream labels keep independent generation phases from sharing randomness.
const (
labelBelt = iota + 1
labelStation
)
// Generate builds the asteroid field and station from the config seed.
func Generate(cfg config.Config) ([]Asteroid, Station) {
r := rng.Derive(cfg.Seed, labelBelt)
asts := make([]Asteroid, cfg.AsteroidCount)
for i := range asts {
a := r.FixedRange(cfg.BeltInner, cfg.BeltOuter)
asts[i] = Asteroid{
ID: int64(i + 1),
Orbit: Orbit{
A: a,
Period: PeriodFor(a, cfg.OrbitSpeed),
M0: r.FixedRange(0, fixed.TwoPi),
Node: r.FixedRange(0, fixed.TwoPi),
// Bias inclination low (squared uniform).
Inc: r.Fixed().Mul(r.Fixed()).Mul(cfg.MaxInclination),
},
}
// Each asteroid has a total mass and a random mix of ores.
total := int64(50_000) + int64(r.Intn(950_000))
var weights [NumOre]uint64
var wsum uint64
for o := range weights {
weights[o] = r.Intn(100) + 1
wsum += weights[o]
}
// Platinum is rare: only a fifth of asteroids carry much of it.
if r.Intn(5) != 0 {
wsum -= weights[Platinum]
weights[Platinum] = 0
}
for o := range weights {
asts[i].Ore[o] = total * int64(weights[o]) / int64(wsum)
}
}
sr := rng.Derive(cfg.Seed, labelStation)
a := (cfg.BeltInner + cfg.BeltOuter).DivInt(2)
st := Station{Orbit: Orbit{
A: a,
Period: PeriodFor(a, cfg.OrbitSpeed),
M0: sr.FixedRange(0, fixed.TwoPi),
}}
return asts, st
}