151 lines
3.1 KiB
Go
151 lines
3.1 KiB
Go
// Package sim is the deterministic core: given a State, the day's inputs and
|
|
// a Config it advances the world by one day. It performs no I/O.
|
|
package sim
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"wh/config"
|
|
"wh/fixed"
|
|
"wh/market"
|
|
"wh/vm"
|
|
"wh/world"
|
|
)
|
|
|
|
// Hull describes the physical properties of a ship design.
|
|
type Hull struct {
|
|
DryMass int64 // kg
|
|
FuelCap int64 // kg
|
|
CargoCap int64 // kg
|
|
Thrust int64 // newtons at full throttle
|
|
ExhaustVel int64 // m/s
|
|
MineRate int64 // kg mined per tick
|
|
}
|
|
|
|
// CommandShip is the only hull for now.
|
|
var CommandShip = Hull{
|
|
DryMass: 8000,
|
|
FuelCap: 4000,
|
|
CargoCap: 6000,
|
|
Thrust: 6000,
|
|
ExhaustVel: 30000,
|
|
MineRate: 10,
|
|
}
|
|
|
|
// Docking / mining limits.
|
|
const (
|
|
MineRangeKm = 5 // max distance to an asteroid for mining
|
|
DockRangeKm = 20 // max distance to the station for selling
|
|
MaxRelSpeedM = 100 // max relative speed (m/s) for mining or docking
|
|
StarRadiusKm = 200_000
|
|
)
|
|
|
|
type Ship struct {
|
|
ID int64
|
|
Owner int64
|
|
Hull Hull
|
|
Pos fixed.Vec
|
|
Vel fixed.Vec
|
|
Fuel fixed.F
|
|
Cargo [world.NumOre]int64
|
|
CPU *vm.CPU
|
|
Alive bool
|
|
Earned int64 // credits earned so far
|
|
|
|
// Peripheral state.
|
|
Throttle int32
|
|
Azimuth int32
|
|
Pitch int32
|
|
Target int64
|
|
Mining bool
|
|
UplinkNew bool
|
|
UplinkLen int32
|
|
MathX int32
|
|
MathY int32
|
|
MathZ int32
|
|
}
|
|
|
|
func (s *Ship) CargoTotal() int64 {
|
|
var t int64
|
|
for _, v := range s.Cargo {
|
|
t += v
|
|
}
|
|
return t
|
|
}
|
|
|
|
func (s *Ship) Mass() fixed.F {
|
|
return fixed.FromInt(s.Hull.DryMass+s.CargoTotal()) + s.Fuel
|
|
}
|
|
|
|
// State is everything that persists between daily runs.
|
|
type State struct {
|
|
Day int64
|
|
Asteroids []world.Asteroid // sorted by ID
|
|
Station world.Station
|
|
Ships []*Ship // sorted by ID
|
|
Credits map[int64]int64
|
|
Market market.Market
|
|
}
|
|
|
|
// NewState builds the initial world from the config seed.
|
|
func NewState(cfg config.Config) *State {
|
|
asts, st := world.Generate(cfg)
|
|
return &State{
|
|
Asteroids: asts,
|
|
Station: st,
|
|
Credits: map[int64]int64{},
|
|
Market: market.New(),
|
|
}
|
|
}
|
|
|
|
func (s *State) asteroid(id int64) *world.Asteroid {
|
|
// Asteroids are numbered 1..N in slice order.
|
|
if id >= 1 && id <= int64(len(s.Asteroids)) {
|
|
return &s.Asteroids[id-1]
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Launch describes a ship entering the belt at the start of a day.
|
|
type Launch struct {
|
|
ShipID int64
|
|
Owner int64
|
|
Program []byte
|
|
}
|
|
|
|
// Uplink is a message delivered to a ship's comm buffer at the start of a day.
|
|
type Uplink struct {
|
|
ShipID int64
|
|
Data []byte
|
|
}
|
|
|
|
// DayInput is everything external the simulation consumes for one day.
|
|
type DayInput struct {
|
|
Launches []Launch // processed in slice order (must be deterministic)
|
|
Uplinks []Uplink
|
|
}
|
|
|
|
// Downlink is the content of a ship's transmit buffer at the end of the day.
|
|
type Downlink struct {
|
|
ShipID int64
|
|
Data []byte
|
|
}
|
|
|
|
type Event struct {
|
|
Tick int
|
|
ShipID int64
|
|
Kind string
|
|
Detail string
|
|
}
|
|
|
|
type DayResult struct {
|
|
Day int64
|
|
Downlinks []Downlink
|
|
Events []Event
|
|
Hash [32]byte
|
|
}
|
|
|
|
func (e Event) String() string {
|
|
return fmt.Sprintf("t%04d ship %d %s %s", e.Tick, e.ShipID, e.Kind, e.Detail)
|
|
}
|