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 }