refactor: planet owner

This commit is contained in:
Ilia Denisov
2026-02-04 19:26:17 +02:00
parent 6a603ea9ad
commit c1d397c993
17 changed files with 170 additions and 183 deletions
+33 -31
View File
@@ -5,6 +5,35 @@ import (
"github.com/iliadenisov/galaxy/internal/model/game" "github.com/iliadenisov/galaxy/internal/model/game"
) )
func (c *Cache) ProduceBombings() []*game.Bombing {
report := make([]*game.Bombing, 0)
for pn, enemies := range c.collectBombingGroups() {
p := c.MustPlanet(pn)
if !p.Owned() {
continue
}
for ri, groups := range enemies {
br := c.bombingReport(p, ri, groups)
report = append(report, br)
if br.Wiped {
break
}
}
if p.Population == 0 {
// TODO: what aboul colonists left on planet?
p.Free()
clear(p.Route)
} else {
// Если на планете остались также и колонисты, то они превращаются в население,
// а накопленная промышленность возмещает потери производства.
p.UnpackColonists()
p.UnpackCapital()
}
}
return report
}
func (c *Cache) bombingReport(p *game.Planet, ri int, groups []int) *game.Bombing { func (c *Cache) bombingReport(p *game.Planet, ri int, groups []int) *game.Bombing {
attackPower := 0. attackPower := 0.
for _, i := range groups { for _, i := range groups {
@@ -14,10 +43,10 @@ func (c *Cache) bombingReport(p *game.Planet, ri int, groups []int) *game.Bombin
} }
r := &game.Bombing{ r := &game.Bombing{
ID: uuid.New(), ID: uuid.New(),
PlanetOwnedID: p.Owner, PlanetOwnedID: *p.Owner,
Planet: p.Name, Planet: p.Name,
Number: p.Number, Number: p.Number,
Owner: c.g.Race[c.RaceIndex(p.Owner)].Name, Owner: c.g.Race[c.RaceIndex(*p.Owner)].Name,
Attacker: c.g.Race[ri].Name, Attacker: c.g.Race[ri].Name,
Production: c.PlanetProductionDisplayName(p.Number), Production: c.PlanetProductionDisplayName(p.Number),
Industry: p.Industry, Industry: p.Industry,
@@ -32,33 +61,6 @@ func (c *Cache) bombingReport(p *game.Planet, ri int, groups []int) *game.Bombin
return r return r
} }
func (c *Cache) ProduceBombings() []*game.Bombing {
report := make([]*game.Bombing, 0)
for pn, enemies := range c.collectBombingGroups() {
p := c.MustPlanet(pn)
for ri, groups := range enemies {
br := c.bombingReport(p, ri, groups)
report = append(report, br)
if br.Wiped {
break
}
}
if p.Population == 0 {
// TODO: what aboul colonists left on planet?
p.Owner = uuid.Nil
p.Production = game.ProductionNone.AsType(uuid.Nil)
clear(p.Route)
} else {
// Если на планете остались также и колонисты, то они превращаются в население,
// а накопленная промышленность возмещает потери производства.
p.UnpackColonists()
p.UnpackCapital()
}
}
return report
}
func bombPlanet(p *game.Planet, power float64) { func bombPlanet(p *game.Planet, power float64) {
// Уничтожается население и колонисты в количестве равном [суммарной] мощности бомбардировки // Уничтожается население и колонисты в количестве равном [суммарной] мощности бомбардировки
if power > p.Population.F() { if power > p.Population.F() {
@@ -94,11 +96,11 @@ func (c *Cache) collectBombingGroups() map[uint]map[int][]int {
continue continue
} }
p := c.MustPlanet(sg.Destination) p := c.MustPlanet(sg.Destination)
if p.Owner == sg.OwnerID || p.Owner == uuid.Nil { if p.OwnedBy(sg.OwnerID) || !p.Owned() {
continue continue
} }
r1 := c.RaceIndex(sg.OwnerID) r1 := c.RaceIndex(sg.OwnerID)
r2 := c.RaceIndex(p.Owner) r2 := c.RaceIndex(*p.Owner)
if c.Relation(r1, r2) == game.RelationPeace { if c.Relation(r1, r2) == game.RelationPeace {
continue continue
} }
+4 -3
View File
@@ -10,7 +10,8 @@ import (
) )
func TestBombPlanet(t *testing.T) { func TestBombPlanet(t *testing.T) {
p := controller.NewPlanet(0, "Planet_0", uuid.New(), 1, 1, 1000, 300, 200, 10, game.ResearchDrive.AsType(uuid.Nil)) id := uuid.New()
p := controller.NewPlanet(0, "Planet_0", &id, 1, 1, 1000, 300, 200, 10, game.ResearchDrive.AsType(uuid.Nil))
(&p).Colonists = 100. (&p).Colonists = 100.
assert.Equal(t, 0., p.Material.F()) assert.Equal(t, 0., p.Material.F())
@@ -128,7 +129,7 @@ func TestProduceBombings(t *testing.T) {
assert.Equal(t, Race_0.Name, b.Attacker) assert.Equal(t, Race_0.Name, b.Attacker)
assert.InDelta(t, 697.857, b.AttackPower.F(), 0.0003) assert.InDelta(t, 697.857, b.AttackPower.F(), 0.0003)
assert.True(t, b.Wiped) assert.True(t, b.Wiped)
assert.Equal(t, uuid.Nil, c.MustPlanet(pn).Owner) assert.False(t, c.MustPlanet(pn).Owned())
assert.Empty(t, c.MustPlanet(pn).Route) assert.Empty(t, c.MustPlanet(pn).Route)
assert.Equal(t, 0., c.MustPlanet(pn).Population.F()) assert.Equal(t, 0., c.MustPlanet(pn).Population.F())
case R0_Planet_2_num: case R0_Planet_2_num:
@@ -136,7 +137,7 @@ func TestProduceBombings(t *testing.T) {
assert.Equal(t, Race_1.Name, b.Attacker) assert.Equal(t, Race_1.Name, b.Attacker)
assert.InDelta(t, 358.856, b.AttackPower.F(), 0.0001) assert.InDelta(t, 358.856, b.AttackPower.F(), 0.0001)
assert.False(t, b.Wiped) assert.False(t, b.Wiped)
assert.Equal(t, Race_0_ID, c.MustPlanet(pn).Owner) assert.True(t, c.MustPlanet(pn).OwnedBy(Race_0_ID))
assert.NotEmpty(t, c.MustPlanet(pn).Route) assert.NotEmpty(t, c.MustPlanet(pn).Route)
assert.InDelta(t, 500.-358.85596, c.MustPlanet(pn).Population.F(), 0.000001) assert.InDelta(t, 500.-358.85596, c.MustPlanet(pn).Population.F(), 0.000001)
} }
+5 -5
View File
@@ -95,11 +95,11 @@ func newGame() *game.Game {
Width: 1000, Width: 1000,
Height: 1000, Height: 1000,
Planet: []game.Planet{ Planet: []game.Planet{
controller.NewPlanet(R0_Planet_0_num, "Planet_0", Race_0.ID, 1, 1, 100, 100, 100, 0, game.ProductionCapital.AsType(uuid.Nil)), controller.NewPlanet(R0_Planet_0_num, "Planet_0", &Race_0.ID, 1, 1, 100, 100, 100, 0, game.ProductionCapital.AsType(uuid.Nil)),
controller.NewPlanet(R1_Planet_1_num, "Planet_1", Race_1.ID, 2, 2, 100, 0, 0, 0, game.ProductionCapital.AsType(uuid.Nil)), controller.NewPlanet(R1_Planet_1_num, "Planet_1", &Race_1.ID, 2, 2, 100, 0, 0, 0, game.ProductionCapital.AsType(uuid.Nil)),
controller.NewPlanet(R0_Planet_2_num, "Planet_2", Race_0.ID, 3, 3, 100, 0, 0, 0, game.ProductionCapital.AsType(uuid.Nil)), controller.NewPlanet(R0_Planet_2_num, "Planet_2", &Race_0.ID, 3, 3, 100, 0, 0, 0, game.ProductionCapital.AsType(uuid.Nil)),
controller.NewPlanet(Uninhabited_Planet_3_num, "Planet_3", uuid.Nil, 500, 500, 100, 0, 0, 0, game.ProductionNone.AsType(uuid.Nil)), controller.NewPlanet(Uninhabited_Planet_3_num, "Planet_3", &uuid.Nil, 500, 500, 100, 0, 0, 0, game.ProductionNone.AsType(uuid.Nil)),
controller.NewPlanet(Uninhabited_Planet_4_num, "Planet_4", uuid.Nil, 10, 10, 500, 0, 0, 10, game.ProductionNone.AsType(uuid.Nil)), controller.NewPlanet(Uninhabited_Planet_4_num, "Planet_4", nil, 10, 10, 500, 0, 0, 10, game.ProductionNone.AsType(uuid.Nil)),
}, },
}, },
} }
+17 -20
View File
@@ -71,7 +71,7 @@ func buildGameOnMap(races []string, m generator.Map) (*game.Game, error) {
gameMap.Planet = append(gameMap.Planet, NewPlanet( gameMap.Planet = append(gameMap.Planet, NewPlanet(
planetCount, planetCount,
m.HomePlanets[i].HW.RandomName(), m.HomePlanets[i].HW.RandomName(),
raceID, &raceID,
m.HomePlanets[i].HW.Position.X, m.HomePlanets[i].HW.Position.X,
m.HomePlanets[i].HW.Position.Y, m.HomePlanets[i].HW.Position.Y,
m.HomePlanets[i].HW.Size, m.HomePlanets[i].HW.Size,
@@ -85,7 +85,7 @@ func buildGameOnMap(races []string, m generator.Map) (*game.Game, error) {
gameMap.Planet = append(gameMap.Planet, NewPlanet( gameMap.Planet = append(gameMap.Planet, NewPlanet(
planetCount, planetCount,
m.HomePlanets[i].DW[dw].RandomName(), m.HomePlanets[i].DW[dw].RandomName(),
raceID, &raceID,
m.HomePlanets[i].DW[dw].Position.X, m.HomePlanets[i].DW[dw].Position.X,
m.HomePlanets[i].DW[dw].Position.Y, m.HomePlanets[i].DW[dw].Position.Y,
m.HomePlanets[i].DW[dw].Size, m.HomePlanets[i].DW[dw].Size,
@@ -107,7 +107,7 @@ func buildGameOnMap(races []string, m generator.Map) (*game.Game, error) {
gameMap.Planet = append(gameMap.Planet, NewPlanet( gameMap.Planet = append(gameMap.Planet, NewPlanet(
planetCount, planetCount,
m.FreePlanets[i].RandomName(), m.FreePlanets[i].RandomName(),
uuid.Nil, &uuid.Nil,
m.FreePlanets[i].Position.X, m.FreePlanets[i].Position.X,
m.FreePlanets[i].Position.Y, m.FreePlanets[i].Position.Y,
m.FreePlanets[i].Size, m.FreePlanets[i].Size,
@@ -128,23 +128,20 @@ func buildGameOnMap(races []string, m generator.Map) (*game.Game, error) {
return g, nil return g, nil
} }
func NewPlanet(num uint, name string, owner uuid.UUID, x, y, size, pop, ind, res float64, prod game.Production) game.Planet { func NewPlanet(num uint, name string, owner *uuid.UUID, x, y, size, pop, ind, res float64, prod game.Production) game.Planet {
if owner != nil && *owner == uuid.Nil {
owner = nil
}
return game.Planet{ return game.Planet{
Owner: owner, Owner: owner,
PlanetReport: game.PlanetReport{ X: game.F(x),
UninhabitedPlanet: game.UninhabitedPlanet{ Y: game.F(y),
UnidentifiedPlanet: game.UnidentifiedPlanet{ Number: num,
X: game.F(x), Size: game.F(size),
Y: game.F(y), Name: name,
Number: num, Resources: game.F(res),
}, Population: game.F(pop),
Size: game.F(size), Industry: game.F(ind),
Name: name, Production: prod,
Resources: game.F(res),
},
Population: game.F(pop),
Industry: game.F(ind),
Production: prod,
},
} }
} }
+9 -6
View File
@@ -31,7 +31,7 @@ func (c *Cache) RenamePlanet(ri int, number int, name string) error {
if !ok { if !ok {
return e.NewEntityNotExistsError("planet #%d", number) return e.NewEntityNotExistsError("planet #%d", number)
} }
if p.Owner != c.g.Race[ri].ID { if !p.OwnedBy(c.g.Race[ri].ID) {
return e.NewEntityNotOwnedError("planet #%d", number) return e.NewEntityNotOwnedError("planet #%d", number)
} }
c.g.Map.Planet[c.MustPlanetIndex(p.Number)].Name = n c.g.Map.Planet[c.MustPlanetIndex(p.Number)].Name = n
@@ -76,7 +76,7 @@ func (c *Cache) PlanetProduction(ri int, number int, prod game.ProductionType, s
if !ok { if !ok {
return e.NewEntityNotExistsError("planet #%d", number) return e.NewEntityNotExistsError("planet #%d", number)
} }
if p.Owner != c.g.Race[ri].ID { if !p.OwnedBy(c.g.Race[ri].ID) {
return e.NewEntityNotOwnedError("planet #%d", number) return e.NewEntityNotOwnedError("planet #%d", number)
} }
var subjectID *uuid.UUID var subjectID *uuid.UUID
@@ -128,7 +128,10 @@ func (c *Cache) PlanetProduction(ri int, number int, prod game.ProductionType, s
// TODO: test // TODO: test
func (c *Cache) PlanetProductionDisplayName(pn uint) string { func (c *Cache) PlanetProductionDisplayName(pn uint) string {
p := c.MustPlanet(pn) p := c.MustPlanet(pn)
ri := c.RaceIndex(p.Owner) if !p.Owned() {
return "-"
}
ri := c.RaceIndex(*p.Owner)
switch pt := p.Production.Type; pt { switch pt := p.Production.Type; pt {
case game.ResearchDrive: case game.ResearchDrive:
return "Drive" return "Drive"
@@ -202,14 +205,14 @@ func (c *Cache) TurnPlanetProductions() {
// cancel upgrade for groups on wiped planets // cancel upgrade for groups on wiped planets
for sgi := range c.ShipGroupsIndex() { for sgi := range c.ShipGroupsIndex() {
sg := c.ShipGroup(sgi) sg := c.ShipGroup(sgi)
if sg.State() == game.StateUpgrade && c.MustPlanet(sg.Destination).Owner == uuid.Nil { if sg.State() == game.StateUpgrade && !c.MustPlanet(sg.Destination).Owned() {
sg.StateUpgrade = nil sg.StateUpgrade = nil
} }
} }
for pn := range c.listProducingPlanets() { for pn := range c.listProducingPlanets() {
p := c.MustPlanet(pn) p := c.MustPlanet(pn)
ri := c.RaceIndex(p.Owner) ri := c.RaceIndex(*p.Owner)
r := &c.g.Race[ri] r := &c.g.Race[ri]
// upgrade groups and return to in_orbit state // upgrade groups and return to in_orbit state
@@ -261,7 +264,7 @@ func (c *Cache) TurnPlanetProductions() {
func (c *Cache) listProducingPlanets() iter.Seq[uint] { func (c *Cache) listProducingPlanets() iter.Seq[uint] {
ordered := make([]int, 0) ordered := make([]int, 0)
for i := range c.g.Map.Planet { for i := range c.g.Map.Planet {
if c.g.Map.Planet[i].Owner == uuid.Nil || c.g.Map.Planet[i].Production.Type == game.ProductionNone { if !c.g.Map.Planet[i].Owned() || c.g.Map.Planet[i].Production.Type == game.ProductionNone {
continue continue
} }
ordered = append(ordered, i) ordered = append(ordered, i)
+2 -1
View File
@@ -182,7 +182,8 @@ func TestProduceShip(t *testing.T) {
Shields: 35, Shields: 35,
Cargo: 0, Cargo: 0,
} }
p := controller.NewPlanet(0, "Planet_0", uuid.New(), 1, 1, 1000, 1000, 1000, 10, game.ProductionShip.AsType(uuid.Nil)) id := uuid.New()
p := controller.NewPlanet(0, "Planet_0", &id, 1, 1, 1000, 1000, 1000, 10, game.ProductionShip.AsType(uuid.Nil))
r := controller.ProduceShip(&p, p.ProductionCapacity(), Drone.EmptyMass()) r := controller.ProduceShip(&p, p.ProductionCapacity(), Drone.EmptyMass())
assert.Equal(t, uint(99), r) assert.Equal(t, uint(99), r)
+15 -15
View File
@@ -46,10 +46,10 @@ func (c *Cache) InitReport(t uint) *mr.Report {
planets := make(map[int]uint16) planets := make(map[int]uint16)
for pi := range c.g.Map.Planet { for pi := range c.g.Map.Planet {
p := &c.g.Map.Planet[pi] p := &c.g.Map.Planet[pi]
if p.Owner == uuid.Nil { if !p.Owned() {
continue continue
} }
ri := c.RaceIndex(p.Owner) ri := c.RaceIndex(*p.Owner)
sumPop[ri] += p.Population.F() sumPop[ri] += p.Population.F()
sumInd[ri] += p.Industry.F() sumInd[ri] += p.Industry.F()
planets[ri] = planets[ri] + 1 planets[ri] = planets[ri] + 1
@@ -206,10 +206,10 @@ func (c *Cache) ReportOtherScience(ri int, rep *mr.Report) {
continue continue
} }
p := c.MustPlanet(sg.Destination) p := c.MustPlanet(sg.Destination)
if p.Owner == uuid.Nil || p.Owner == r.ID || p.Production.Type != game.ResearchScience { if !p.Owned() || p.OwnedBy(r.ID) || p.Production.Type != game.ResearchScience {
continue continue
} }
ownerIdx := c.RaceIndex(p.Owner) ownerIdx := c.RaceIndex(*p.Owner)
owner := &c.g.Race[ownerIdx] owner := &c.g.Race[ownerIdx]
sc := c.mustScience(ownerIdx, *p.Production.SubjectID) sc := c.mustScience(ownerIdx, *p.Production.SubjectID)
@@ -296,7 +296,7 @@ func (c *Cache) ReportOtherShipClass(ri int, rep *mr.Report) {
// add visible ships from owned and observed planets // add visible ships from owned and observed planets
for pn := range rep.OnPlanetGroupCache { for pn := range rep.OnPlanetGroupCache {
p := c.MustPlanet(pn) p := c.MustPlanet(pn)
if p.Owner == r.ID || if p.OwnedBy(r.ID) ||
slices.IndexFunc(rep.OnPlanetGroupCache[pn], func(sgi int) bool { return c.ShipGroup(sgi).OwnerID == r.ID }) >= 0 { slices.IndexFunc(rep.OnPlanetGroupCache[pn], func(sgi int) bool { return c.ShipGroup(sgi).OwnerID == r.ID }) >= 0 {
for _, sgi := range rep.OnPlanetGroupCache[pn] { for _, sgi := range rep.OnPlanetGroupCache[pn] {
sg := c.ShipGroup(sgi) sg := c.ShipGroup(sgi)
@@ -389,7 +389,7 @@ func (c *Cache) ReportIncomingGroup(ri int, rep *mr.Report) {
} }
p1 := c.MustPlanet(sg.StateInSpace.Origin) p1 := c.MustPlanet(sg.StateInSpace.Origin)
p2 := c.MustPlanet(sg.Destination) p2 := c.MustPlanet(sg.Destination)
if p2.Owner != r.ID { if !p2.OwnedBy(r.ID) {
continue continue
} }
@@ -420,7 +420,7 @@ func (c *Cache) ReportLocalPlanet(ri int, rep *mr.Report) {
i := 0 i := 0
for pi := range c.g.Map.Planet { for pi := range c.g.Map.Planet {
p := &c.g.Map.Planet[pi] p := &c.g.Map.Planet[pi]
if p.Owner != r.ID { if !p.OwnedBy(r.ID) {
continue continue
} }
@@ -463,13 +463,13 @@ func (c *Cache) ReportOtherPlanet(ri int, rep *mr.Report) {
continue continue
} }
p := c.MustPlanet(sg.Destination) p := c.MustPlanet(sg.Destination)
if p.Owner == r.ID || p.Owner == uuid.Nil { if !p.Owned() || p.OwnedBy(r.ID) {
continue continue
} }
sliceIndexValidate(&rep.OtherPlanet, i) sliceIndexValidate(&rep.OtherPlanet, i)
c.localPlanet(&rep.OtherPlanet[i].LocalPlanet, p, rep) c.localPlanet(&rep.OtherPlanet[i].LocalPlanet, p, rep)
rep.OtherPlanet[i].Owner = c.g.Race[c.RaceIndex(p.Owner)].Name rep.OtherPlanet[i].Owner = c.g.Race[c.RaceIndex(*p.Owner)].Name
i++ i++
} }
} }
@@ -485,7 +485,7 @@ func (c *Cache) ReportUninhabitedPlanet(ri int, rep *mr.Report) {
continue continue
} }
p := c.MustPlanet(sg.Destination) p := c.MustPlanet(sg.Destination)
if p.Owner != uuid.Nil { if p.Owned() {
continue continue
} }
@@ -506,7 +506,7 @@ func (c *Cache) ReportUnidentifiedPlanet(ri int, rep *mr.Report) {
p := &c.g.Map.Planet[pi] p := &c.g.Map.Planet[pi]
// skip player's owned planets // skip player's owned planets
if p.Owner == r.ID { if p.OwnedBy(r.ID) {
continue continue
} }
@@ -530,7 +530,7 @@ func (c *Cache) ReportShipProduction(ri int, rep *mr.Report) {
i := 0 i := 0
for pi := range c.g.Map.Planet { for pi := range c.g.Map.Planet {
p := &c.g.Map.Planet[pi] p := &c.g.Map.Planet[pi]
if p.Owner != r.ID || p.Production.Type != game.ProductionShip { if !p.OwnedBy(r.ID) || p.Production.Type != game.ProductionShip {
continue continue
} }
st := c.MustShipType(ri, *p.Production.SubjectID) st := c.MustShipType(ri, *p.Production.SubjectID)
@@ -557,7 +557,7 @@ func (c *Cache) ReportRoute(ri int, rep *mr.Report) {
i := 0 i := 0
for pi := range c.g.Map.Planet { for pi := range c.g.Map.Planet {
p := &c.g.Map.Planet[pi] p := &c.g.Map.Planet[pi]
if p.Owner != r.ID || len(p.Route) == 0 { if !p.OwnedBy(r.ID) || len(p.Route) == 0 {
continue continue
} }
@@ -662,7 +662,7 @@ func (c *Cache) ReportOtherGroup(ri int, rep *mr.Report) {
// visible groups from owned and observed planets // visible groups from owned and observed planets
for pn := range rep.OnPlanetGroupCache { for pn := range rep.OnPlanetGroupCache {
p := c.MustPlanet(pn) p := c.MustPlanet(pn)
if p.Owner == r.ID || if p.OwnedBy(r.ID) ||
slices.IndexFunc(rep.OnPlanetGroupCache[pn], func(sgi int) bool { return c.ShipGroup(sgi).OwnerID == r.ID }) >= 0 { slices.IndexFunc(rep.OnPlanetGroupCache[pn], func(sgi int) bool { return c.ShipGroup(sgi).OwnerID == r.ID }) >= 0 {
for _, sgi := range rep.OnPlanetGroupCache[pn] { for _, sgi := range rep.OnPlanetGroupCache[pn] {
sg := c.ShipGroup(sgi) sg := c.ShipGroup(sgi)
@@ -697,7 +697,7 @@ func (c *Cache) ReportUnidentifiedGroup(ri int, rep *mr.Report) {
} }
for pi := range c.g.Map.Planet { for pi := range c.g.Map.Planet {
p := &c.g.Map.Planet[pi] p := &c.g.Map.Planet[pi]
if p.Owner != r.ID { if !p.OwnedBy(r.ID) {
continue continue
} }
if v, ok := rep.InSpaceGroupRangeCache[sgi][p.Number]; !ok { if v, ok := rep.InSpaceGroupRangeCache[sgi][p.Number]; !ok {
+7 -8
View File
@@ -8,7 +8,6 @@ import (
"math/rand/v2" "math/rand/v2"
"slices" "slices"
"github.com/google/uuid"
e "github.com/iliadenisov/galaxy/internal/error" e "github.com/iliadenisov/galaxy/internal/error"
"github.com/iliadenisov/galaxy/internal/model/game" "github.com/iliadenisov/galaxy/internal/model/game"
"github.com/iliadenisov/galaxy/internal/util" "github.com/iliadenisov/galaxy/internal/util"
@@ -32,7 +31,7 @@ func (c *Cache) SetRoute(ri int, rt game.RouteType, origin, destination uint) er
if !ok { if !ok {
return e.NewEntityNotExistsError("origin planet #%d", origin) return e.NewEntityNotExistsError("origin planet #%d", origin)
} }
if p1.Owner != c.g.Race[ri].ID { if !p1.OwnedBy(c.g.Race[ri].ID) {
return e.NewEntityNotOwnedError("planet #%d", origin) return e.NewEntityNotOwnedError("planet #%d", origin)
} }
p2, ok := c.Planet(destination) p2, ok := c.Planet(destination)
@@ -67,7 +66,7 @@ func (c *Cache) RemoveRoute(ri int, rt game.RouteType, origin uint) error {
if !ok { if !ok {
return e.NewEntityNotExistsError("origin planet #%d", origin) return e.NewEntityNotExistsError("origin planet #%d", origin)
} }
if p1.Owner != c.g.Race[ri].ID { if !p1.OwnedBy(c.g.Race[ri].ID) {
return e.NewEntityNotOwnedError("planet #%d", origin) return e.NewEntityNotOwnedError("planet #%d", origin)
} }
@@ -177,7 +176,7 @@ func (c *Cache) listRoutedSendGroupIds(pn uint) iter.Seq[int] {
for i := range c.ShipGroupsIndex() { for i := range c.ShipGroupsIndex() {
sg := c.ShipGroup(i) sg := c.ShipGroup(i)
st := c.ShipGroupShipClass(i) st := c.ShipGroupShipClass(i)
if sg.OwnerID != p.Owner || // Planet must be owned by ships owner if !p.OwnedBy(sg.OwnerID) || // Planet must be owned by ships owner
sg.FleetID != nil || // Ships must not be part of a Fleet sg.FleetID != nil || // Ships must not be part of a Fleet
sg.State() != game.StateInOrbit || // Ships must be only In_Orbit state sg.State() != game.StateInOrbit || // Ships must be only In_Orbit state
st.CargoBlockMass() == 0 || // Ship Class must have Cargo bays st.CargoBlockMass() == 0 || // Ship Class must have Cargo bays
@@ -208,10 +207,10 @@ func (c *Cache) TurnUnloadEnroutedGroups() {
func (c *Cache) RemoveUnreachableRoutes() { func (c *Cache) RemoveUnreachableRoutes() {
for i := range c.g.Map.Planet { for i := range c.g.Map.Planet {
p1 := &c.g.Map.Planet[i] p1 := &c.g.Map.Planet[i]
if p1.Owner == uuid.Nil { if !p1.Owned() {
continue continue
} }
ri := c.RaceIndex(p1.Owner) ri := c.RaceIndex(*p1.Owner)
for rt, destination := range p1.Route { for rt, destination := range p1.Route {
p2 := c.MustPlanet(destination) p2 := c.MustPlanet(destination)
rangeToDestination := util.ShortDistance(c.g.Map.Width, c.g.Map.Height, p1.X.F(), p1.Y.F(), p2.X.F(), p2.Y.F()) rangeToDestination := util.ShortDistance(c.g.Map.Width, c.g.Map.Height, p1.X.F(), p1.Y.F(), p2.X.F(), p2.Y.F())
@@ -231,13 +230,13 @@ func (c *Cache) doUnload(groups iter.Seq[int]) {
func (c *Cache) unloadRoutedColonists(pn uint, groups iter.Seq[int]) iter.Seq[int] { func (c *Cache) unloadRoutedColonists(pn uint, groups iter.Seq[int]) iter.Seq[int] {
p := c.MustPlanet(pn) p := c.MustPlanet(pn)
gr := slices.Collect(groups) gr := slices.Collect(groups)
if p.Owner == uuid.Nil { if !p.Owned() {
return c.selectColUnloadGroup(gr) return c.selectColUnloadGroup(gr)
} }
return func(yield func(int) bool) { return func(yield func(int) bool) {
for _, sgi := range gr { for _, sgi := range gr {
sg := c.ShipGroup(sgi) sg := c.ShipGroup(sgi)
if p.Owner != sg.OwnerID { if !p.OwnedBy(sg.OwnerID) {
continue continue
} }
if !yield(sgi) { if !yield(sgi) {
+1 -1
View File
@@ -412,7 +412,7 @@ func TestTurnUnloadEnroutedGroups(t *testing.T) {
assert.Equal(t, 11., c.MustPlanet(R0_Planet_0_num).Capital.F()) assert.Equal(t, 11., c.MustPlanet(R0_Planet_0_num).Capital.F())
assert.Equal(t, 0., c.ShipGroup(2).Load.F()) assert.Equal(t, 0., c.ShipGroup(2).Load.F())
assert.Equal(t, 96.8, c.MustPlanet(Uninhabited_Planet_4_num).Population.F()) assert.Equal(t, 96.8, c.MustPlanet(Uninhabited_Planet_4_num).Population.F())
assert.Equal(t, Race_1_ID, c.MustPlanet(Uninhabited_Planet_4_num).Owner) assert.True(t, c.MustPlanet(Uninhabited_Planet_4_num).OwnedBy(Race_1_ID))
assert.Equal(t, game.ProductionCapital, c.MustPlanet(Uninhabited_Planet_4_num).Production.Type) assert.Equal(t, game.ProductionCapital, c.MustPlanet(Uninhabited_Planet_4_num).Production.Type)
assert.Equal(t, 17.3, c.ShipGroup(3).Load.F()) assert.Equal(t, 17.3, c.ShipGroup(3).Load.F())
} }
+1 -1
View File
@@ -75,7 +75,7 @@ func (c *Cache) MergeShipType(ri int, name, targetName string) error {
// switch planet productions to the new type // switch planet productions to the new type
for pl := range c.g.Map.Planet { for pl := range c.g.Map.Planet {
if c.g.Map.Planet[pl].Owner == c.g.Race[ri].ID && if c.g.Map.Planet[pl].OwnedBy(c.g.Race[ri].ID) &&
c.g.Map.Planet[pl].Production.Type == game.ProductionShip && c.g.Map.Planet[pl].Production.Type == game.ProductionShip &&
c.g.Map.Planet[pl].Production.SubjectID != nil && c.g.Map.Planet[pl].Production.SubjectID != nil &&
*c.g.Map.Planet[pl].Production.SubjectID == st.ID { *c.g.Map.Planet[pl].Production.SubjectID == st.ID {
+6 -6
View File
@@ -21,7 +21,7 @@ func (c *Cache) CreateShips(ri int, shipTypeName string, planetNumber uint, quan
if !ok { if !ok {
return e.NewEntityNotExistsError("planet #%d", planetNumber) return e.NewEntityNotExistsError("planet #%d", planetNumber)
} }
if p.Owner != c.g.Race[ri].ID { if !p.OwnedBy(c.g.Race[ri].ID) {
return e.NewEntityNotOwnedError("planet #%d", planetNumber) return e.NewEntityNotOwnedError("planet #%d", planetNumber)
} }
@@ -231,7 +231,7 @@ func (c *Cache) DisassembleGroup(ri int, groupIndex, quantity uint) error {
load := c.ShipGroup(sgi).Load.F() load := c.ShipGroup(sgi).Load.F()
switch ct { switch ct {
case game.CargoColonist: case game.CargoColonist:
if p.Owner == c.g.Race[ri].ID { if p.OwnedBy(c.g.Race[ri].ID) {
p = game.UnloadColonists(p, load) p = game.UnloadColonists(p, load)
} }
case game.CargoMaterial: case game.CargoMaterial:
@@ -281,7 +281,7 @@ func (c *Cache) LoadCargo(ri int, groupIndex uint, ct game.CargoType, ships uint
return e.NewGameStateError("planet #%d", c.ShipGroup(sgi).Destination) return e.NewGameStateError("planet #%d", c.ShipGroup(sgi).Destination)
} }
if p.Owner != uuid.Nil && p.Owner != c.g.Race[ri].ID { if p.Owned() && !p.OwnedBy(c.g.Race[ri].ID) {
return e.NewEntityNotOwnedError("planet #%d", p.Number) return e.NewEntityNotOwnedError("planet #%d", p.Number)
} }
st := c.ShipGroupShipClass(sgi) st := c.ShipGroupShipClass(sgi)
@@ -366,7 +366,7 @@ func (c *Cache) UnloadCargo(ri int, groupIndex uint, ships uint, quantity float6
ct := *c.ShipGroup(sgi).CargoType ct := *c.ShipGroup(sgi).CargoType
p := c.MustPlanet(c.ShipGroup(sgi).Destination) p := c.MustPlanet(c.ShipGroup(sgi).Destination)
if ct == game.CargoColonist && p.Owner != uuid.Nil && p.Owner != c.g.Race[ri].ID { if ct == game.CargoColonist && p.Owned() && !p.OwnedBy(c.g.Race[ri].ID) {
return e.NewEntityNotOwnedError("planet #%d unload %v", p.Number, ct) return e.NewEntityNotOwnedError("planet #%d unload %v", p.Number, ct)
} }
if ships > 0 && ships < c.ShipGroup(sgi).Number { if ships > 0 && ships < c.ShipGroup(sgi).Number {
@@ -405,8 +405,8 @@ func (c *Cache) unsafeUnloadCargo(sgi int, q float64) {
switch ct { switch ct {
case game.CargoColonist: case game.CargoColonist:
availableOnPlanet = &p.Colonists availableOnPlanet = &p.Colonists
if p.Owner == uuid.Nil { if !p.Owned() {
p.Owner = c.ShipGroup(sgi).OwnerID p.Own(c.ShipGroup(sgi).OwnerID)
p.Production = game.ProductionCapital.AsType(uuid.Nil) p.Production = game.ProductionCapital.AsType(uuid.Nil)
} }
case game.CargoMaterial: case game.CargoMaterial:
+1 -2
View File
@@ -4,7 +4,6 @@ import (
"math" "math"
"slices" "slices"
"github.com/google/uuid"
e "github.com/iliadenisov/galaxy/internal/error" e "github.com/iliadenisov/galaxy/internal/error"
"github.com/iliadenisov/galaxy/internal/model/game" "github.com/iliadenisov/galaxy/internal/model/game"
) )
@@ -31,7 +30,7 @@ func (c *Cache) UpgradeGroup(ri int, groupIndex uint, techInput string, limitShi
} }
p := c.MustPlanet(sg.Destination) p := c.MustPlanet(sg.Destination)
if p.Owner != uuid.Nil && p.Owner != c.g.Race[ri].ID { if p.Owned() && !p.OwnedBy(c.g.Race[ri].ID) {
return e.NewEntityNotOwnedError("planet #%d for upgrade group #%d", p.Number, groupIndex) return e.NewEntityNotOwnedError("planet #%d for upgrade group #%d", p.Number, groupIndex)
} }
+2 -2
View File
@@ -83,10 +83,10 @@ func (c *Cache) votesByRace() map[int]float64 {
result := make(map[int]float64) result := make(map[int]float64)
for i := range c.g.Map.Planet { for i := range c.g.Map.Planet {
p := &c.g.Map.Planet[i] p := &c.g.Map.Planet[i]
if p.Owner == uuid.Nil { if !p.Owned() {
continue continue
} }
ri := c.RaceIndex(p.Owner) ri := c.RaceIndex(*p.Owner)
planetVotes := p.Votes() planetVotes := p.Votes()
result[ri] += planetVotes result[ri] += planetVotes
} }
+3 -3
View File
@@ -19,9 +19,9 @@ func TestRenamePlanet(t *testing.T) {
var number int var number int
var owner uuid.UUID var owner uuid.UUID
for pl := range cg.Map.Planet { for pl := range cg.Map.Planet {
if cg.Map.Planet[pl].Owner != uuid.Nil { if cg.Map.Planet[pl].Owned() {
number = int(cg.Map.Planet[pl].Number) number = int(cg.Map.Planet[pl].Number)
owner = cg.Map.Planet[pl].Owner owner = *cg.Map.Planet[pl].Owner
break break
} }
} }
@@ -36,7 +36,7 @@ func TestRenamePlanet(t *testing.T) {
err := game.RenamePlanet(p, race, number, newName) err := game.RenamePlanet(p, race, number, newName)
assert.NoError(t, err) assert.NoError(t, err)
cg = g() cg = g()
pi := slices.IndexFunc(cg.Map.Planet, func(pl mg.Planet) bool { return pl.Owner == owner && pl.Number == uint(number) }) pi := slices.IndexFunc(cg.Map.Planet, func(pl mg.Planet) bool { return pl.OwnedBy(owner) && pl.Number == uint(number) })
assert.GreaterOrEqual(t, pi, 0) assert.GreaterOrEqual(t, pi, 0)
assert.Equal(t, "Some-New-Name", cg.Map.Planet[pi].Name) assert.Equal(t, "Some-New-Name", cg.Map.Planet[pi].Name)
+1 -1
View File
@@ -70,7 +70,7 @@ type BattleMeta struct {
func (g Game) RaceVotes(raceID uuid.UUID) float64 { func (g Game) RaceVotes(raceID uuid.UUID) float64 {
var result float64 var result float64
for i := range g.Map.Planet { for i := range g.Map.Planet {
if g.Map.Planet[i].Owner == raceID { if g.Map.Planet[i].OwnedBy(raceID) {
result += g.Map.Planet[i].Votes() result += g.Map.Planet[i].Votes()
} }
} }
+39 -30
View File
@@ -6,39 +6,48 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
) )
type UnidentifiedPlanet struct {
X Float `json:"x"`
Y Float `json:"y"`
Number uint `json:"number"`
}
type UninhabitedPlanet struct {
UnidentifiedPlanet
Size Float `json:"size"`
Name string `json:"name"`
Resources Float `json:"resources"` // R - Ресурсы
Capital Float `json:"capital"` // CAP $ - Запасы промышленности
Material Float `json:"material"` // MAT M - Запасы ресурсов / сырьё
}
type PlanetReport struct {
UninhabitedPlanet
Industry Float `json:"industry"` // I - Промышленность
Population Float `json:"population"` // P - Население
Colonists Float `json:"colonists"` // COL C - Количество колонистов
Production Production `json:"production"` // TODO: internal/report format
}
// TODO: unwrap in one struct
type Planet struct { type Planet struct {
Owner uuid.UUID `json:"owner"` // FIXME: nil value when no owner X Float `json:"x"`
Route map[RouteType]uint `json:"route"` Y Float `json:"y"`
PlanetReport Number uint `json:"number"`
Size Float `json:"size"`
Name string `json:"name"`
Owner *uuid.UUID `json:"owner,omitempty"`
Resources Float `json:"resources"` // R - Ресурсы
Capital Float `json:"capital"` // CAP $ - Запасы промышленности
Material Float `json:"material"` // MAT M - Запасы ресурсов / сырьё
Industry Float `json:"industry"` // I - Промышленность
Population Float `json:"population"` // P - Население
Colonists Float `json:"colonists"` // COL C - Количество колонистов
Production Production `json:"production"`
Route map[RouteType]uint `json:"route"`
} }
type PlanetReportForeign struct { func (p *Planet) Own(v uuid.UUID) {
RaceName string if v == uuid.Nil {
PlanetReport p.Free()
return
}
if p.Owner == nil || *p.Owner != v {
p.Production = ProductionCapital.AsType(uuid.Nil)
}
p.Owner = &v
}
func (p *Planet) Free() {
p.Owner = nil
p.Production = ProductionNone.AsType(uuid.Nil)
}
func (p Planet) Owned() bool {
return p.Owner != nil && *p.Owner != uuid.Nil
}
func (p Planet) OwnedBy(v uuid.UUID) bool {
if !p.Owned() {
return false
}
return *p.Owner == v
} }
func (p *Planet) Mat(v float64) { func (p *Planet) Mat(v float64) {
+24 -48
View File
@@ -16,24 +16,16 @@ func TestPlanetProduction(t *testing.T) {
func TestProduceIndustry(t *testing.T) { func TestProduceIndustry(t *testing.T) {
HW := &game.Planet{ HW := &game.Planet{
PlanetReport: game.PlanetReport{ Size: 1000,
UninhabitedPlanet: game.UninhabitedPlanet{ Resources: 10,
Size: 1000, Population: 1000,
Resources: 10, Industry: 1000,
},
Population: 1000,
Industry: 1000,
},
} }
DW := &game.Planet{ DW := &game.Planet{
PlanetReport: game.PlanetReport{ Size: 500,
UninhabitedPlanet: game.UninhabitedPlanet{ Resources: 10,
Size: 500, Population: 500,
Resources: 10, Industry: 500,
},
Population: 500,
Industry: 500,
},
} }
HW.ProduceIndustry() HW.ProduceIndustry()
assert.InDelta(t, 196.078, HW.Capital.F(), 0.0005) assert.InDelta(t, 196.078, HW.Capital.F(), 0.0005)
@@ -58,14 +50,10 @@ func TestProduceIndustry(t *testing.T) {
func TestProduceMaterial(t *testing.T) { func TestProduceMaterial(t *testing.T) {
HW := &game.Planet{ HW := &game.Planet{
PlanetReport: game.PlanetReport{ Size: 1000,
UninhabitedPlanet: game.UninhabitedPlanet{ Resources: 10,
Size: 1000, Population: 1000,
Resources: 10, Industry: 1000,
},
Population: 1000,
Industry: 1000,
},
} }
assert.Equal(t, 0., HW.Material.F()) assert.Equal(t, 0., HW.Material.F())
@@ -84,14 +72,10 @@ func TestProduceMaterial(t *testing.T) {
func TestUnpackCapital(t *testing.T) { func TestUnpackCapital(t *testing.T) {
HW := &game.Planet{ HW := &game.Planet{
PlanetReport: game.PlanetReport{ Size: 1000,
UninhabitedPlanet: game.UninhabitedPlanet{ Resources: 10,
Size: 1000, Population: 1000,
Resources: 10, Industry: 1000,
},
Population: 1000,
Industry: 1000,
},
} }
assert.Equal(t, 0., HW.Capital.F()) assert.Equal(t, 0., HW.Capital.F())
@@ -119,14 +103,10 @@ func TestUnpackCapital(t *testing.T) {
func TestUnpackColonists(t *testing.T) { func TestUnpackColonists(t *testing.T) {
HW := &game.Planet{ HW := &game.Planet{
PlanetReport: game.PlanetReport{ Size: 1000,
UninhabitedPlanet: game.UninhabitedPlanet{ Resources: 10,
Size: 1000, Population: 1000,
Resources: 10, Industry: 1000,
},
Population: 1000,
Industry: 1000,
},
} }
assert.Equal(t, 0., HW.Colonists.F()) assert.Equal(t, 0., HW.Colonists.F())
@@ -152,14 +132,10 @@ func TestUnpackColonists(t *testing.T) {
func TestProducePopulation(t *testing.T) { func TestProducePopulation(t *testing.T) {
HW := &game.Planet{ HW := &game.Planet{
PlanetReport: game.PlanetReport{ Size: 1000,
UninhabitedPlanet: game.UninhabitedPlanet{ Resources: 10,
Size: 1000, Population: 500,
Resources: 10, Industry: 1000,
},
Population: 500,
Industry: 1000,
},
} }
assert.Equal(t, 500., HW.Population.F()) assert.Equal(t, 500., HW.Population.F())
assert.Equal(t, 0., HW.Colonists.F()) assert.Equal(t, 0., HW.Colonists.F())