feat: cargo unload challenge

This commit is contained in:
Ilia Denisov
2026-02-21 09:57:02 +02:00
parent 233c9ebc2a
commit 9e36d7151e
12 changed files with 137 additions and 166 deletions
+75 -16
View File
@@ -6,6 +6,7 @@ import (
"github.com/google/uuid"
e "github.com/iliadenisov/galaxy/internal/error"
"github.com/iliadenisov/galaxy/internal/model/game"
"github.com/iliadenisov/galaxy/internal/model/order"
)
@@ -108,11 +109,12 @@ func (c *Controller) applyCommand(actor string, cmd order.DecodableCommand) (err
return
}
// TODO: test commands ordering
func (c *Controller) applyOrders(t uint) error {
raceOrder := make(map[int][]order.DecodableCommand)
unloadGroups := make([]uuid.UUID, 0)
unloadQuantities := make([]float64, 0)
commandRace := make(map[string]string)
challenge := make(map[string]*order.CommandShipGroupUnload)
cmdApplied := make(map[string]bool)
for ri := range c.Cache.listRaceActingIdx() {
o, ok, err := c.Repo.LoadOrder(t, c.Cache.g.Race[ri].ID)
if err != nil {
@@ -123,30 +125,33 @@ func (c *Controller) applyOrders(t uint) error {
}
raceOrder[ri] = o.Commands
for i := range o.Commands {
if o.Commands[i].CommandType() == order.CommandTypeShipGroupUnload {
unloadCommand := o.Commands[i].(order.CommandShipGroupUnload)
unloadGroups = append(unloadGroups, uuid.MustParse(unloadCommand.ID))
unloadQuantities = append(unloadQuantities, unloadCommand.Quantity)
commandRace[o.Commands[i].CommandID()] = c.Cache.g.Race[ri].Name
if v, ok := order.AsCommand[*order.CommandShipGroupUnload](o.Commands[i]); ok {
if _, ok := challenge[v.ID]; ok {
panic(fmt.Sprintf("unload command %s already cached", v.ID))
}
if ok, err := c.shouldChallenge(v); err != nil {
return err
} else if ok {
challenge[v.ID] = v
}
}
}
}
if err := c.Cache.shipGroupUnloadColonistChallenge(unloadGroups, unloadQuantities); err != nil {
return err
for _, cmdID := range c.challengeUnload(challenge) {
if err := c.applyCommand(commandRace[cmdID], challenge[cmdID]); err == nil {
cmdApplied[cmdID] = true
}
}
for ri := range raceOrder {
for _, cmd := range raceOrder[ri] {
if cmd.CommandType() == order.CommandTypeShipGroupUnload {
// group unload commands execution should be failed at this point,
// otherwise produce no-errors
if v, ok := order.AsCommand[*order.CommandShipGroupUnload](cmd); ok {
v.Result(0)
}
if v, ok := cmdApplied[cmd.CommandID()]; ok && v {
continue
}
// any command might fail due to challenged planets colonization
_ = c.applyCommand(c.Cache.g.Race[ri].Name, cmd)
_ = c.applyCommand(commandRace[cmd.CommandID()], cmd)
}
}
@@ -158,3 +163,57 @@ func (c *Controller) applyOrders(t uint) error {
return nil
}
func (c *Controller) shouldChallenge(cmd *order.CommandShipGroupUnload) (resut bool, err error) {
sgi, ok := c.Cache.shipGroupIndexByID(uuid.MustParse(cmd.ID))
if !ok {
err = e.NewGameStateError("challenge group unload: group not found: %v", cmd.ID)
return
}
sg := c.Cache.ShipGroup(sgi)
pn, ok := sg.AtPlanet()
if !ok || sg.CargoType == nil {
return false, nil
}
p := c.Cache.MustPlanet(pn)
if p.Owned() || *sg.CargoType != game.CargoColonist {
return false, nil
}
return true, nil
}
func (c *Controller) challengeUnload(challenge map[string]*order.CommandShipGroupUnload) []string {
if len(challenge) == 0 {
return nil
}
planetRaceQuantity := make(map[uint]map[int]float64, 0)
raceCommand := make(map[uint]map[int][]string)
for cmdID, cmd := range challenge {
sgi, ok := c.Cache.shipGroupIndexByID(uuid.MustParse(cmd.ID))
if !ok {
panic(fmt.Sprintf("challenge group unload: group not found: %v", cmd.ID))
}
sg := c.Cache.ShipGroup(sgi)
ri := c.Cache.ShipGroupOwnerRaceIndex(sgi)
pn, ok := sg.AtPlanet()
if _, ok := raceCommand[pn]; !ok {
raceCommand[pn] = make(map[int][]string)
}
raceCommand[pn][ri] = append(raceCommand[pn][ri], cmdID)
if _, ok := planetRaceQuantity[pn]; !ok {
planetRaceQuantity[pn] = make(map[int]float64)
}
planetRaceQuantity[pn][ri] = planetRaceQuantity[pn][ri] + UnloadCargoRequest(float64(sg.Load), cmd.Quantity)
}
result := make([]string, 0)
for pn := range planetRaceQuantity {
if len(planetRaceQuantity[pn]) < 2 {
continue
}
winner := MaxOrRandomLoadId(planetRaceQuantity[pn], func(ri int) float64 { return float64(c.Cache.g.Race[ri].Votes) })
result = append(result, raceCommand[pn][winner]...)
}
return result
}