Files
galaxy-game/game/internal/controller/planet_test.go
T
Ilia Denisov b4abf90ec5
Tests · Go / test (push) Successful in 1m58s
Tests · Integration / integration (pull_request) Successful in 1m50s
Tests · Go / test (pull_request) Successful in 2m5s
fix(game): fight before departure and reorder the turn sequence
Per the documented turn order (game/rules.txt "Последовательность
действий"), no ship should dodge the pre-departure battle by slipping
into hyperspace. MakeTurn now runs merge -> battle -> load+launch routed
groups -> fly -> merge -> battle, so:

- ships ordered to depart (Launched) and ships being upgraded now take
  part in the pre-departure battle at their planet (CollectPlanetGroups /
  FilterBattleGroups); only survivors then enter hyperspace;
- routed transports are loaded and launched AFTER that battle, so they
  fight empty and cannot escape it.

A just-launched group has no stored hyperspace position, so moveShipGroup
starts its first leg from the origin planet; the previous code read the
nil launch coordinate and would panic.

Because upgrading groups can now lose ships in the battle, the pending
upgrade cost is recomputed from the group's current ship count instead of
the value stored when the order was validated.

Rules: reordered "Последовательность действий" and rewrote the combat
note that ordered/routed ships skip the battle.

Tests: launched-group move from origin, launched/upgrade groups taking
part in battle, upgrade cost tracking ship losses.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 00:25:46 +02:00

429 lines
17 KiB
Go

package controller_test
import (
"slices"
"testing"
"galaxy/util"
e "galaxy/error"
"galaxy/game/internal/controller"
"galaxy/game/internal/model/game"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
)
func TestPlanetRename(t *testing.T) {
c, g := newCache()
assert.Equal(t, "Planet_0", c.MustPlanet(R0_Planet_0_num).Name)
assert.NoError(t, g.PlanetRename(Race_0.Name, int(R0_Planet_0_num), "Home_World"))
assert.Equal(t, "Home_World", c.MustPlanet(R0_Planet_0_num).Name)
assert.ErrorContains(t,
g.PlanetRename(UnknownRace, int(R0_Planet_0_num), "Home_World"),
e.GenericErrorText(e.ErrInputUnknownRace))
assert.ErrorContains(t,
g.PlanetRename(Race_Extinct.Name, int(R0_Planet_0_num), "Home_World"),
e.GenericErrorText(e.ErrRaceExtinct))
assert.ErrorContains(t,
g.PlanetRename(Race_0.Name, -1, "Home_World"),
e.GenericErrorText(e.ErrInputPlanetNumber))
assert.ErrorContains(t,
g.PlanetRename(Race_0.Name, 500, "Home_World"),
e.GenericErrorText(e.ErrInputEntityNotExists))
assert.ErrorContains(t,
g.PlanetRename(Race_0.Name, int(R1_Planet_1_num), "Home_World"),
e.GenericErrorText(e.ErrInputEntityNotOwned))
}
func TestPlanetProduce(t *testing.T) {
c, g := newCache()
scienceName := "Drive_Shields"
assert.NoError(t, g.ScienceCreate(Race_0.Name, scienceName, 0.4, 0, 0.6, 0))
assert.Len(t, c.RaceScience(Race_0_idx), 1)
scID := c.RaceScience(Race_0_idx)[0].ID
assert.Equal(t, "-", c.PlanetProductionDisplayName(3))
pn := int(R0_Planet_0_num)
assert.NoError(t, g.PlanetProduce(Race_0.Name, pn, "MAT", ""))
assert.Equal(t, game.ProductionMaterial, c.MustPlanet(R0_Planet_0_num).Production.Type)
assert.Nil(t, c.MustPlanet(R0_Planet_0_num).Production.SubjectID)
assert.Nil(t, c.MustPlanet(R0_Planet_0_num).Production.Progress)
assert.Equal(t, "Material", c.PlanetProductionDisplayName(R0_Planet_0_num))
assert.NoError(t, g.PlanetProduce(Race_0.Name, pn, "CAP", ""))
assert.Equal(t, game.ProductionCapital, c.MustPlanet(R0_Planet_0_num).Production.Type)
assert.Nil(t, c.MustPlanet(R0_Planet_0_num).Production.SubjectID)
assert.Nil(t, c.MustPlanet(R0_Planet_0_num).Production.Progress)
assert.Equal(t, "Capital", c.PlanetProductionDisplayName(R0_Planet_0_num))
assert.NoError(t, g.PlanetProduce(Race_0.Name, pn, "Weapons", "500"))
assert.Equal(t, game.ResearchWeapons, c.MustPlanet(R0_Planet_0_num).Production.Type)
assert.Nil(t, c.MustPlanet(R0_Planet_0_num).Production.SubjectID)
assert.Nil(t, c.MustPlanet(R0_Planet_0_num).Production.Progress)
assert.Equal(t, "Weapons", c.PlanetProductionDisplayName(R0_Planet_0_num))
assert.NoError(t, g.PlanetProduce(Race_0.Name, pn, "cargo", ""))
assert.Equal(t, game.ResearchCargo, c.MustPlanet(R0_Planet_0_num).Production.Type)
assert.Nil(t, c.MustPlanet(R0_Planet_0_num).Production.SubjectID)
assert.Nil(t, c.MustPlanet(R0_Planet_0_num).Production.Progress)
assert.Equal(t, "Cargo", c.PlanetProductionDisplayName(R0_Planet_0_num))
assert.NoError(t, g.PlanetProduce(Race_0.Name, pn, "SHIELDS", scienceName))
assert.Equal(t, game.ResearchShields, c.MustPlanet(R0_Planet_0_num).Production.Type)
assert.Nil(t, c.MustPlanet(R0_Planet_0_num).Production.SubjectID)
assert.Nil(t, c.MustPlanet(R0_Planet_0_num).Production.Progress)
assert.Equal(t, "Shields", c.PlanetProductionDisplayName(R0_Planet_0_num))
assert.NoError(t, g.PlanetProduce(Race_0.Name, pn, "DrivE", ""))
assert.Equal(t, game.ResearchDrive, c.MustPlanet(R0_Planet_0_num).Production.Type)
assert.Nil(t, c.MustPlanet(R0_Planet_0_num).Production.SubjectID)
assert.Nil(t, c.MustPlanet(R0_Planet_0_num).Production.Progress)
assert.Equal(t, "Drive", c.PlanetProductionDisplayName(R0_Planet_0_num))
assert.NoError(t, g.PlanetProduce(Race_0.Name, pn, "Science", scienceName))
assert.Equal(t, game.ResearchScience, c.MustPlanet(R0_Planet_0_num).Production.Type)
assert.Nil(t, c.MustPlanet(R0_Planet_0_num).Production.Progress)
assert.NotNil(t, c.MustPlanet(R0_Planet_0_num).Production.SubjectID)
assert.Equal(t, scID, *c.MustPlanet(R0_Planet_0_num).Production.SubjectID)
assert.Equal(t, scienceName, c.PlanetProductionDisplayName(R0_Planet_0_num))
assert.NoError(t, g.PlanetProduce(Race_0.Name, pn, "SHIP", Race_0_Gunship))
assert.Equal(t, game.ProductionShip, c.MustPlanet(R0_Planet_0_num).Production.Type)
assert.NotNil(t, c.MustPlanet(R0_Planet_0_num).Production.Progress)
assert.NotNil(t, c.MustPlanet(R0_Planet_0_num).Production.SubjectID)
st := c.MustShipClass(Race_0_idx, Race_0_Gunship)
assert.Equal(t, st.ID, *c.MustPlanet(R0_Planet_0_num).Production.SubjectID)
assert.Equal(t, st.Name, c.PlanetProductionDisplayName(R0_Planet_0_num))
pn = int(R0_Planet_2_num)
assert.ErrorContains(t,
g.PlanetProduce(UnknownRace, pn, "DRIVE", ""),
e.GenericErrorText(e.ErrInputUnknownRace))
assert.ErrorContains(t,
g.PlanetProduce(Race_Extinct.Name, pn, "DRIVE", ""),
e.GenericErrorText(e.ErrRaceExtinct))
assert.ErrorContains(t,
g.PlanetProduce(Race_0.Name, pn, "Hyperdrive", ""),
e.GenericErrorText(e.ErrInputProductionInvalid))
assert.ErrorContains(t,
g.PlanetProduce(Race_0.Name, -1, "DRIVE", ""),
e.GenericErrorText(e.ErrInputPlanetNumber))
assert.ErrorContains(t,
g.PlanetProduce(Race_0.Name, 500, "DRIVE", ""),
e.GenericErrorText(e.ErrInputEntityNotExists))
assert.ErrorContains(t,
g.PlanetProduce(Race_0.Name, int(R1_Planet_1_num), "DRIVE", ""),
e.GenericErrorText(e.ErrInputEntityNotOwned))
assert.ErrorContains(t,
g.PlanetProduce(Race_0.Name, pn, "Science", ""),
e.GenericErrorText(e.ErrInputEntityTypeNameInvalid))
assert.ErrorContains(t,
g.PlanetProduce(Race_0.Name, pn, "SHIP", ""),
e.GenericErrorText(e.ErrInputEntityTypeNameInvalid))
assert.ErrorContains(t,
g.PlanetProduce(Race_0.Name, pn, "Science", "Winning"),
e.GenericErrorText(e.ErrInputEntityNotExists))
assert.ErrorContains(t,
g.PlanetProduce(Race_0.Name, pn, "SHIP", "Drone"),
e.GenericErrorText(e.ErrInputEntityNotExists))
}
func TestPlanetProductionCapacity(t *testing.T) {
c, _ := newCache()
assert.NoError(t, c.CreateShips(Race_0_idx, ShipType_Cruiser, R0_Planet_0_num, 1))
assert.Equal(t, 100., c.PlanetProductionCapacity(R0_Planet_0_num))
c.UpgradeShipGroup(0, game.TechDrive, 1.6)
assert.Equal(t, 53.125, c.PlanetProductionCapacity(R0_Planet_0_num))
}
func TestProduceShips(t *testing.T) {
c, g := newCache()
pn := int(R0_Planet_0_num)
assert.NoError(t, g.PlanetProduce(Race_0.Name, pn, "SHIP", Race_0_Gunship))
assert.Equal(t, game.ProductionShip, c.MustPlanet(R0_Planet_0_num).Production.Type)
assert.NotNil(t, c.MustPlanet(R0_Planet_0_num).Production.Progress)
assert.NotNil(t, c.MustPlanet(R0_Planet_0_num).Production.SubjectID)
st := c.MustShipClass(Race_0_idx, Race_0_Gunship)
assert.Equal(t, st.ID, *c.MustPlanet(R0_Planet_0_num).Production.SubjectID)
c.MustPlanet(R0_Planet_0_num).Size = 1000.
c.MustPlanet(R0_Planet_0_num).Population = 1000.
c.MustPlanet(R0_Planet_0_num).Industry = 1000.
c.MustPlanet(R0_Planet_0_num).Resources = 10.
shipMass := st.EmptyMass()
c.TurnPlanetProductions()
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 0)
assert.NotNil(t, c.MustPlanet(R0_Planet_0_num).Production.Progress)
progress := *c.MustPlanet(R0_Planet_0_num).Production.Progress
assert.InDelta(t, 0.45, progress.F(), 0.001)
assert.NoError(t, c.ShipClassCreate(Race_0_idx, "Drone", 1, 0, 0, 0, 0))
assert.NoError(t, c.CreateShips(Race_0_idx, "Drone", uint(pn), 7))
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 1)
assert.Equal(t, uint(7), c.ShipGroup(0).Number)
assert.NoError(t, g.PlanetProduce(Race_0.Name, pn, "SHIP", "Drone"))
assert.InDelta(t, shipMass*progress.F(), c.MustPlanet(R0_Planet_0_num).Material.F(), 0.00001) // 99.(0099) material build
c.MustPlanet(R0_Planet_0_num).Material = 0
c.MustPlanet(R0_Planet_0_num).Colonists = 0
c.TurnPlanetProductions()
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 1)
assert.Equal(t, uint(106), c.ShipGroup(0).Number)
progress = *c.MustPlanet(R0_Planet_0_num).Production.Progress
assert.InDelta(t, 0.0099, progress.F(), 0.00001) // 1.(0099) drones with no CAP on planet
//
// groups is upgrade state
//
assert.NoError(t, g.PlanetProduce(Race_0.Name, int(R0_Planet_0_num), "MAT", ""))
assert.NoError(t, g.PlanetProduce(Race_0.Name, int(R0_Planet_2_num), "CAP", ""))
assert.NoError(t, c.CreateShips(Race_0_idx, "Drone", R0_Planet_2_num, 5))
c.MustPlanet(R0_Planet_2_num).Resources = 5
c.MustPlanet(R0_Planet_2_num).Population = 100
c.MustPlanet(R0_Planet_2_num).Industry = 100
c.RaceTechLevel(Race_0_idx, game.TechDrive, 1.5)
assert.NoError(t, g.ShipGroupUpgrade(Race_0.Name, c.ShipGroup(1).ID, "Drive", 0))
assert.NoError(t, g.ShipGroupUpgrade(Race_0.Name, c.ShipGroup(0).ID, "Drive", 0))
assert.Equal(t, game.StateUpgrade, c.ShipGroup(0).State())
assert.Equal(t, game.StateUpgrade, c.ShipGroup(1).State())
c.MustPlanet(R0_Planet_2_num).Free() // wipe planet as battle result
c.TurnPlanetProductions()
assert.Equal(t, game.StateInOrbit, c.ShipGroup(1).State())
assert.Equal(t, 1.1, c.ShipGroup(1).TechLevel(game.TechDrive).F())
assert.Equal(t, game.StateInOrbit, c.ShipGroup(0).State())
assert.Equal(t, 1.5, c.ShipGroup(0).TechLevel(game.TechDrive).F())
// Upgrade cost is now recomputed from the group's current ship count
// (calc raw float) rather than read from the Fixed12-rounded stored value,
// which shifts Material at the 12th decimal — far below the 3-decimal
// report precision, so an InDelta check is the robust expectation here.
assert.InDelta(t, 4346.6766, c.MustPlanet(R0_Planet_0_num).Material.F(), 0.001)
}
func TestProduceShip(t *testing.T) {
Drone := game.ShipType{
Name: "Drone",
Drive: 1,
Armament: 0,
Weapons: 0,
Shields: 0,
Cargo: 0,
}
BattleShip := game.ShipType{
Name: "BattleShip",
Drive: 25,
Armament: 1,
Weapons: 30,
Shields: 35,
Cargo: 0,
}
TestShipCargo1 := game.ShipType{
Name: "Cargo1",
Drive: 30.18,
Armament: 0,
Weapons: 0.,
Shields: 0.,
Cargo: 19.,
}
TestShipDROCOLZ := game.ShipType{
Name: "DROCOLZ",
Drive: 11.32,
Armament: 0,
Weapons: 0,
Shields: 0,
Cargo: 1,
}
TestShipElephant := game.ShipType{
Name: "ElEphant",
Drive: 80,
Armament: 30,
Weapons: 50,
Shields: 100,
Cargo: 0,
}
id := uuid.New()
var r uint
hw := controller.NewPlanet(0, "Planet_0", &id, 1, 1, 1000, 1000, 1000, 10, game.ProductionShip.AsType(uuid.Nil))
//
// documented data
//
r = controller.ProduceShip(&hw, hw.ProductionCapacity(), Drone.EmptyMass())
assert.Equal(t, uint(99), r)
assert.InDelta(t, 0.0099, (*hw.Production.Progress).F(), 0.000001)
assert.Equal(t, 0.009900990099, (*hw.Production.Progress).F()) // 0.0099 % = 99.0099 mass production per turn
(&hw).Production = game.ProductionShip.AsType(uuid.Nil)
(&hw).Material = 100. // no material deficit
r = controller.ProduceShip(&hw, hw.ProductionCapacity(), Drone.EmptyMass())
assert.Equal(t, uint(100), r)
assert.Equal(t, 0., (*hw.Production.Progress).F())
assert.Equal(t, 0., hw.Material.F())
(&hw).Production = game.ProductionShip.AsType(uuid.Nil)
(&hw).Material = 0.
r = controller.ProduceShip(&hw, hw.ProductionCapacity(), BattleShip.EmptyMass())
assert.Equal(t, uint(1), r)
assert.InDelta(t, 0.1, (*hw.Production.Progress).F(), 0.001)
(&hw).Production = game.ProductionShip.AsType(uuid.Nil)
(&hw).Material = 900. // no material deficit
r = controller.ProduceShip(&hw, hw.ProductionCapacity(), BattleShip.EmptyMass())
assert.Equal(t, uint(1), r)
assert.Equal(t, util.Fixed12(1./9.), (*hw.Production.Progress).F())
//
// real report data
//
dw1 := controller.NewPlanet(0, "DW2", &id, 1, 1, 500, 500, 500, 10, game.ProductionShip.AsType(uuid.Nil))
dw2 := controller.NewPlanet(0, "DW1", &id, 1, 1, 500, 500, 500, 10, game.ProductionShip.AsType(uuid.Nil))
(&dw1).Material = 0.0
r = controller.ProduceShip(&dw1, dw1.ProductionCapacity(), TestShipDROCOLZ.EmptyMass())
assert.Equal(t, uint(4), r)
assert.Equal(t, 2.272, (*dw1.Production.ProdUsed).F())
(&dw2).Material = 0.0
r = controller.ProduceShip(&dw2, dw2.ProductionCapacity(), TestShipCargo1.EmptyMass())
assert.Equal(t, uint(1), r)
assert.Equal(t, 3.282, (*dw2.Production.ProdUsed).F())
// production stopped and extra MAT released
(&dw2).ReleaseMaterial(TestShipCargo1.EmptyMass())
assert.Equal(t, 0.32495049505, (&dw2).Material.F()) // from report: 0.32
// building new ship with extra MAT
r = controller.ProduceShip(&dw2, dw2.ProductionCapacity(), TestShipDROCOLZ.EmptyMass())
assert.Equal(t, uint(4), r)
assert.Equal(t, 2.304495049505, (*dw2.Production.ProdUsed).F()) // from report: 2.3
//
// insufficient production capacity to produce single ship at one turn
//
assert.Greater(t, TestShipElephant.EmptyMass(), 100.)
// one turn
(&hw).Production = game.ProductionShip.AsType(uuid.Nil)
(&hw).Material = 0.
r = controller.ProduceShip(&hw, hw.ProductionCapacity(), TestShipElephant.EmptyMass())
assert.Equal(t, uint(0), r)
assert.Equal(t, 0., (&hw).Material.F())
assert.InDelta(t, 0.1, (*hw.Production.Progress).F(), 0.01)
(&hw).ReleaseMaterial(TestShipElephant.EmptyMass())
assert.Equal(t, 99.009900990099, (&hw).Material.F())
// two turns
(&hw).Production = game.ProductionShip.AsType(uuid.Nil)
(&hw).Material = 0.
r = controller.ProduceShip(&hw, hw.ProductionCapacity(), TestShipElephant.EmptyMass())
assert.Equal(t, uint(0), r)
assert.Equal(t, 0., (&hw).Material.F())
assert.InDelta(t, 0.1, (*hw.Production.Progress).F(), 0.01)
r = controller.ProduceShip(&hw, hw.ProductionCapacity(), TestShipElephant.EmptyMass())
assert.Equal(t, uint(0), r)
assert.Equal(t, 0., (&hw).Material.F())
assert.InDelta(t, 0.2, (*hw.Production.Progress).F(), 0.01)
(&hw).ReleaseMaterial(TestShipElephant.EmptyMass())
assert.Equal(t, 198.019801980198, (&hw).Material.F())
}
func TestListProducingPlanets(t *testing.T) {
c, g := newCache()
c.MustPlanet(0).Production = game.ProductionNone.AsType(uuid.Nil)
c.MustPlanet(1).Production = game.ProductionNone.AsType(uuid.Nil)
c.MustPlanet(2).Production = game.ProductionNone.AsType(uuid.Nil)
planets := slices.Collect(c.ListProducingPlanets())
assert.Len(t, planets, 0)
assert.NoError(t, g.PlanetProduce(Race_0.Name, int(R0_Planet_0_num), "CAP", ""))
planets = slices.Collect(c.ListProducingPlanets())
assert.Len(t, planets, 1)
assert.Equal(t, R0_Planet_0_num, c.MustPlanet(planets[0]).Number)
assert.NoError(t, g.PlanetProduce(Race_0.Name, int(R0_Planet_2_num), "SHIP", Race_0_Gunship))
planets = slices.Collect(c.ListProducingPlanets())
assert.Len(t, planets, 2)
assert.Equal(t, R0_Planet_2_num, c.MustPlanet(planets[0]).Number)
assert.Equal(t, R0_Planet_0_num, c.MustPlanet(planets[1]).Number)
}
func TestTurnPlanetProductions(t *testing.T) {
c, g := newCache()
assert.NoError(t, c.ShipClassCreate(Race_0_idx, "Drone", 1, 0, 0, 0, 0))
assert.NoError(t, g.ScienceCreate(Race_0.Name, "Equality", 0.25, 0.25, 0.25, 0.25))
c.MustPlanet(R0_Planet_0_num).Resources = 10.
c.MustPlanet(R0_Planet_0_num).Size = 1000.
c.MustPlanet(R0_Planet_0_num).Population = 1000.
c.MustPlanet(R0_Planet_0_num).Industry = 1000.
pn := int(R0_Planet_0_num)
assert.NoError(t, g.PlanetProduce(Race_0.Name, pn, "CAP", ""))
assert.Equal(t, 0.0, c.MustPlanet(R0_Planet_0_num).Capital.F())
assert.Equal(t, 0.0, c.MustPlanet(R0_Planet_0_num).Colonists.F())
c.TurnPlanetProductions()
assert.InDelta(t, 196., c.MustPlanet(R0_Planet_0_num).Capital.F(), 0.1)
assert.Equal(t, 10.0, c.MustPlanet(R0_Planet_0_num).Colonists.F())
assert.NoError(t, g.PlanetProduce(Race_0.Name, pn, "MAT", ""))
assert.Equal(t, 0.0, c.MustPlanet(R0_Planet_0_num).Material.F())
c.TurnPlanetProductions()
assert.Equal(t, 10000., c.MustPlanet(R0_Planet_0_num).Material.F())
assert.InDelta(t, 20.0, c.MustPlanet(R0_Planet_0_num).Colonists.F(), 0.000001)
assert.NoError(t, g.PlanetProduce(Race_0.Name, pn, "DRIVE", ""))
assert.Equal(t, 1.1, c.Race(Race_0_idx).TechLevel(game.TechDrive))
c.TurnPlanetProductions()
assert.Equal(t, 1.3, c.Race(Race_0_idx).TechLevel(game.TechDrive))
assert.NoError(t, g.PlanetProduce(Race_0.Name, pn, "WEAPONS", ""))
assert.Equal(t, 1.2, c.Race(Race_0_idx).TechLevel(game.TechWeapons))
c.TurnPlanetProductions()
assert.Equal(t, 1.4, c.Race(Race_0_idx).TechLevel(game.TechWeapons))
assert.NoError(t, g.PlanetProduce(Race_0.Name, pn, "SHIELDS", ""))
assert.Equal(t, 1.3, c.Race(Race_0_idx).TechLevel(game.TechShields))
c.TurnPlanetProductions()
assert.Equal(t, 1.5, c.Race(Race_0_idx).TechLevel(game.TechShields))
assert.NoError(t, g.PlanetProduce(Race_0.Name, pn, "CARGO", ""))
assert.Equal(t, 1.4, c.Race(Race_0_idx).TechLevel(game.TechCargo))
c.TurnPlanetProductions()
assert.Equal(t, 1.6, c.Race(Race_0_idx).TechLevel(game.TechCargo))
assert.NoError(t, g.PlanetProduce(Race_0.Name, pn, "SCIENCE", "Equality"))
c.TurnPlanetProductions()
assert.Equal(t, 1.35, c.Race(Race_0_idx).TechLevel(game.TechDrive))
assert.Equal(t, 1.45, c.Race(Race_0_idx).TechLevel(game.TechWeapons))
assert.Equal(t, 1.55, c.Race(Race_0_idx).TechLevel(game.TechShields))
assert.Equal(t, 1.65, c.Race(Race_0_idx).TechLevel(game.TechCargo))
assert.NoError(t, g.PlanetProduce(Race_0.Name, pn, "SHIP", "Drone"))
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 0)
c.TurnPlanetProductions()
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 1)
assert.Equal(t, uint(100), c.ShipGroup(0).Number)
}