feat: enroute groups

This commit is contained in:
Ilia Denisov
2026-01-16 22:20:27 +02:00
parent 16aba8435d
commit 741a5f726b
8 changed files with 299 additions and 9 deletions
+106
View File
@@ -1,6 +1,11 @@
package controller
import (
"cmp"
"iter"
"math"
"slices"
e "github.com/iliadenisov/galaxy/internal/error"
"github.com/iliadenisov/galaxy/internal/model/game"
"github.com/iliadenisov/galaxy/internal/util"
@@ -82,3 +87,104 @@ func (c *Cache) RemovePlanetRoute(rt game.RouteType, origin uint) {
delete(c.g.Map.Planet[pi].Route, rt)
}
}
// TODO: NOT IN THIS FUNC: remove routes if planet became uninhabited
func (c *Cache) EnrouteGroups() {
for pi := range c.g.Map.Planet {
if len(c.g.Map.Planet[pi].Route) == 0 {
continue
}
groups := slices.Collect(c.listRouteEligibleGroupIds(c.g.Map.Planet[pi].Number))
if len(groups) == 0 {
continue
}
sortGroups := func(g []int) {
// sort groups by largest CargoCapacity
slices.SortFunc(g, func(l, r int) int {
return cmp.Or(cmp.Compare(c.ShipGroup(r).CargoCapacity(c.ShipGroupShipClass(r)),
c.ShipGroup(l).CargoCapacity(c.ShipGroupShipClass(l))),
cmp.Compare(l, r))
})
}
reorderGroups := func(g []int) []int {
g = slices.DeleteFunc(g, func(i int) bool { return c.ShipGroup(i).State() != game.StateInOrbit })
sortGroups(g)
return g
}
sortGroups(groups)
p := c.MustPlanet(c.g.Map.Planet[pi].Number)
// COL -> CAP -> MAT -> EMPTY
for _, rt := range []game.RouteType{game.RouteColonist, game.RouteCapital, game.RouteMaterial, game.RouteEmpty} {
dest, ok := c.g.Map.Planet[pi].Route[rt]
if !ok {
continue
}
var res *float64
var ct game.CargoType
switch rt {
case game.RouteColonist:
res = &p.Colonists
ct = game.CargoColonist
case game.RouteCapital:
res = &p.Capital
ct = game.CargoCapital
case game.RouteMaterial:
res = &p.Material
ct = game.CargoMaterial
default:
for _, sgi := range groups {
c.LaunchShips(c.ShipGroup(sgi), dest)
}
groups = reorderGroups(groups)
continue
}
for res != nil && *res > 0 && len(groups) > 0 {
sgi := groups[0]
sg := c.ShipGroup(sgi)
st := c.ShipGroupShipClass(sgi)
ships := sg.Number
sgCapacity := sg.CargoCapacity(st)
toLoad := *res
if toLoad > sgCapacity {
toLoad = sgCapacity
} else if maxShips := uint(math.Ceil(toLoad / (sgCapacity / float64(ships)))); maxShips < ships {
newGroupIdx := c.breakGroupUnsafe(c.RaceIndex(sg.OwnerID), sgi, maxShips)
sg = c.ShipGroup(newGroupIdx)
}
// decrease planet resource
*res = *res - toLoad
// load group
sg.Load += toLoad
sg.CargoType = &ct
c.LaunchShips(sg, dest)
groups = reorderGroups(groups)
}
}
}
}
func (c *Cache) listRouteEligibleGroupIds(pn uint) iter.Seq[int] {
return func(yield func(int) bool) {
p := c.MustPlanet(pn)
for i := range c.ShipGroupsIndex() {
sg := c.ShipGroup(i)
st := c.ShipGroupShipClass(i)
if sg.OwnerID != p.Owner || // Planet must be owned by ships owner
sg.FleetID != nil || // Ships must not be part of a Fleet
sg.State() != game.StateInOrbit || // Ships must be only In_Orbit state
st.CargoBlockMass() == 0 || // Ship Class must have Cargo bays
sg.Load != 0 || // Ships must not be loaded for enrouting
sg.Destination != p.Number {
continue
}
if !yield(i) {
return
}
}
}
}