feat: produce on planets, unload on routes

This commit is contained in:
Ilia Denisov
2026-01-21 23:01:33 +02:00
parent 7e73601bce
commit 9825e05c0e
10 changed files with 319 additions and 60 deletions
+82 -1
View File
@@ -3,9 +3,12 @@ package controller
import (
"cmp"
"iter"
"maps"
"math"
"math/rand/v2"
"slices"
"github.com/google/uuid"
e "github.com/iliadenisov/galaxy/internal/error"
"github.com/iliadenisov/galaxy/internal/model/game"
"github.com/iliadenisov/galaxy/internal/util"
@@ -88,7 +91,7 @@ func (c *Cache) RemovePlanetRoute(rt game.RouteType, origin uint) {
}
}
// TODO: NOT IN THIS FUNC: remove routes if planet became uninhabited
// TODO: NOT IN THIS FUNC: remove routes if planet became uninhabited (bombing, quit game, etc)
func (c *Cache) EnrouteGroups() {
for pi := range c.g.Map.Planet {
if len(c.g.Map.Planet[pi].Route) == 0 {
@@ -188,3 +191,81 @@ func (c *Cache) listRouteEligibleGroupIds(pn uint) iter.Seq[int] {
}
}
}
// Невозможно лишь выгрузить колонистов на чужой планете.
func (c *Cache) TurnUnloadEnroutedGroups() {
for pi := range c.g.Map.Planet {
p := &c.g.Map.Planet[pi]
colGroups := c.listUnloadEligibleShipGroupIds(p.Number, game.RouteColonist)
if p.Owner == uuid.Nil {
c.selectColUnloadGroup(colGroups)
} else {
for sgi := range colGroups {
sg := c.ShipGroup(sgi)
if sg.OwnerID != p.Owner {
continue
}
c.unloadCargoUnsafe(sgi, sg.Load)
}
}
for _, rt := range []game.RouteType{game.RouteMaterial, game.RouteCapital} {
for sgi := range c.listUnloadEligibleShipGroupIds(p.Number, rt) {
c.unloadCargoUnsafe(sgi, c.ShipGroup(sgi).Load)
}
}
}
}
func (c *Cache) selectColUnloadGroup(seq iter.Seq[int]) {
groupByRace := make(map[int][]int)
loadByRace := make(map[int]float64)
for i := range seq {
sg := c.ShipGroup(i)
ri := c.RaceIndex(sg.OwnerID)
groupByRace[ri] = append(groupByRace[ri], i)
loadByRace[ri] += sg.Load
}
if len(loadByRace) < 2 {
for _, gr := range groupByRace {
for _, sgi := range gr {
c.unloadCargoUnsafe(sgi, c.ShipGroup(sgi).Load)
}
}
return
}
// select winner to unload
raceIdx := slices.Collect(maps.Keys(loadByRace))
slices.SortFunc(raceIdx, func(ri1, ri2 int) int { return cmp.Compare(loadByRace[ri2], loadByRace[ri1]) })
if loadByRace[raceIdx[0]] == loadByRace[raceIdx[1]] {
// no single winner with highest load
raceIdx = slices.DeleteFunc(raceIdx, func(v int) bool { return loadByRace[v] < loadByRace[raceIdx[0]] })
rand.Shuffle(len(raceIdx), func(i, j int) { raceIdx[i], raceIdx[j] = raceIdx[j], raceIdx[i] })
// now raceIdx[0] has a random race index
}
for _, sgi := range groupByRace[raceIdx[0]] {
c.unloadCargoUnsafe(sgi, c.ShipGroup(sgi).Load)
}
}
func (c *Cache) listUnloadEligibleShipGroupIds(pn uint, routeType game.RouteType) iter.Seq[int] {
return func(yield func(int) bool) {
for i := range c.g.Map.Planet {
for rt, dest := range c.g.Map.Planet[i].Route {
if dest != pn || rt != routeType {
continue
}
for i := range c.ShipGroupsIndex() {
sg := c.ShipGroup(i)
if sg.FleetID != nil || sg.State() != game.StateInOrbit || sg.CargoType == nil {
continue
}
if !yield(i) {
return
}
}
}
}
}
}