refactor: floats, tests
This commit is contained in:
@@ -64,9 +64,9 @@ func FilterBattleOpponents(c *Cache, attIdx, defIdx int, cacheProbability map[in
|
|||||||
}
|
}
|
||||||
|
|
||||||
p := DestructionProbability(
|
p := DestructionProbability(
|
||||||
c.ShipGroupShipClass(attIdx).Weapons,
|
c.ShipGroupShipClass(attIdx).Weapons.F(),
|
||||||
c.ShipGroup(attIdx).TechLevel(game.TechWeapons).F(),
|
c.ShipGroup(attIdx).TechLevel(game.TechWeapons).F(),
|
||||||
c.ShipGroupShipClass(defIdx).Shields,
|
c.ShipGroupShipClass(defIdx).Shields.F(),
|
||||||
c.ShipGroup(defIdx).TechLevel(game.TechShields).F(),
|
c.ShipGroup(defIdx).TechLevel(game.TechShields).F(),
|
||||||
c.ShipGroup(defIdx).FullMass(c.ShipGroupShipClass(defIdx)),
|
c.ShipGroup(defIdx).FullMass(c.ShipGroupShipClass(defIdx)),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -36,25 +36,25 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestDestructionProbability(t *testing.T) {
|
func TestDestructionProbability(t *testing.T) {
|
||||||
probability := controller.DestructionProbability(ship.Weapons, 1, ship.Shields, 1, ship.EmptyMass())
|
probability := controller.DestructionProbability(ship.Weapons.F(), 1, ship.Shields.F(), 1, ship.EmptyMass())
|
||||||
assert.Equal(t, .5, probability)
|
assert.Equal(t, .5, probability)
|
||||||
|
|
||||||
undefeatedShip := ship
|
undefeatedShip := ship
|
||||||
undefeatedShip.Shields = 55
|
undefeatedShip.Shields = 55
|
||||||
probability = controller.DestructionProbability(ship.Weapons, 1, undefeatedShip.Shields, 1, undefeatedShip.EmptyMass())
|
probability = controller.DestructionProbability(ship.Weapons.F(), 1, undefeatedShip.Shields.F(), 1, undefeatedShip.EmptyMass())
|
||||||
assert.LessOrEqual(t, probability, 0.)
|
assert.LessOrEqual(t, probability, 0.)
|
||||||
|
|
||||||
disruptiveShip := ship
|
disruptiveShip := ship
|
||||||
disruptiveShip.Weapons = 40
|
disruptiveShip.Weapons = 40
|
||||||
probability = controller.DestructionProbability(disruptiveShip.Weapons, 1, ship.Shields, 1, ship.EmptyMass())
|
probability = controller.DestructionProbability(disruptiveShip.Weapons.F(), 1, ship.Shields.F(), 1, ship.EmptyMass())
|
||||||
assert.GreaterOrEqual(t, probability, 1.)
|
assert.GreaterOrEqual(t, probability, 1.)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEffectiveDefence(t *testing.T) {
|
func TestEffectiveDefence(t *testing.T) {
|
||||||
assert.Equal(t, 10., controller.EffectiveDefence(ship.Shields, 1, ship.EmptyMass()))
|
assert.Equal(t, 10., controller.EffectiveDefence(ship.Shields.F(), 1, ship.EmptyMass()))
|
||||||
|
|
||||||
attackerEffectiveDefence := controller.EffectiveDefence(attacker.Shields, 1, attacker.EmptyMass())
|
attackerEffectiveDefence := controller.EffectiveDefence(attacker.Shields.F(), 1, attacker.EmptyMass())
|
||||||
defenderEffectiveDefence := controller.EffectiveDefence(defender.Shields, 1, defender.EmptyMass())
|
defenderEffectiveDefence := controller.EffectiveDefence(defender.Shields.F(), 1, defender.EmptyMass())
|
||||||
|
|
||||||
// attacker's effective shields must be 'just' 4 times greater than defender's
|
// attacker's effective shields must be 'just' 4 times greater than defender's
|
||||||
assert.InDelta(t, defenderEffectiveDefence*4, attackerEffectiveDefence, 0)
|
assert.InDelta(t, defenderEffectiveDefence*4, attackerEffectiveDefence, 0)
|
||||||
@@ -95,7 +95,7 @@ func TestFilterBattleOpponents(t *testing.T) {
|
|||||||
assert.NoError(t, c.CreateShips(Race_1_idx, Race_1_Gunship, R1_Planet_1_num, 15)) // 2
|
assert.NoError(t, c.CreateShips(Race_1_idx, Race_1_Gunship, R1_Planet_1_num, 15)) // 2
|
||||||
undefeatedShip := ship
|
undefeatedShip := ship
|
||||||
undefeatedShip.Shields = 100
|
undefeatedShip.Shields = 100
|
||||||
assert.NoError(t, c.CreateShipType(Race_1_idx, undefeatedShip.Name, undefeatedShip.Drive, int(undefeatedShip.Armament), undefeatedShip.Weapons, undefeatedShip.Shields, undefeatedShip.Cargo))
|
assert.NoError(t, c.CreateShipType(Race_1_idx, undefeatedShip.Name, undefeatedShip.Drive.F(), int(undefeatedShip.Armament), undefeatedShip.Weapons.F(), undefeatedShip.Shields.F(), undefeatedShip.Cargo.F()))
|
||||||
assert.NoError(t, c.CreateShips(Race_1_idx, undefeatedShip.Name, R1_Planet_1_num, 1)) // 3
|
assert.NoError(t, c.CreateShips(Race_1_idx, undefeatedShip.Name, R1_Planet_1_num, 1)) // 3
|
||||||
|
|
||||||
cacheProbability := make(map[int]map[int]float64)
|
cacheProbability := make(map[int]map[int]float64)
|
||||||
@@ -120,7 +120,7 @@ func TestFilterBattleOpponents(t *testing.T) {
|
|||||||
assert.True(t, controller.FilterBattleOpponents(c, 2, 0, cacheProbability))
|
assert.True(t, controller.FilterBattleOpponents(c, 2, 0, cacheProbability))
|
||||||
assert.NoError(t, c.UpdateRelation(Race_0_idx, Race_1_idx, game.RelationWar))
|
assert.NoError(t, c.UpdateRelation(Race_0_idx, Race_1_idx, game.RelationWar))
|
||||||
|
|
||||||
assert.LessOrEqual(t, controller.DestructionProbability(Cruiser.Weapons, 1, undefeatedShip.Shields, 1, undefeatedShip.EmptyMass()), 0.)
|
assert.LessOrEqual(t, controller.DestructionProbability(Cruiser.Weapons.F(), 1, undefeatedShip.Shields.F(), 1, undefeatedShip.EmptyMass()), 0.)
|
||||||
assert.True(t, controller.FilterBattleOpponents(c, 1, 3, cacheProbability))
|
assert.True(t, controller.FilterBattleOpponents(c, 1, 3, cacheProbability))
|
||||||
assert.NotContains(t, cacheProbability[1], 3)
|
assert.NotContains(t, cacheProbability[1], 3)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ func TransformBattle(c *Cache, b *Battle) *report.BattleReport {
|
|||||||
// CargoTech: report.F(sg.TechLevel(game.TechCargo).F()),
|
// CargoTech: report.F(sg.TechLevel(game.TechCargo).F()),
|
||||||
}
|
}
|
||||||
for t, v := range sg.Tech {
|
for t, v := range sg.Tech {
|
||||||
bg.Tech[t.String()] = report.F(v)
|
bg.Tech[t.String()] = report.F(v.F())
|
||||||
}
|
}
|
||||||
r.Ships[itemNumber] = *bg
|
r.Ships[itemNumber] = *bg
|
||||||
cacheShipClass[shipClass.ID] = itemNumber
|
cacheShipClass[shipClass.ID] = itemNumber
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ func TestProduceBombings(t *testing.T) {
|
|||||||
case R0_Planet_2_num:
|
case R0_Planet_2_num:
|
||||||
assert.Equal(t, Race_0.Name, b.Owner)
|
assert.Equal(t, Race_0.Name, b.Owner)
|
||||||
assert.Equal(t, Race_1.Name, b.Attacker)
|
assert.Equal(t, Race_1.Name, b.Attacker)
|
||||||
assert.Equal(t, 358.856, b.AttackPower.F())
|
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.Equal(t, Race_0_ID, c.MustPlanet(pn).Owner)
|
||||||
assert.NotEmpty(t, c.MustPlanet(pn).Route)
|
assert.NotEmpty(t, c.MustPlanet(pn).Route)
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ var (
|
|||||||
ID: Race_0_ID,
|
ID: Race_0_ID,
|
||||||
VoteFor: Race_0_ID,
|
VoteFor: Race_0_ID,
|
||||||
Name: "Race_0",
|
Name: "Race_0",
|
||||||
Tech: map[game.Tech]float64{
|
Tech: map[game.Tech]game.Float{
|
||||||
game.TechDrive: 1.1,
|
game.TechDrive: 1.1,
|
||||||
game.TechWeapons: 1.2,
|
game.TechWeapons: 1.2,
|
||||||
game.TechShields: 1.3,
|
game.TechShields: 1.3,
|
||||||
@@ -28,7 +28,7 @@ var (
|
|||||||
ID: Race_1_ID,
|
ID: Race_1_ID,
|
||||||
VoteFor: Race_1_ID,
|
VoteFor: Race_1_ID,
|
||||||
Name: "Race_1",
|
Name: "Race_1",
|
||||||
Tech: map[game.Tech]float64{
|
Tech: map[game.Tech]game.Float{
|
||||||
game.TechDrive: 2.1,
|
game.TechDrive: 2.1,
|
||||||
game.TechWeapons: 2.2,
|
game.TechWeapons: 2.2,
|
||||||
game.TechShields: 2.3,
|
game.TechShields: 2.3,
|
||||||
@@ -95,9 +95,9 @@ 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.ProductionNone.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.ProductionNone.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.ProductionNone.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", uuid.Nil, 10, 10, 500, 0, 0, 10, game.ProductionNone.AsType(uuid.Nil)),
|
||||||
},
|
},
|
||||||
@@ -111,7 +111,7 @@ func newCache() (*controller.Cache, *controller.Controller) {
|
|||||||
c := controller.NewCache(g)
|
c := controller.NewCache(g)
|
||||||
assertNoError(c.CreateShipType(Race_0_idx, Race_0_Gunship, 60, 3, 30, 100, 0))
|
assertNoError(c.CreateShipType(Race_0_idx, Race_0_Gunship, 60, 3, 30, 100, 0))
|
||||||
assertNoError(c.CreateShipType(Race_0_idx, Race_0_Freighter, 8, 0, 0, 2, 10))
|
assertNoError(c.CreateShipType(Race_0_idx, Race_0_Freighter, 8, 0, 0, 2, 10))
|
||||||
assertNoError(c.CreateShipType(Race_0_idx, ShipType_Cruiser, Cruiser.Drive, int(Cruiser.Armament), Cruiser.Weapons, Cruiser.Shields, Cruiser.Cargo))
|
assertNoError(c.CreateShipType(Race_0_idx, ShipType_Cruiser, Cruiser.Drive.F(), int(Cruiser.Armament), Cruiser.Weapons.F(), Cruiser.Shields.F(), Cruiser.Cargo.F()))
|
||||||
|
|
||||||
assertNoError(c.CreateShipType(Race_1_idx, Race_1_Gunship, 60, 3, 30, 100, 0))
|
assertNoError(c.CreateShipType(Race_1_idx, Race_1_Gunship, 60, 3, 30, 100, 0))
|
||||||
assertNoError(c.CreateShipType(Race_1_idx, Race_1_Freighter, 8, 0, 0, 2, 10))
|
assertNoError(c.CreateShipType(Race_1_idx, Race_1_Freighter, 8, 0, 0, 2, 10))
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ func buildGameOnMap(races []string, m generator.Map) (*game.Game, error) {
|
|||||||
ID: raceID,
|
ID: raceID,
|
||||||
Name: races[i],
|
Name: races[i],
|
||||||
VoteFor: raceID,
|
VoteFor: raceID,
|
||||||
Tech: map[game.Tech]float64{
|
Tech: map[game.Tech]game.Float{
|
||||||
game.TechDrive: 1,
|
game.TechDrive: 1,
|
||||||
game.TechWeapons: 1,
|
game.TechWeapons: 1,
|
||||||
game.TechShields: 1,
|
game.TechShields: 1,
|
||||||
|
|||||||
@@ -108,11 +108,11 @@ func (c *Cache) PlanetProduction(ri int, number int, prod game.ProductionType, s
|
|||||||
|
|
||||||
if p.Production.Type == game.ProductionShip && (prod != game.ProductionShip || *subjectID != *p.Production.SubjectID) {
|
if p.Production.Type == game.ProductionShip && (prod != game.ProductionShip || *subjectID != *p.Production.SubjectID) {
|
||||||
mat, _ := c.MustShipType(ri, *p.Production.SubjectID).ProductionCost()
|
mat, _ := c.MustShipType(ri, *p.Production.SubjectID).ProductionCost()
|
||||||
p.Mat(p.Material.F() + mat*(*p.Production.Progress))
|
p.Mat(p.Material.F() + mat*(*p.Production.Progress).F())
|
||||||
*p.Production.Progress = 0.
|
*p.Production.Progress = 0.
|
||||||
} else if prod == game.ProductionShip {
|
} else if prod == game.ProductionShip {
|
||||||
// new ship class to produce; otherwise we must have been returned from the func earlier
|
// new ship class to produce; otherwise we must have been returned from the func earlier
|
||||||
var progress float64 = 0.
|
progress := game.F(0.)
|
||||||
p.Production.Progress = &progress
|
p.Production.Progress = &progress
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,7 +218,7 @@ func (c *Cache) TurnPlanetProductions() {
|
|||||||
cost := sg.StateUpgrade.Cost()
|
cost := sg.StateUpgrade.Cost()
|
||||||
if productionAvailable >= cost {
|
if productionAvailable >= cost {
|
||||||
for i := range sg.StateUpgrade.UpgradeTech {
|
for i := range sg.StateUpgrade.UpgradeTech {
|
||||||
sg.Tech = sg.Tech.Set(sg.StateUpgrade.UpgradeTech[i].Tech, sg.StateUpgrade.UpgradeTech[i].Level)
|
sg.Tech = sg.Tech.Set(sg.StateUpgrade.UpgradeTech[i].Tech, sg.StateUpgrade.UpgradeTech[i].Level.F())
|
||||||
}
|
}
|
||||||
productionAvailable -= cost
|
productionAvailable -= cost
|
||||||
}
|
}
|
||||||
@@ -233,7 +233,7 @@ func (c *Cache) TurnPlanetProductions() {
|
|||||||
}
|
}
|
||||||
case game.ResearchScience:
|
case game.ResearchScience:
|
||||||
sc := c.mustScience(ri, *p.Production.SubjectID)
|
sc := c.mustScience(ri, *p.Production.SubjectID)
|
||||||
ResearchTech(r, p.ProductionCapacity(), sc.Drive, sc.Weapons, sc.Shields, sc.Cargo)
|
ResearchTech(r, p.ProductionCapacity(), sc.Drive.F(), sc.Weapons.F(), sc.Shields.F(), sc.Cargo.F())
|
||||||
case game.ResearchDrive:
|
case game.ResearchDrive:
|
||||||
ResearchTech(r, p.ProductionCapacity(), 1., 0, 0, 0)
|
ResearchTech(r, p.ProductionCapacity(), 1., 0, 0, 0)
|
||||||
case game.ResearchWeapons:
|
case game.ResearchWeapons:
|
||||||
@@ -247,7 +247,7 @@ func (c *Cache) TurnPlanetProductions() {
|
|||||||
case game.ProductionCapital:
|
case game.ProductionCapital:
|
||||||
p.ProduceIndustry()
|
p.ProduceIndustry()
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("unprocessed production type: %v", pt))
|
panic(fmt.Sprintf("unprocessed production type: '%v' for planet: #%d owner=%v", pt, pn, p.Owner))
|
||||||
}
|
}
|
||||||
|
|
||||||
// last step: increase population / colonists
|
// last step: increase population / colonists
|
||||||
@@ -261,7 +261,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 {
|
if c.g.Map.Planet[i].Owner == uuid.Nil || c.g.Map.Planet[i].Production.Type == game.ProductionNone {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ordered = append(ordered, i)
|
ordered = append(ordered, i)
|
||||||
@@ -305,7 +305,7 @@ func ProduceShip(p *game.Planet, productionAvailable, shipMass float64) uint {
|
|||||||
CAP_perShip := shipMass / p.Resources.F()
|
CAP_perShip := shipMass / p.Resources.F()
|
||||||
productionForMass := shipMass * 10.
|
productionForMass := shipMass * 10.
|
||||||
ships := uint(0)
|
ships := uint(0)
|
||||||
flZero := 0.
|
flZero := game.F(0.)
|
||||||
p.Production.Progress = &flZero
|
p.Production.Progress = &flZero
|
||||||
for productionAvailable > 0 {
|
for productionAvailable > 0 {
|
||||||
var productionExtraCAP float64
|
var productionExtraCAP float64
|
||||||
@@ -318,8 +318,8 @@ func ProduceShip(p *game.Planet, productionAvailable, shipMass float64) uint {
|
|||||||
p.Cap(p.Capital.F() - (CAP_perShip - productionExtraCAP))
|
p.Cap(p.Capital.F() - (CAP_perShip - productionExtraCAP))
|
||||||
ships++
|
ships++
|
||||||
} else {
|
} else {
|
||||||
progress := productionAvailable / productionCost
|
progress := game.F(productionAvailable / productionCost)
|
||||||
productionAvailable -= productionCost * progress
|
productionAvailable -= productionCost * progress.F()
|
||||||
p.Production.Progress = &progress
|
p.Production.Progress = &progress
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,14 +145,14 @@ func TestProduceShips(t *testing.T) {
|
|||||||
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 0)
|
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 0)
|
||||||
assert.NotNil(t, c.MustPlanet(R0_Planet_0_num).Production.Progress)
|
assert.NotNil(t, c.MustPlanet(R0_Planet_0_num).Production.Progress)
|
||||||
progress := *c.MustPlanet(R0_Planet_0_num).Production.Progress
|
progress := *c.MustPlanet(R0_Planet_0_num).Production.Progress
|
||||||
assert.InDelta(t, 0.45, progress, 0.001)
|
assert.InDelta(t, 0.45, progress.F(), 0.001)
|
||||||
|
|
||||||
assert.NoError(t, c.CreateShipType(Race_0_idx, "Drone", 1, 0, 0, 0, 0))
|
assert.NoError(t, c.CreateShipType(Race_0_idx, "Drone", 1, 0, 0, 0, 0))
|
||||||
assert.NoError(t, c.CreateShips(Race_0_idx, "Drone", uint(pn), 7))
|
assert.NoError(t, c.CreateShips(Race_0_idx, "Drone", uint(pn), 7))
|
||||||
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 1)
|
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 1)
|
||||||
assert.Equal(t, uint(7), c.ShipGroup(0).Number)
|
assert.Equal(t, uint(7), c.ShipGroup(0).Number)
|
||||||
assert.NoError(t, g.PlanetProduction(Race_0.Name, pn, "SHIP", "Drone"))
|
assert.NoError(t, g.PlanetProduction(Race_0.Name, pn, "SHIP", "Drone"))
|
||||||
assert.InDelta(t, shipMass*progress, c.MustPlanet(R0_Planet_0_num).Material.F(), 0.00001) // 99.(0099) material build
|
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).Material = 0
|
||||||
c.MustPlanet(R0_Planet_0_num).Colonists = 0
|
c.MustPlanet(R0_Planet_0_num).Colonists = 0
|
||||||
@@ -162,7 +162,7 @@ func TestProduceShips(t *testing.T) {
|
|||||||
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 1)
|
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 1)
|
||||||
assert.Equal(t, uint(106), c.ShipGroup(0).Number)
|
assert.Equal(t, uint(106), c.ShipGroup(0).Number)
|
||||||
progress = *c.MustPlanet(R0_Planet_0_num).Production.Progress
|
progress = *c.MustPlanet(R0_Planet_0_num).Production.Progress
|
||||||
assert.InDelta(t, 0.0099, progress, 0.00001) // 1.(0099) drones with no CAP on planet
|
assert.InDelta(t, 0.0099, progress.F(), 0.00001) // 1.(0099) drones with no CAP on planet
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProduceShip(t *testing.T) {
|
func TestProduceShip(t *testing.T) {
|
||||||
@@ -186,26 +186,26 @@ func TestProduceShip(t *testing.T) {
|
|||||||
|
|
||||||
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)
|
||||||
assert.InDelta(t, 0.0099, *p.Production.Progress, 0.000001)
|
assert.InDelta(t, 0.0099, (*p.Production.Progress).F(), 0.000001)
|
||||||
|
|
||||||
(&p).Production = game.ProductionShip.AsType(uuid.Nil)
|
(&p).Production = game.ProductionShip.AsType(uuid.Nil)
|
||||||
(&p).Capital = 10.
|
(&p).Capital = 10.
|
||||||
r = controller.ProduceShip(&p, p.ProductionCapacity(), Drone.EmptyMass())
|
r = controller.ProduceShip(&p, p.ProductionCapacity(), Drone.EmptyMass())
|
||||||
assert.Equal(t, uint(100), r)
|
assert.Equal(t, uint(100), r)
|
||||||
assert.Equal(t, 0., *p.Production.Progress)
|
assert.Equal(t, 0., (*p.Production.Progress).F())
|
||||||
assert.Equal(t, 0., number.Fixed3(p.Capital.F())) // TODO: zero CAP is not actual '0.0' after series of decrements
|
assert.Equal(t, 0., number.Fixed3(p.Capital.F())) // TODO: zero CAP is not actual '0.0' after series of decrements
|
||||||
|
|
||||||
(&p).Production = game.ProductionShip.AsType(uuid.Nil)
|
(&p).Production = game.ProductionShip.AsType(uuid.Nil)
|
||||||
(&p).Capital = 0.
|
(&p).Capital = 0.
|
||||||
r = controller.ProduceShip(&p, p.ProductionCapacity(), BattleShip.EmptyMass())
|
r = controller.ProduceShip(&p, p.ProductionCapacity(), BattleShip.EmptyMass())
|
||||||
assert.Equal(t, uint(1), r)
|
assert.Equal(t, uint(1), r)
|
||||||
assert.InDelta(t, 0.1, *p.Production.Progress, 0.001)
|
assert.InDelta(t, 0.1, (*p.Production.Progress).F(), 0.001)
|
||||||
|
|
||||||
(&p).Production = game.ProductionShip.AsType(uuid.Nil)
|
(&p).Production = game.ProductionShip.AsType(uuid.Nil)
|
||||||
(&p).Capital = 20.
|
(&p).Capital = 20.
|
||||||
r = controller.ProduceShip(&p, p.ProductionCapacity(), BattleShip.EmptyMass())
|
r = controller.ProduceShip(&p, p.ProductionCapacity(), BattleShip.EmptyMass())
|
||||||
assert.Equal(t, uint(1), r)
|
assert.Equal(t, uint(1), r)
|
||||||
assert.Equal(t, 1./9., *p.Production.Progress)
|
assert.Equal(t, 1./9., (*p.Production.Progress).F())
|
||||||
|
|
||||||
// TODO: test with insufficient production capacity
|
// TODO: test with insufficient production capacity
|
||||||
}
|
}
|
||||||
@@ -213,6 +213,10 @@ func TestProduceShip(t *testing.T) {
|
|||||||
func TestListProducingPlanets(t *testing.T) {
|
func TestListProducingPlanets(t *testing.T) {
|
||||||
c, g := newCache()
|
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())
|
planets := slices.Collect(c.ListProducingPlanets())
|
||||||
assert.Len(t, planets, 0)
|
assert.Len(t, planets, 0)
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ func (c *Cache) InitReport(t uint) *mr.Report {
|
|||||||
if vi := slices.IndexFunc(c.g.Race, func(v game.Race) bool { return r.VoteFor == v.ID }); vi < 0 {
|
if vi := slices.IndexFunc(c.g.Race, func(v game.Race) bool { return r.VoteFor == v.ID }); vi < 0 {
|
||||||
panic(fmt.Sprintf("voting for unknown race, id=%v", r.VoteFor))
|
panic(fmt.Sprintf("voting for unknown race, id=%v", r.VoteFor))
|
||||||
} else {
|
} else {
|
||||||
sumVote[vi] += r.Votes
|
sumVote[vi] += r.Votes.F()
|
||||||
dest := &report.Player[vi]
|
dest := &report.Player[vi]
|
||||||
dest.Votes = mr.F(sumVote[vi])
|
dest.Votes = mr.F(sumVote[vi])
|
||||||
}
|
}
|
||||||
@@ -110,7 +110,7 @@ func (c *Cache) ReportRace(ri int, rep *mr.Report, battles []*mr.BattleReport, b
|
|||||||
|
|
||||||
// votes based on population
|
// votes based on population
|
||||||
// TODO: check vote values was previously calculated
|
// TODO: check vote values was previously calculated
|
||||||
rep.Votes = mr.F(r.Votes)
|
rep.Votes = mr.F(r.Votes.F())
|
||||||
|
|
||||||
// relations
|
// relations
|
||||||
for i := range r.Relations {
|
for i := range r.Relations {
|
||||||
@@ -185,10 +185,10 @@ func (c *Cache) ReportLocalScience(ri int, rep *mr.Report) {
|
|||||||
for i := range r.Sciences {
|
for i := range r.Sciences {
|
||||||
sliceIndexValidate(&rep.LocalScience, i)
|
sliceIndexValidate(&rep.LocalScience, i)
|
||||||
rep.LocalScience[i].Name = r.Sciences[i].Name
|
rep.LocalScience[i].Name = r.Sciences[i].Name
|
||||||
rep.LocalScience[i].Drive = mr.F(r.Sciences[i].Drive)
|
rep.LocalScience[i].Drive = mr.F(r.Sciences[i].Drive.F())
|
||||||
rep.LocalScience[i].Weapons = mr.F(r.Sciences[i].Weapons)
|
rep.LocalScience[i].Weapons = mr.F(r.Sciences[i].Weapons.F())
|
||||||
rep.LocalScience[i].Shields = mr.F(r.Sciences[i].Shields)
|
rep.LocalScience[i].Shields = mr.F(r.Sciences[i].Shields.F())
|
||||||
rep.LocalScience[i].Cargo = mr.F(r.Sciences[i].Cargo)
|
rep.LocalScience[i].Cargo = mr.F(r.Sciences[i].Cargo.F())
|
||||||
}
|
}
|
||||||
|
|
||||||
slices.SortFunc(rep.LocalScience, func(a, b mr.Science) int { return cmp.Compare(a.Name, b.Name) })
|
slices.SortFunc(rep.LocalScience, func(a, b mr.Science) int { return cmp.Compare(a.Name, b.Name) })
|
||||||
@@ -215,10 +215,10 @@ func (c *Cache) ReportOtherScience(ri int, rep *mr.Report) {
|
|||||||
|
|
||||||
sliceIndexValidate(&rep.OtherScience, i)
|
sliceIndexValidate(&rep.OtherScience, i)
|
||||||
rep.OtherScience[i].Name = owner.Name
|
rep.OtherScience[i].Name = owner.Name
|
||||||
rep.OtherScience[i].Drive = mr.F(sc.Drive)
|
rep.OtherScience[i].Drive = mr.F(sc.Drive.F())
|
||||||
rep.OtherScience[i].Weapons = mr.F(sc.Weapons)
|
rep.OtherScience[i].Weapons = mr.F(sc.Weapons.F())
|
||||||
rep.OtherScience[i].Shields = mr.F(sc.Shields)
|
rep.OtherScience[i].Shields = mr.F(sc.Shields.F())
|
||||||
rep.OtherScience[i].Cargo = mr.F(sc.Cargo)
|
rep.OtherScience[i].Cargo = mr.F(sc.Cargo.F())
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,11 +236,11 @@ func (c *Cache) ReportLocalShipClass(ri int, report *mr.Report) {
|
|||||||
for st := range c.ListShipTypes(ri) {
|
for st := range c.ListShipTypes(ri) {
|
||||||
sliceIndexValidate(&report.LocalShipClass, i)
|
sliceIndexValidate(&report.LocalShipClass, i)
|
||||||
report.LocalShipClass[i].Name = st.Name
|
report.LocalShipClass[i].Name = st.Name
|
||||||
report.LocalShipClass[i].Drive = mr.F(st.Drive)
|
report.LocalShipClass[i].Drive = mr.F(st.Drive.F())
|
||||||
report.LocalShipClass[i].Armament = st.Armament
|
report.LocalShipClass[i].Armament = st.Armament
|
||||||
report.LocalShipClass[i].Weapons = mr.F(st.Weapons)
|
report.LocalShipClass[i].Weapons = mr.F(st.Weapons.F())
|
||||||
report.LocalShipClass[i].Shields = mr.F(st.Shields)
|
report.LocalShipClass[i].Shields = mr.F(st.Shields.F())
|
||||||
report.LocalShipClass[i].Cargo = mr.F(st.Cargo)
|
report.LocalShipClass[i].Cargo = mr.F(st.Cargo.F())
|
||||||
report.LocalShipClass[i].Mass = mr.F(st.EmptyMass())
|
report.LocalShipClass[i].Mass = mr.F(st.EmptyMass())
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
@@ -308,11 +308,11 @@ func (c *Cache) ReportOtherShipClass(ri int, rep *mr.Report) {
|
|||||||
sliceIndexValidate(&rep.OtherShipClass, i)
|
sliceIndexValidate(&rep.OtherShipClass, i)
|
||||||
rep.OtherShipClass[i].Race = c.g.Race[c.RaceIndex(sg.OwnerID)].Name
|
rep.OtherShipClass[i].Race = c.g.Race[c.RaceIndex(sg.OwnerID)].Name
|
||||||
rep.OtherShipClass[i].Name = st.Name
|
rep.OtherShipClass[i].Name = st.Name
|
||||||
rep.OtherShipClass[i].Drive = mr.F(st.Drive)
|
rep.OtherShipClass[i].Drive = mr.F(st.Drive.F())
|
||||||
rep.OtherShipClass[i].Armament = st.Armament
|
rep.OtherShipClass[i].Armament = st.Armament
|
||||||
rep.OtherShipClass[i].Weapons = mr.F(st.Weapons)
|
rep.OtherShipClass[i].Weapons = mr.F(st.Weapons.F())
|
||||||
rep.OtherShipClass[i].Shields = mr.F(st.Shields)
|
rep.OtherShipClass[i].Shields = mr.F(st.Shields.F())
|
||||||
rep.OtherShipClass[i].Cargo = mr.F(st.Cargo)
|
rep.OtherShipClass[i].Cargo = mr.F(st.Cargo.F())
|
||||||
rep.OtherShipClass[i].Mass = mr.F(st.EmptyMass())
|
rep.OtherShipClass[i].Mass = mr.F(st.EmptyMass())
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
@@ -543,7 +543,7 @@ func (c *Cache) ReportShipProduction(ri int, rep *mr.Report) {
|
|||||||
rep.ShipProduction[pi].Free = mr.F(free)
|
rep.ShipProduction[pi].Free = mr.F(free)
|
||||||
|
|
||||||
// FIXME: take logic from [ProduceShip] and test at [controller_test.TestProduceShip]
|
// FIXME: take logic from [ProduceShip] and test at [controller_test.TestProduceShip]
|
||||||
rep.ShipProduction[pi].Wasted = mr.F(free * *p.Production.Progress)
|
rep.ShipProduction[pi].Wasted = mr.F(free * (*p.Production.Progress).F())
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -717,7 +717,7 @@ func (c *Cache) otherGroup(v *mr.OtherGroup, sg *game.ShipGroup, st *game.ShipTy
|
|||||||
v.Class = st.Name
|
v.Class = st.Name
|
||||||
// rep.LocalGroup[i].Tech = make(map[string]mr.Float)
|
// rep.LocalGroup[i].Tech = make(map[string]mr.Float)
|
||||||
for t, val := range sg.Tech {
|
for t, val := range sg.Tech {
|
||||||
v.Tech[t.String()] = mr.F(val)
|
v.Tech[t.String()] = mr.F(val.F())
|
||||||
}
|
}
|
||||||
v.Cargo = sg.CargoString()
|
v.Cargo = sg.CargoString()
|
||||||
v.Load = mr.F(sg.Load.F())
|
v.Load = mr.F(sg.Load.F())
|
||||||
|
|||||||
@@ -21,11 +21,11 @@ func TestReportLocalShipClass(t *testing.T) {
|
|||||||
assert.NotEmpty(t, r.LocalShipClass[i].Name)
|
assert.NotEmpty(t, r.LocalShipClass[i].Name)
|
||||||
switch n := r.LocalShipClass[i].Name; n {
|
switch n := r.LocalShipClass[i].Name; n {
|
||||||
case Cruiser.Name:
|
case Cruiser.Name:
|
||||||
assert.Equal(t, report.F(Cruiser.Drive), r.LocalShipClass[i].Drive)
|
assert.Equal(t, report.F(Cruiser.Drive.F()), r.LocalShipClass[i].Drive)
|
||||||
assert.Equal(t, Cruiser.Armament, r.LocalShipClass[i].Armament)
|
assert.Equal(t, Cruiser.Armament, r.LocalShipClass[i].Armament)
|
||||||
assert.Equal(t, report.F(Cruiser.Weapons), r.LocalShipClass[i].Weapons)
|
assert.Equal(t, report.F(Cruiser.Weapons.F()), r.LocalShipClass[i].Weapons)
|
||||||
assert.Equal(t, report.F(Cruiser.Shields), r.LocalShipClass[i].Shields)
|
assert.Equal(t, report.F(Cruiser.Shields.F()), r.LocalShipClass[i].Shields)
|
||||||
assert.Equal(t, report.F(Cruiser.Cargo), r.LocalShipClass[i].Cargo)
|
assert.Equal(t, report.F(Cruiser.Cargo.F()), r.LocalShipClass[i].Cargo)
|
||||||
case Race_0_Gunship:
|
case Race_0_Gunship:
|
||||||
assert.Equal(t, report.F(60.), r.LocalShipClass[i].Drive)
|
assert.Equal(t, report.F(60.), r.LocalShipClass[i].Drive)
|
||||||
assert.Equal(t, uint(3), r.LocalShipClass[i].Armament)
|
assert.Equal(t, uint(3), r.LocalShipClass[i].Armament)
|
||||||
|
|||||||
@@ -46,10 +46,10 @@ func (c *Cache) CreateScience(ri int, name string, drive, weapons, shileds, carg
|
|||||||
c.g.Race[ri].Sciences = append(c.g.Race[ri].Sciences, game.Science{
|
c.g.Race[ri].Sciences = append(c.g.Race[ri].Sciences, game.Science{
|
||||||
ID: uuid.New(),
|
ID: uuid.New(),
|
||||||
Name: n,
|
Name: n,
|
||||||
Drive: drive,
|
Drive: game.Float(drive),
|
||||||
Weapons: weapons,
|
Weapons: game.Float(weapons),
|
||||||
Shields: shileds,
|
Shields: game.Float(shileds),
|
||||||
Cargo: cargo,
|
Cargo: game.Float(cargo),
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ func TestCreateScience(t *testing.T) {
|
|||||||
sc := c.RaceScience(Race_0_idx)[0]
|
sc := c.RaceScience(Race_0_idx)[0]
|
||||||
assert.NoError(t, uuid.Validate(sc.ID.String()))
|
assert.NoError(t, uuid.Validate(sc.ID.String()))
|
||||||
assert.Equal(t, first, sc.Name)
|
assert.Equal(t, first, sc.Name)
|
||||||
assert.Equal(t, 0.4, sc.Drive)
|
assert.Equal(t, 0.4, sc.Drive.F())
|
||||||
assert.Equal(t, 0., sc.Weapons)
|
assert.Equal(t, 0., sc.Weapons.F())
|
||||||
assert.Equal(t, 0.6, sc.Shields)
|
assert.Equal(t, 0.6, sc.Shields.F())
|
||||||
assert.Equal(t, 0., sc.Cargo)
|
assert.Equal(t, 0., sc.Cargo.F())
|
||||||
|
|
||||||
assert.ErrorContains(t,
|
assert.ErrorContains(t,
|
||||||
g.CreateScience("UnknownRace", second, 0.4, 0, 0.6, 0),
|
g.CreateScience("UnknownRace", second, 0.4, 0, 0.6, 0),
|
||||||
@@ -66,10 +66,10 @@ func TestCreateScience(t *testing.T) {
|
|||||||
sc = c.RaceScience(Race_0_idx)[1]
|
sc = c.RaceScience(Race_0_idx)[1]
|
||||||
assert.NoError(t, uuid.Validate(sc.ID.String()))
|
assert.NoError(t, uuid.Validate(sc.ID.String()))
|
||||||
assert.Equal(t, second, sc.Name)
|
assert.Equal(t, second, sc.Name)
|
||||||
assert.Equal(t, 0.25, sc.Drive)
|
assert.Equal(t, 0.25, sc.Drive.F())
|
||||||
assert.Equal(t, 0.25, sc.Weapons)
|
assert.Equal(t, 0.25, sc.Weapons.F())
|
||||||
assert.Equal(t, 0.25, sc.Shields)
|
assert.Equal(t, 0.25, sc.Shields.F())
|
||||||
assert.Equal(t, 0.25, sc.Cargo)
|
assert.Equal(t, 0.25, sc.Cargo.F())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeleteScience(t *testing.T) {
|
func TestDeleteScience(t *testing.T) {
|
||||||
|
|||||||
@@ -33,11 +33,11 @@ func (c *Cache) CreateShipType(ri int, typeName string, drive float64, ammo int,
|
|||||||
c.g.Race[ri].ShipTypes = append(c.g.Race[ri].ShipTypes, game.ShipType{
|
c.g.Race[ri].ShipTypes = append(c.g.Race[ri].ShipTypes, game.ShipType{
|
||||||
ID: uuid.New(),
|
ID: uuid.New(),
|
||||||
Name: n,
|
Name: n,
|
||||||
Drive: drive,
|
Drive: game.Float(drive),
|
||||||
Armament: uint(ammo),
|
Armament: uint(ammo),
|
||||||
Weapons: weapons,
|
Weapons: game.Float(weapons),
|
||||||
Shields: shileds,
|
Shields: game.Float(shileds),
|
||||||
Cargo: cargo,
|
Cargo: game.Float(cargo),
|
||||||
})
|
})
|
||||||
c.invalidateShipGroupCache()
|
c.invalidateShipGroupCache()
|
||||||
c.invalidateFleetCache()
|
c.invalidateFleetCache()
|
||||||
|
|||||||
@@ -36,11 +36,11 @@ func (c *Cache) createShipsUnsafe(ri int, classID uuid.UUID, planet uint, quanti
|
|||||||
TypeID: classID,
|
TypeID: classID,
|
||||||
Destination: planet,
|
Destination: planet,
|
||||||
Number: uint(quantity),
|
Number: uint(quantity),
|
||||||
Tech: map[game.Tech]float64{
|
Tech: map[game.Tech]game.Float{
|
||||||
game.TechDrive: c.g.Race[ri].TechLevel(game.TechDrive),
|
game.TechDrive: game.F(c.g.Race[ri].TechLevel(game.TechDrive)),
|
||||||
game.TechWeapons: c.g.Race[ri].TechLevel(game.TechWeapons),
|
game.TechWeapons: game.F(c.g.Race[ri].TechLevel(game.TechWeapons)),
|
||||||
game.TechShields: c.g.Race[ri].TechLevel(game.TechShields),
|
game.TechShields: game.F(c.g.Race[ri].TechLevel(game.TechShields)),
|
||||||
game.TechCargo: c.g.Race[ri].TechLevel(game.TechCargo),
|
game.TechCargo: game.F(c.g.Race[ri].TechLevel(game.TechCargo)),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -459,11 +459,11 @@ func (c *Cache) GiveawayGroup(ri, riAccept int, groupIndex, quantity uint) (err
|
|||||||
if stAcc < 0 {
|
if stAcc < 0 {
|
||||||
err = c.CreateShipType(riAccept,
|
err = c.CreateShipType(riAccept,
|
||||||
st.Name,
|
st.Name,
|
||||||
st.Drive,
|
st.Drive.F(),
|
||||||
int(st.Armament),
|
int(st.Armament),
|
||||||
st.Weapons,
|
st.Weapons.F(),
|
||||||
st.Shields,
|
st.Shields.F(),
|
||||||
st.Cargo)
|
st.Cargo.F())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,8 +51,8 @@ func TestSendGroup(t *testing.T) {
|
|||||||
assert.Equal(t, uint(3), c.ShipGroup(3).Number)
|
assert.Equal(t, uint(3), c.ShipGroup(3).Number)
|
||||||
assert.Equal(t, game.StateLaunched, c.ShipGroup(3).State())
|
assert.Equal(t, game.StateLaunched, c.ShipGroup(3).State())
|
||||||
assert.NotNil(t, c.ShipGroup(3).StateInSpace)
|
assert.NotNil(t, c.ShipGroup(3).StateInSpace)
|
||||||
assert.Equal(t, c.MustPlanet(R0_Planet_0_num).X.F(), c.ShipGroup(3).StateInSpace.X)
|
assert.Equal(t, c.MustPlanet(R0_Planet_0_num).X, c.ShipGroup(3).StateInSpace.X)
|
||||||
assert.Equal(t, c.MustPlanet(R0_Planet_0_num).Y.F(), c.ShipGroup(3).StateInSpace.Y)
|
assert.Equal(t, c.MustPlanet(R0_Planet_0_num).Y, c.ShipGroup(3).StateInSpace.Y)
|
||||||
|
|
||||||
assert.NoError(t, g.SendGroup(Race_0.Name, 4, R0_Planet_0_num, 2)) // un-send 2 of 3
|
assert.NoError(t, g.SendGroup(Race_0.Name, 4, R0_Planet_0_num, 2)) // un-send 2 of 3
|
||||||
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 4)
|
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 4)
|
||||||
@@ -61,8 +61,8 @@ func TestSendGroup(t *testing.T) {
|
|||||||
assert.Equal(t, uint(1), c.MustShipGroup(Race_0_idx, 4).Number)
|
assert.Equal(t, uint(1), c.MustShipGroup(Race_0_idx, 4).Number)
|
||||||
assert.Equal(t, game.StateLaunched, c.MustShipGroup(Race_0_idx, 4).State())
|
assert.Equal(t, game.StateLaunched, c.MustShipGroup(Race_0_idx, 4).State())
|
||||||
assert.NotNil(t, c.MustShipGroup(Race_0_idx, 4).StateInSpace)
|
assert.NotNil(t, c.MustShipGroup(Race_0_idx, 4).StateInSpace)
|
||||||
assert.Equal(t, c.MustPlanet(R0_Planet_0_num).X.F(), c.MustShipGroup(Race_0_idx, 4).StateInSpace.X)
|
assert.Equal(t, c.MustPlanet(R0_Planet_0_num).X, c.MustShipGroup(Race_0_idx, 4).StateInSpace.X)
|
||||||
assert.Equal(t, c.MustPlanet(R0_Planet_0_num).Y.F(), c.MustShipGroup(Race_0_idx, 4).StateInSpace.Y)
|
assert.Equal(t, c.MustPlanet(R0_Planet_0_num).Y, c.MustShipGroup(Race_0_idx, 4).StateInSpace.Y)
|
||||||
|
|
||||||
assert.NoError(t, g.SendGroup(Race_0.Name, 4, R0_Planet_0_num, 0)) // un-send the rest 1
|
assert.NoError(t, g.SendGroup(Race_0.Name, 4, R0_Planet_0_num, 0)) // un-send the rest 1
|
||||||
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 3)
|
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 3)
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ func TestJoinEqualGroups(t *testing.T) {
|
|||||||
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 7)
|
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 7)
|
||||||
|
|
||||||
c.RaceTechLevel(Race_1_idx, game.TechShields, 2.0)
|
c.RaceTechLevel(Race_1_idx, game.TechShields, 2.0)
|
||||||
assert.Equal(t, 2.0, c.Race(Race_1_idx).Tech[game.TechShields])
|
assert.Equal(t, 2.0, c.Race(Race_1_idx).Tech[game.TechShields].F())
|
||||||
assert.NoError(t, c.CreateShips(1, Race_1_Freighter, R1_Planet_1_num, 1))
|
assert.NoError(t, c.CreateShips(1, Race_1_Freighter, R1_Planet_1_num, 1))
|
||||||
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_1_idx)), 3)
|
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_1_idx)), 3)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package controller
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
|
"slices"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"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"
|
||||||
@@ -66,19 +69,15 @@ func (c *Cache) UpgradeGroup(ri int, groupIndex uint, techInput string, limitShi
|
|||||||
if c.g.Race[ri].TechLevel(tech) < limitLevel {
|
if c.g.Race[ri].TechLevel(tech) < limitLevel {
|
||||||
return e.NewUpgradeTechLevelInsufficientError("%s=%.03f < %.03f", tech.String(), c.g.Race[ri].TechLevel(tech), limitLevel)
|
return e.NewUpgradeTechLevelInsufficientError("%s=%.03f < %.03f", tech.String(), c.g.Race[ri].TechLevel(tech), limitLevel)
|
||||||
}
|
}
|
||||||
targetLevel[tech] = game.FutureUpgradeLevel(c.g.Race[ri].TechLevel(tech), sg.TechLevel(tech).F(), limitLevel)
|
targetLevel[tech] = FutureUpgradeLevel(c.g.Race[ri].TechLevel(tech), sg.TechLevel(tech).F(), limitLevel)
|
||||||
} else {
|
} else {
|
||||||
targetLevel[tech] = game.CurrentUpgradingLevel(sg, tech)
|
targetLevel[tech] = CurrentUpgradingLevel(sg, tech)
|
||||||
}
|
}
|
||||||
sumLevels += targetLevel[tech]
|
sumLevels += targetLevel[tech]
|
||||||
}
|
}
|
||||||
|
|
||||||
productionCapacity := c.PlanetProductionCapacity(p.Number)
|
productionCapacity := c.PlanetProductionCapacity(p.Number)
|
||||||
// if sg.State() == game.StateUpgrade {
|
uc := GroupUpgradeCost(sg, *st, targetLevel[game.TechDrive], targetLevel[game.TechWeapons], targetLevel[game.TechShields], targetLevel[game.TechCargo])
|
||||||
// // to calculate actual capacity we must "compensate" upgrade cost of selected group, if it is in upgrade state
|
|
||||||
// productionCapacity += sg.StateUpgrade.Cost()
|
|
||||||
// }
|
|
||||||
uc := game.GroupUpgradeCost(sg, *st, targetLevel[game.TechDrive], targetLevel[game.TechWeapons], targetLevel[game.TechShields], targetLevel[game.TechCargo])
|
|
||||||
costForShip := uc.UpgradeCost(1)
|
costForShip := uc.UpgradeCost(1)
|
||||||
if costForShip == 0 {
|
if costForShip == 0 {
|
||||||
return e.NewUpgradeShipsAlreadyUpToDateError("%#v", targetLevel)
|
return e.NewUpgradeShipsAlreadyUpToDateError("%#v", targetLevel)
|
||||||
@@ -118,7 +117,7 @@ func (c *Cache) UpgradeGroup(ri int, groupIndex uint, techInput string, limitShi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// sanity check
|
// sanity check
|
||||||
uc = game.GroupUpgradeCost(sg, *st, targetLevel[game.TechDrive], targetLevel[game.TechWeapons], targetLevel[game.TechShields], targetLevel[game.TechCargo])
|
uc = GroupUpgradeCost(sg, *st, targetLevel[game.TechDrive], targetLevel[game.TechWeapons], targetLevel[game.TechShields], targetLevel[game.TechCargo])
|
||||||
costForGroup := uc.UpgradeCost(maxUpgradableShips)
|
costForGroup := uc.UpgradeCost(maxUpgradableShips)
|
||||||
if costForGroup > productionCapacity {
|
if costForGroup > productionCapacity {
|
||||||
e.NewGameStateError("cost recalculation: coef=%f cost(%d)=%f L=%f", coef, maxUpgradableShips, costForGroup, productionCapacity)
|
e.NewGameStateError("cost recalculation: coef=%f cost(%d)=%f L=%f", coef, maxUpgradableShips, costForGroup, productionCapacity)
|
||||||
@@ -126,9 +125,6 @@ func (c *Cache) UpgradeGroup(ri int, groupIndex uint, techInput string, limitShi
|
|||||||
|
|
||||||
// break group if needed
|
// break group if needed
|
||||||
if maxUpgradableShips < sg.Number {
|
if maxUpgradableShips < sg.Number {
|
||||||
if sg.State() == game.StateUpgrade {
|
|
||||||
return e.NewUpgradeGroupBreakNotAllowedError("ships=%d max=%d", sg.Number, maxUpgradableShips)
|
|
||||||
}
|
|
||||||
nsgi, err := c.breakGroupSafe(ri, groupIndex, maxUpgradableShips)
|
nsgi, err := c.breakGroupSafe(ri, groupIndex, maxUpgradableShips)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -149,5 +145,91 @@ func (c *Cache) UpgradeGroup(ri int, groupIndex uint, techInput string, limitShi
|
|||||||
func (c *Cache) UpgradeShipGroup(sgi int, tech game.Tech, v float64) {
|
func (c *Cache) UpgradeShipGroup(sgi int, tech game.Tech, v float64) {
|
||||||
sg := *(c.ShipGroup(sgi))
|
sg := *(c.ShipGroup(sgi))
|
||||||
st := c.ShipGroupShipClass(sgi)
|
st := c.ShipGroupShipClass(sgi)
|
||||||
c.g.ShipGroups[sgi] = game.UpgradeGroupPreference(sg, *st, tech, v)
|
c.g.ShipGroups[sgi] = UpgradeGroupPreference(sg, *st, tech, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// helpers
|
||||||
|
|
||||||
|
type UpgradeCalc struct {
|
||||||
|
Cost map[game.Tech]float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (uc UpgradeCalc) UpgradeCost(ships uint) float64 {
|
||||||
|
var sum float64
|
||||||
|
for _, v := range uc.Cost {
|
||||||
|
sum += v
|
||||||
|
}
|
||||||
|
return sum * float64(ships)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (uc UpgradeCalc) UpgradeMaxShips(resources float64) uint {
|
||||||
|
return uint(math.Floor(resources / uc.UpgradeCost(1)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func BlockUpgradeCost(blockMass, currentBlockTech, targetBlockTech float64) float64 {
|
||||||
|
if blockMass == 0 || targetBlockTech <= currentBlockTech {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return (1 - currentBlockTech/targetBlockTech) * 10 * blockMass
|
||||||
|
}
|
||||||
|
|
||||||
|
func GroupUpgradeCost(sg *game.ShipGroup, st game.ShipType, drive, weapons, shields, cargo float64) UpgradeCalc {
|
||||||
|
uc := &UpgradeCalc{Cost: make(map[game.Tech]float64)}
|
||||||
|
if drive > 0 {
|
||||||
|
uc.Cost[game.TechDrive] = BlockUpgradeCost(st.DriveBlockMass(), sg.TechLevel(game.TechDrive).F(), drive)
|
||||||
|
}
|
||||||
|
if weapons > 0 {
|
||||||
|
uc.Cost[game.TechWeapons] = BlockUpgradeCost(st.WeaponsBlockMass(), sg.TechLevel(game.TechWeapons).F(), weapons)
|
||||||
|
}
|
||||||
|
if shields > 0 {
|
||||||
|
uc.Cost[game.TechShields] = BlockUpgradeCost(st.ShieldsBlockMass(), sg.TechLevel(game.TechShields).F(), shields)
|
||||||
|
}
|
||||||
|
if cargo > 0 {
|
||||||
|
uc.Cost[game.TechCargo] = BlockUpgradeCost(st.CargoBlockMass(), sg.TechLevel(game.TechCargo).F(), cargo)
|
||||||
|
}
|
||||||
|
return *uc
|
||||||
|
}
|
||||||
|
|
||||||
|
func CurrentUpgradingLevel(sg *game.ShipGroup, tech game.Tech) float64 {
|
||||||
|
if sg.StateUpgrade == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
ti := slices.IndexFunc(sg.StateUpgrade.UpgradeTech, func(pref game.UpgradePreference) bool { return pref.Tech == tech })
|
||||||
|
if ti >= 0 {
|
||||||
|
return sg.StateUpgrade.UpgradeTech[ti].Level.F()
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func FutureUpgradeLevel(raceLevel, groupLevel, limit float64) float64 {
|
||||||
|
target := limit
|
||||||
|
if target == 0 || target > raceLevel {
|
||||||
|
target = raceLevel
|
||||||
|
}
|
||||||
|
if groupLevel == target {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return target
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpgradeGroupPreference(sg game.ShipGroup, st game.ShipType, tech game.Tech, v float64) game.ShipGroup {
|
||||||
|
if v <= 0 || st.BlockMass(tech) == 0 || sg.TechLevel(tech).F() >= v {
|
||||||
|
return sg
|
||||||
|
}
|
||||||
|
var su game.InUpgrade
|
||||||
|
if sg.StateUpgrade != nil {
|
||||||
|
su = *sg.StateUpgrade
|
||||||
|
} else {
|
||||||
|
su = game.InUpgrade{UpgradeTech: []game.UpgradePreference{}}
|
||||||
|
}
|
||||||
|
ti := slices.IndexFunc(su.UpgradeTech, func(pref game.UpgradePreference) bool { return pref.Tech == tech })
|
||||||
|
if ti < 0 {
|
||||||
|
su.UpgradeTech = append(su.UpgradeTech, game.UpgradePreference{Tech: tech})
|
||||||
|
ti = len(su.UpgradeTech) - 1
|
||||||
|
}
|
||||||
|
su.UpgradeTech[ti].Level = game.F(v)
|
||||||
|
su.UpgradeTech[ti].Cost = game.F(BlockUpgradeCost(st.BlockMass(tech), sg.TechLevel(tech).F(), v) * float64(sg.Number))
|
||||||
|
|
||||||
|
sg.StateUpgrade = &su
|
||||||
|
return sg
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,126 @@ import (
|
|||||||
"slices"
|
"slices"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/iliadenisov/galaxy/internal/controller"
|
||||||
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"
|
||||||
|
g "github.com/iliadenisov/galaxy/internal/model/game"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// var (
|
||||||
|
// Cruiser = game.ShipType{
|
||||||
|
// Name: "Cruiser",
|
||||||
|
// Drive: 15,
|
||||||
|
// Armament: 1,
|
||||||
|
// Weapons: 15,
|
||||||
|
// Shields: 15,
|
||||||
|
// Cargo: 0,
|
||||||
|
// }
|
||||||
|
// )
|
||||||
|
|
||||||
|
func TestBlockUpgradeCost(t *testing.T) {
|
||||||
|
assert.Equal(t, 00.0, controller.BlockUpgradeCost(1, 1.0, 1.0))
|
||||||
|
assert.Equal(t, 25.0, controller.BlockUpgradeCost(5, 1.0, 2.0))
|
||||||
|
assert.Equal(t, 50.0, controller.BlockUpgradeCost(10, 1.0, 2.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGroupUpgradeCost(t *testing.T) {
|
||||||
|
sg := &g.ShipGroup{
|
||||||
|
Tech: map[g.Tech]g.Float{
|
||||||
|
g.TechDrive: 1.0,
|
||||||
|
g.TechWeapons: 1.0,
|
||||||
|
g.TechShields: 1.0,
|
||||||
|
g.TechCargo: 1.0,
|
||||||
|
},
|
||||||
|
Number: 1,
|
||||||
|
}
|
||||||
|
assert.Equal(t, 225.0, controller.GroupUpgradeCost(sg, Cruiser, 2.0, 2.0, 2.0, 2.0).UpgradeCost(1))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpgradeMaxShips(t *testing.T) {
|
||||||
|
sg := &g.ShipGroup{
|
||||||
|
Tech: map[g.Tech]g.Float{
|
||||||
|
g.TechDrive: 1.0,
|
||||||
|
g.TechWeapons: 1.0,
|
||||||
|
g.TechShields: 1.0,
|
||||||
|
g.TechCargo: 1.0,
|
||||||
|
},
|
||||||
|
Number: 10,
|
||||||
|
}
|
||||||
|
uc := controller.GroupUpgradeCost(sg, Cruiser, 2.0, 2.0, 2.0, 2.0)
|
||||||
|
assert.Equal(t, uint(4), uc.UpgradeMaxShips(1000))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCurrentUpgradingLevel(t *testing.T) {
|
||||||
|
sg := &g.ShipGroup{
|
||||||
|
StateUpgrade: nil,
|
||||||
|
}
|
||||||
|
assert.Equal(t, 0.0, controller.CurrentUpgradingLevel(sg, g.TechDrive))
|
||||||
|
assert.Equal(t, 0.0, controller.CurrentUpgradingLevel(sg, g.TechWeapons))
|
||||||
|
assert.Equal(t, 0.0, controller.CurrentUpgradingLevel(sg, g.TechShields))
|
||||||
|
assert.Equal(t, 0.0, controller.CurrentUpgradingLevel(sg, g.TechCargo))
|
||||||
|
|
||||||
|
sg.StateUpgrade = &g.InUpgrade{
|
||||||
|
UpgradeTech: []g.UpgradePreference{
|
||||||
|
{Tech: g.TechDrive, Level: 1.5, Cost: 100.1},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.Equal(t, 1.5, controller.CurrentUpgradingLevel(sg, g.TechDrive))
|
||||||
|
assert.Equal(t, 0.0, controller.CurrentUpgradingLevel(sg, g.TechWeapons))
|
||||||
|
assert.Equal(t, 0.0, controller.CurrentUpgradingLevel(sg, g.TechShields))
|
||||||
|
assert.Equal(t, 0.0, controller.CurrentUpgradingLevel(sg, g.TechCargo))
|
||||||
|
|
||||||
|
sg.StateUpgrade.UpgradeTech = append(sg.StateUpgrade.UpgradeTech, g.UpgradePreference{Tech: g.TechCargo, Level: 2.2, Cost: 200.2})
|
||||||
|
assert.Equal(t, 1.5, controller.CurrentUpgradingLevel(sg, g.TechDrive))
|
||||||
|
assert.Equal(t, 0.0, controller.CurrentUpgradingLevel(sg, g.TechWeapons))
|
||||||
|
assert.Equal(t, 0.0, controller.CurrentUpgradingLevel(sg, g.TechShields))
|
||||||
|
assert.Equal(t, 2.2, controller.CurrentUpgradingLevel(sg, g.TechCargo))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFutureUpgradeLevel(t *testing.T) {
|
||||||
|
assert.Equal(t, 0.0, controller.FutureUpgradeLevel(2.0, 2.0, 2.0))
|
||||||
|
assert.Equal(t, 0.0, controller.FutureUpgradeLevel(2.0, 2.0, 3.0))
|
||||||
|
assert.Equal(t, 1.5, controller.FutureUpgradeLevel(1.5, 2.0, 3.0))
|
||||||
|
assert.Equal(t, 2.0, controller.FutureUpgradeLevel(2.5, 1.0, 2.0))
|
||||||
|
assert.Equal(t, 2.5, controller.FutureUpgradeLevel(2.5, 1.0, 0.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpgradeGroupPreference(t *testing.T) {
|
||||||
|
sg := g.ShipGroup{
|
||||||
|
Number: 4,
|
||||||
|
Tech: g.TechSet{
|
||||||
|
g.TechDrive: 1.0,
|
||||||
|
g.TechWeapons: 1.0,
|
||||||
|
g.TechShields: 1.0,
|
||||||
|
g.TechCargo: 1.0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.Nil(t, sg.StateUpgrade)
|
||||||
|
sg = controller.UpgradeGroupPreference(sg, Cruiser, g.TechDrive, 0)
|
||||||
|
assert.Nil(t, sg.StateUpgrade)
|
||||||
|
|
||||||
|
sg = controller.UpgradeGroupPreference(sg, Cruiser, g.TechDrive, 2.0)
|
||||||
|
assert.NotNil(t, sg.StateUpgrade)
|
||||||
|
assert.Equal(t, 300., sg.StateUpgrade.TechCost(g.TechDrive))
|
||||||
|
assert.Equal(t, 300., sg.StateUpgrade.Cost())
|
||||||
|
|
||||||
|
sg = controller.UpgradeGroupPreference(sg, Cruiser, g.TechWeapons, 2.0)
|
||||||
|
assert.NotNil(t, sg.StateUpgrade)
|
||||||
|
assert.Equal(t, 300., sg.StateUpgrade.TechCost(g.TechWeapons))
|
||||||
|
assert.Equal(t, 600., sg.StateUpgrade.Cost())
|
||||||
|
|
||||||
|
sg = controller.UpgradeGroupPreference(sg, Cruiser, g.TechShields, 2.0)
|
||||||
|
assert.NotNil(t, sg.StateUpgrade)
|
||||||
|
assert.Equal(t, 300., sg.StateUpgrade.TechCost(g.TechShields))
|
||||||
|
assert.Equal(t, 900., sg.StateUpgrade.Cost())
|
||||||
|
|
||||||
|
sg = controller.UpgradeGroupPreference(sg, Cruiser, g.TechCargo, 2.0)
|
||||||
|
assert.NotNil(t, sg.StateUpgrade)
|
||||||
|
assert.Equal(t, 0., sg.StateUpgrade.TechCost(g.TechCargo))
|
||||||
|
assert.Equal(t, 900., sg.StateUpgrade.Cost())
|
||||||
|
}
|
||||||
|
|
||||||
func TestUpgradeGroup(t *testing.T) {
|
func TestUpgradeGroup(t *testing.T) {
|
||||||
c, g := newCache()
|
c, g := newCache()
|
||||||
// group #1 - in_orbit, free to upgrade
|
// group #1 - in_orbit, free to upgrade
|
||||||
@@ -63,5 +178,5 @@ func TestUpgradeGroup(t *testing.T) {
|
|||||||
|
|
||||||
assert.ErrorContains(t,
|
assert.ErrorContains(t,
|
||||||
g.UpgradeGroup(Race_0.Name, 4, "DRIVE", 1, 1.3),
|
g.UpgradeGroup(Race_0.Name, 4, "DRIVE", 1, 1.3),
|
||||||
e.GenericErrorText(e.ErrInputUpgradeGroupBreakNotAllowed))
|
e.GenericErrorText(e.ErrShipsBusy))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,11 +48,12 @@ func (c *Cache) TurnCalculateVotes() []int {
|
|||||||
|
|
||||||
c.g.Votes = 0
|
c.g.Votes = 0
|
||||||
for ri, votes := range raceVotes {
|
for ri, votes := range raceVotes {
|
||||||
c.g.Race[ri].Votes = votes
|
v := game.F(votes)
|
||||||
c.g.Votes += votes
|
c.g.Race[ri].Votes = v
|
||||||
|
c.g.Votes += v
|
||||||
}
|
}
|
||||||
|
|
||||||
return votingWinners(calc, c.g.Votes)
|
return votingWinners(calc, c.g.Votes.F())
|
||||||
}
|
}
|
||||||
|
|
||||||
func VotingGraph(races []game.Race, raceIndex func(uuid.UUID) int) []*VoteNode {
|
func VotingGraph(races []game.Race, raceIndex func(uuid.UUID) int) []*VoteNode {
|
||||||
|
|||||||
@@ -61,7 +61,6 @@ const (
|
|||||||
ErrInputUpgradeShipTechNotUsed
|
ErrInputUpgradeShipTechNotUsed
|
||||||
ErrInputUpgradeParameterNotAllowed
|
ErrInputUpgradeParameterNotAllowed
|
||||||
ErrInputUpgradeShipsAlreadyUpToDate
|
ErrInputUpgradeShipsAlreadyUpToDate
|
||||||
ErrInputUpgradeGroupBreakNotAllowed
|
|
||||||
ErrInputUpgradeTechLevelInsufficient
|
ErrInputUpgradeTechLevelInsufficient
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -161,8 +160,6 @@ func GenericErrorText(code int) string {
|
|||||||
return "Not enough ships in the group to make an upgrade"
|
return "Not enough ships in the group to make an upgrade"
|
||||||
case ErrUpgradeInsufficientResources:
|
case ErrUpgradeInsufficientResources:
|
||||||
return "Insufficient planet production capacity"
|
return "Insufficient planet production capacity"
|
||||||
case ErrInputUpgradeGroupBreakNotAllowed:
|
|
||||||
return "The Group is already in upgrade state and can't be divided to a smaller group"
|
|
||||||
case ErrInputUpgradeTechLevelInsufficient:
|
case ErrInputUpgradeTechLevelInsufficient:
|
||||||
return "Insifficient Tech level for requested upgrade"
|
return "Insifficient Tech level for requested upgrade"
|
||||||
case ErrSendShipHasNoDrives:
|
case ErrSendShipHasNoDrives:
|
||||||
|
|||||||
@@ -160,10 +160,6 @@ func NewUpgradeInsufficientResourcesError(arg ...any) error {
|
|||||||
return newGenericError(ErrUpgradeInsufficientResources, arg...)
|
return newGenericError(ErrUpgradeInsufficientResources, arg...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUpgradeGroupBreakNotAllowedError(arg ...any) error {
|
|
||||||
return newGenericError(ErrInputUpgradeGroupBreakNotAllowed, arg...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewUpgradeTechLevelInsufficientError(arg ...any) error {
|
func NewUpgradeTechLevelInsufficientError(arg ...any) error {
|
||||||
return newGenericError(ErrInputUpgradeTechLevelInsufficient, arg...)
|
return newGenericError(ErrInputUpgradeTechLevelInsufficient, arg...)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,10 +26,10 @@ func TestCreateShipType(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, st, 1)
|
assert.Len(t, st, 1)
|
||||||
assert.Equal(t, st[0].Name, typeName)
|
assert.Equal(t, st[0].Name, typeName)
|
||||||
assert.Equal(t, st[0].Drive, 1.)
|
assert.Equal(t, st[0].Drive.F(), 1.)
|
||||||
assert.Equal(t, st[0].Weapons, 0.)
|
assert.Equal(t, st[0].Weapons.F(), 0.)
|
||||||
assert.Equal(t, st[0].Shields, 0.)
|
assert.Equal(t, st[0].Shields.F(), 0.)
|
||||||
assert.Equal(t, st[0].Cargo, 0.)
|
assert.Equal(t, st[0].Cargo.F(), 0.)
|
||||||
assert.Equal(t, st[0].Armament, uint(0))
|
assert.Equal(t, st[0].Armament, uint(0))
|
||||||
// TODO: test with existing ship group
|
// TODO: test with existing ship group
|
||||||
err = game.DeleteShipType(p, unknownRaceName, typeName) // TODO: test on dead race
|
err = game.DeleteShipType(p, unknownRaceName, typeName) // TODO: test on dead race
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ func TestComposeGame(t *testing.T) {
|
|||||||
g(t, func(p func(*controller.Param), g func() *mg.Game) {
|
g(t, func(p func(*controller.Param), g func() *mg.Game) {
|
||||||
_, err := game.GenerateGame(p, []string{"r1", "r2"})
|
_, err := game.GenerateGame(p, []string{"r1", "r2"})
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.ErrorContains(t, err, "state for turn 0 already saved")
|
assert.ErrorContains(t, err, "turn 0 already saved at 0000/state.json")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,80 +0,0 @@
|
|||||||
package game
|
|
||||||
|
|
||||||
// import (
|
|
||||||
// "fmt"
|
|
||||||
// "slices"
|
|
||||||
|
|
||||||
// e "github.com/iliadenisov/galaxy/internal/error"
|
|
||||||
// "github.com/iliadenisov/galaxy/internal/util"
|
|
||||||
// )
|
|
||||||
|
|
||||||
// func (g *Game) SendFleet(raceName, fleetName string, planetNumber uint) error {
|
|
||||||
// ri, err := g.raceIndex(raceName)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// fi := g.fleetIndex(ri, fleetName)
|
|
||||||
// if fi < 0 {
|
|
||||||
// return e.NewEntityNotExistsError("fleet %q", fleetName)
|
|
||||||
// }
|
|
||||||
// return g.sendFleetInternal(ri, fi, planetNumber)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (g *Game) sendFleetInternal(ri, fi int, planetNumber uint) error {
|
|
||||||
// state, sourcePlanet, _ := FleetState(g, g.Fleets[fi].ID)
|
|
||||||
// if StateInOrbit != state && StateLaunched != state {
|
|
||||||
// return e.NewShipsBusyError()
|
|
||||||
// }
|
|
||||||
|
|
||||||
// p1, ok := PlanetByNum(g, *sourcePlanet)
|
|
||||||
// if !ok {
|
|
||||||
// return e.NewGameStateError("source planet #%d does not exists", sourcePlanet)
|
|
||||||
// }
|
|
||||||
// p2, ok := PlanetByNum(g, planetNumber)
|
|
||||||
// if !ok {
|
|
||||||
// return e.NewEntityNotExistsError("destination planet #%d", planetNumber)
|
|
||||||
// }
|
|
||||||
// rangeToDestination := util.ShortDistance(g.Map.Width, g.Map.Height, p1.X, p1.Y, p2.X, p2.Y)
|
|
||||||
// if rangeToDestination > g.Race[ri].FlightDistance() {
|
|
||||||
// return e.NewSendUnreachableDestinationError("range=%.03f", rangeToDestination)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// for sg := range FleetGroups(g, ri, fi) {
|
|
||||||
// st, ok := ShipClass(g, ri, sg.TypeID)
|
|
||||||
// if !ok {
|
|
||||||
// return e.NewGameStateError("not found: ShipType ID=%v", sg.TypeID)
|
|
||||||
// }
|
|
||||||
// if st.DriveBlockMass() == 0 {
|
|
||||||
// return e.NewSendShipHasNoDrivesError("Class=%s", st.Name)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if *sourcePlanet == planetNumber {
|
|
||||||
// UnsendFleet(g, ri, fi)
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
// LaunchFleet(g, ri, fi, planetNumber)
|
|
||||||
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func LaunchFleet(g *Game, ri, fi int, destination uint) {
|
|
||||||
// for sg := range FleetGroups(g, ri, fi) {
|
|
||||||
// sgi := slices.IndexFunc(g.ShipGroups, func(s ShipGroup) bool { return sg.Index == s.Index })
|
|
||||||
// if sgi < 0 {
|
|
||||||
// panic(fmt.Sprintf("LauncgFleet: cannot find ship group index=%d", sg.Index))
|
|
||||||
// }
|
|
||||||
// g.ShipGroups[sgi] = LaunchShips(sg, destination)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func UnsendFleet(g *Game, ri, fi int) {
|
|
||||||
// for sg := range FleetGroups(g, ri, fi) {
|
|
||||||
// sgi := slices.IndexFunc(g.ShipGroups, func(s ShipGroup) bool { return sg.Index == s.Index })
|
|
||||||
// if sgi < 0 {
|
|
||||||
// panic(fmt.Sprintf("UnsendFleet: cannot find ship group index=%d", sg.Index))
|
|
||||||
// }
|
|
||||||
// g.ShipGroups[sgi] = UnsendShips(sg)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
package game_test
|
|
||||||
|
|
||||||
// import (
|
|
||||||
// "slices"
|
|
||||||
// "testing"
|
|
||||||
|
|
||||||
// e "github.com/iliadenisov/galaxy/internal/error"
|
|
||||||
// "github.com/iliadenisov/galaxy/internal/model/game"
|
|
||||||
// "github.com/stretchr/testify/assert"
|
|
||||||
// )
|
|
||||||
|
|
||||||
// func TestSendFleet(t *testing.T) {
|
|
||||||
// g := newGame()
|
|
||||||
// // group #1 - in_orbit Planet_0
|
|
||||||
// assert.NoError(t, g.CreateShips(Race_0_idx, Race_0_Freighter, R0_Planet_0_num, 1))
|
|
||||||
// // group #2 - in_space (later)
|
|
||||||
// assert.NoError(t, g.CreateShips(Race_0_idx, Race_0_Gunship, R0_Planet_0_num, 3))
|
|
||||||
// // group #3 - in_orbit Planet_0, unmovable
|
|
||||||
// g.CreateShipType(Race_0.Name, "Fortress", 0, 50, 30, 100, 0)
|
|
||||||
// assert.NoError(t, g.CreateShips(Race_0_idx, "Fortress", R0_Planet_0_num, 1))
|
|
||||||
// // group #4 - in_orbit Planet_0
|
|
||||||
// assert.NoError(t, g.CreateShips(Race_0_idx, Race_0_Gunship, R0_Planet_0_num, 2))
|
|
||||||
|
|
||||||
// // ensure race has no Fleets
|
|
||||||
// assert.Len(t, slices.Collect(g.ListFleets(Race_0_idx)), 0)
|
|
||||||
|
|
||||||
// fleetSending := "R0_Fleet_one"
|
|
||||||
// fleetInSpace := "R0_Fleet_inSpace"
|
|
||||||
// fleetUnmovable := "R0_Fleet_unmovable"
|
|
||||||
|
|
||||||
// assert.NoError(t, g.JoinShipGroupToFleet(Race_0.Name, fleetSending, 1, 0))
|
|
||||||
// assert.NoError(t, g.JoinShipGroupToFleet(Race_0.Name, fleetSending, 3, 0))
|
|
||||||
|
|
||||||
// assert.NoError(t, g.JoinShipGroupToFleet(Race_0.Name, fleetInSpace, 2, 0))
|
|
||||||
// assert.NoError(t, g.JoinShipGroupToFleet(Race_0.Name, fleetUnmovable, 3, 0))
|
|
||||||
// // group #2 - in_space
|
|
||||||
// g.ShipGroups[1].StateInSpace = &game.InSpace{Origin: 2, Range: 1.23}
|
|
||||||
|
|
||||||
// assert.ErrorContains(t,
|
|
||||||
// g.SendFleet("UnknownRace", fleetSending, 2),
|
|
||||||
// e.GenericErrorText(e.ErrInputUnknownRace))
|
|
||||||
// assert.ErrorContains(t,
|
|
||||||
// g.SendFleet(Race_0.Name, "UnknownFleet", 2),
|
|
||||||
// e.GenericErrorText(e.ErrInputEntityNotExists))
|
|
||||||
// assert.ErrorContains(t,
|
|
||||||
// g.SendFleet(Race_0.Name, fleetInSpace, 2),
|
|
||||||
// e.GenericErrorText(e.ErrShipsBusy))
|
|
||||||
// assert.ErrorContains(t,
|
|
||||||
// g.SendFleet(Race_0.Name, fleetSending, 200),
|
|
||||||
// e.GenericErrorText(e.ErrInputEntityNotExists))
|
|
||||||
// assert.ErrorContains(t,
|
|
||||||
// g.SendFleet(Race_0.Name, fleetSending, 3),
|
|
||||||
// e.GenericErrorText(e.ErrSendUnreachableDestination))
|
|
||||||
// assert.ErrorContains(t,
|
|
||||||
// g.SendFleet(Race_0.Name, fleetUnmovable, 2),
|
|
||||||
// e.GenericErrorText(e.ErrSendShipHasNoDrives))
|
|
||||||
|
|
||||||
// assert.NoError(t, g.SendFleet(Race_0.Name, fleetSending, 2))
|
|
||||||
// fi := slices.IndexFunc(slices.Collect(g.ListFleets(Race_0_idx)), func(f game.Fleet) bool { return f.Name == fleetSending })
|
|
||||||
// state, _, _ := game.FleetState(g, g.Fleets[fi].ID)
|
|
||||||
// assert.Equal(t, game.StateLaunched, state)
|
|
||||||
// for sg := range game.FleetGroups(g, Race_0_idx, fi) {
|
|
||||||
// assert.Equal(t, game.StateLaunched, sg.State())
|
|
||||||
// }
|
|
||||||
|
|
||||||
// assert.NoError(t, g.SendFleet(Race_0.Name, fleetSending, 0))
|
|
||||||
// fi = slices.IndexFunc(slices.Collect(g.ListFleets(Race_0_idx)), func(f game.Fleet) bool { return f.Name == fleetSending })
|
|
||||||
// state, _, _ = game.FleetState(g, g.Fleets[fi].ID)
|
|
||||||
// assert.Equal(t, game.StateInOrbit, state)
|
|
||||||
// for sg := range game.FleetGroups(g, Race_0_idx, fi) {
|
|
||||||
// assert.Equal(t, game.StateInOrbit, sg.State())
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
package game_test
|
|
||||||
|
|
||||||
// import (
|
|
||||||
// "slices"
|
|
||||||
// "testing"
|
|
||||||
|
|
||||||
// e "github.com/iliadenisov/galaxy/internal/error"
|
|
||||||
// "github.com/iliadenisov/galaxy/internal/model/game"
|
|
||||||
// "github.com/stretchr/testify/assert"
|
|
||||||
// )
|
|
||||||
|
|
||||||
// func TestJoinShipGroupToFleet(t *testing.T) {
|
|
||||||
// g := newGame()
|
|
||||||
// var groupIndex uint = 1
|
|
||||||
|
|
||||||
// assert.ErrorContains(t,
|
|
||||||
// g.JoinShipGroupToFleet(Race_0.Name, " ", groupIndex, 0),
|
|
||||||
// e.GenericErrorText(e.ErrInputEntityTypeNameInvalid))
|
|
||||||
|
|
||||||
// assert.ErrorContains(t,
|
|
||||||
// g.JoinShipGroupToFleet(Race_0.Name, "Unnamed", groupIndex, 0),
|
|
||||||
// e.GenericErrorText(e.ErrInputEntityNotExists))
|
|
||||||
|
|
||||||
// // creating ShipGroup
|
|
||||||
// assert.NoError(t, g.CreateShips(Race_0_idx, Race_0_Freighter, R0_Planet_0_num, 5))
|
|
||||||
|
|
||||||
// assert.ErrorContains(t,
|
|
||||||
// g.JoinShipGroupToFleet(Race_0.Name, "Unnamed", groupIndex, 6),
|
|
||||||
// e.GenericErrorText(e.ErrJoinFleetGroupNumberNotEnough))
|
|
||||||
|
|
||||||
// // ensure race has no Fleets
|
|
||||||
// assert.Len(t, slices.Collect(g.ListFleets(Race_0_idx)), 0)
|
|
||||||
|
|
||||||
// fleetOne := "R0_Fleet_one"
|
|
||||||
// fleetTwo := "R0_Fleet_two"
|
|
||||||
|
|
||||||
// assert.NoError(t, g.JoinShipGroupToFleet(Race_0.Name, fleetOne, groupIndex, 0))
|
|
||||||
// fleets := slices.Collect(g.ListFleets(Race_0_idx))
|
|
||||||
// groups := slices.Collect(g.ListShipGroups(Race_0_idx))
|
|
||||||
// assert.Len(t, groups, 1)
|
|
||||||
// gi := 0
|
|
||||||
// assert.Len(t, fleets, 1)
|
|
||||||
// assert.Equal(t, fleets[0].Name, fleetOne)
|
|
||||||
// state, _, _ := game.FleetState(g, fleets[0].ID)
|
|
||||||
// assert.Equal(t, game.StateInOrbit, state)
|
|
||||||
|
|
||||||
// assert.NotNil(t, groups[gi].FleetID)
|
|
||||||
// assert.Equal(t, fleets[0].ID, *groups[gi].FleetID)
|
|
||||||
|
|
||||||
// // create another ShipGroup
|
|
||||||
// assert.NoError(t, g.CreateShips(Race_0_idx, Race_0_Gunship, R0_Planet_0_num, 3))
|
|
||||||
// groupIndex = 2
|
|
||||||
// assert.NoError(t, g.JoinShipGroupToFleet(Race_0.Name, fleetTwo, groupIndex, 2))
|
|
||||||
// fleets = slices.Collect(g.ListFleets(Race_0_idx))
|
|
||||||
// groups = slices.Collect(g.ListShipGroups(Race_0_idx))
|
|
||||||
// assert.Len(t, groups, 3)
|
|
||||||
// gi = 1
|
|
||||||
// assert.Len(t, fleets, 2)
|
|
||||||
// assert.Equal(t, fleets[1].Name, fleetTwo)
|
|
||||||
// state, _, _ = game.FleetState(g, fleets[1].ID)
|
|
||||||
// assert.Equal(t, game.StateInOrbit, state)
|
|
||||||
|
|
||||||
// assert.NotNil(t, groups[gi].FleetID)
|
|
||||||
// assert.Equal(t, fleets[1].ID, *groups[gi].FleetID)
|
|
||||||
// assert.Equal(t, uint(2), groups[gi].Number)
|
|
||||||
// assert.Equal(t, uint(2), groups[gi].Index)
|
|
||||||
|
|
||||||
// gi = 2
|
|
||||||
// assert.Nil(t, groups[gi].FleetID)
|
|
||||||
// assert.Equal(t, uint(1), groups[gi].Number)
|
|
||||||
// assert.Equal(t, uint(3), groups[gi].Index)
|
|
||||||
|
|
||||||
// groupIndex = groups[gi].Index
|
|
||||||
// assert.NoError(t, g.JoinShipGroupToFleet(Race_0.Name, fleetOne, groupIndex, 0))
|
|
||||||
// fleets = slices.Collect(g.ListFleets(Race_0_idx))
|
|
||||||
// assert.Len(t, fleets, 2)
|
|
||||||
// groups = slices.Collect(g.ListShipGroups(Race_0_idx))
|
|
||||||
// assert.NotNil(t, groups[gi].FleetID)
|
|
||||||
// assert.Equal(t, fleets[0].ID, *groups[gi].FleetID)
|
|
||||||
// state, _, _ = game.FleetState(g, fleets[0].ID)
|
|
||||||
// assert.Equal(t, game.StateInOrbit, state)
|
|
||||||
|
|
||||||
// // group not In_Orbit
|
|
||||||
// assert.NoError(t, g.CreateShips(Race_0_idx, Race_0_Gunship, R0_Planet_0_num, 7))
|
|
||||||
// gi = 3
|
|
||||||
// g.ShipGroups[gi].StateInSpace = &game.InSpace{
|
|
||||||
// Origin: 2,
|
|
||||||
// Range: 1,
|
|
||||||
// }
|
|
||||||
// assert.ErrorContains(t,
|
|
||||||
// g.JoinShipGroupToFleet(Race_0.Name, fleetOne, g.ShipGroups[gi].Index, 0),
|
|
||||||
// e.GenericErrorText(e.ErrShipsBusy))
|
|
||||||
// g.ShipGroups[gi].StateInSpace = nil
|
|
||||||
|
|
||||||
// // existing fleet not on the same planet or in_orbit
|
|
||||||
// g.ShipGroups[0].StateInSpace = &game.InSpace{
|
|
||||||
// Origin: 2,
|
|
||||||
// Range: 1,
|
|
||||||
// }
|
|
||||||
// g.ShipGroups[2].StateInSpace = g.ShipGroups[0].StateInSpace
|
|
||||||
// assert.ErrorContains(t,
|
|
||||||
// g.JoinShipGroupToFleet(Race_0.Name, fleetOne, g.ShipGroups[gi].Index, 0),
|
|
||||||
// e.GenericErrorText(e.ErrShipsNotOnSamePlanet))
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func TestJoinFleets(t *testing.T) {
|
|
||||||
// g := newGame()
|
|
||||||
// // creating ShipGroup #1 at Planet_0
|
|
||||||
// assert.NoError(t, g.CreateShips(Race_0_idx, Race_0_Freighter, R0_Planet_0_num, 1)) // group #1
|
|
||||||
// // creating ShipGroup #2 at Planet_2
|
|
||||||
// assert.NoError(t, g.CreateShips(Race_0_idx, Race_0_Gunship, R0_Planet_2_num, 2)) // group #2
|
|
||||||
// // creating ShipGroup #3 at Planet_0
|
|
||||||
// assert.NoError(t, g.CreateShips(Race_0_idx, Race_0_Gunship, R0_Planet_0_num, 3)) // group #3
|
|
||||||
|
|
||||||
// // ensure race has no Fleets
|
|
||||||
// assert.Len(t, slices.Collect(g.ListFleets(Race_0_idx)), 0)
|
|
||||||
|
|
||||||
// fleetPlanet2 := "R0_Fleet_On_Planet_2"
|
|
||||||
// fleetSource := "R0_Fleet_one"
|
|
||||||
// fleetTarget := "R0_Fleet_two"
|
|
||||||
|
|
||||||
// assert.ErrorContains(t,
|
|
||||||
// g.JoinFleets(Race_0.Name, fleetSource, fleetTarget),
|
|
||||||
// e.GenericErrorText(e.ErrInputEntityNotExists))
|
|
||||||
// assert.NoError(t, g.JoinShipGroupToFleet(Race_0.Name, fleetSource, 1, 0))
|
|
||||||
// assert.ErrorContains(t,
|
|
||||||
// g.JoinFleets(Race_0.Name, fleetSource, fleetTarget),
|
|
||||||
// e.GenericErrorText(e.ErrInputEntityNotExists))
|
|
||||||
// assert.NoError(t, g.JoinShipGroupToFleet(Race_0.Name, fleetTarget, 3, 0))
|
|
||||||
// assert.NoError(t, g.JoinFleets(Race_0.Name, fleetSource, fleetTarget))
|
|
||||||
|
|
||||||
// assert.NoError(t, g.JoinShipGroupToFleet(Race_0.Name, fleetPlanet2, 2, 0))
|
|
||||||
// assert.ErrorContains(t,
|
|
||||||
// g.JoinFleets(Race_0.Name, fleetPlanet2, fleetTarget),
|
|
||||||
// e.GenericErrorText(e.ErrShipsNotOnSamePlanet))
|
|
||||||
// }
|
|
||||||
@@ -22,11 +22,11 @@ func (f Float) F() float64 {
|
|||||||
return float64(f)
|
return float64(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
type TechSet map[Tech]float64
|
type TechSet map[Tech]Float
|
||||||
|
|
||||||
func (ts TechSet) Value(t Tech) float64 {
|
func (ts TechSet) Value(t Tech) float64 {
|
||||||
if v, ok := ts[t]; ok {
|
if v, ok := ts[t]; ok {
|
||||||
return v
|
return v.F()
|
||||||
} else {
|
} else {
|
||||||
panic(fmt.Sprintf("TechSet: Value: %s's value not set", t.String()))
|
panic(fmt.Sprintf("TechSet: Value: %s's value not set", t.String()))
|
||||||
}
|
}
|
||||||
@@ -34,7 +34,7 @@ func (ts TechSet) Value(t Tech) float64 {
|
|||||||
|
|
||||||
func (ts TechSet) Set(t Tech, v float64) TechSet {
|
func (ts TechSet) Set(t Tech, v float64) TechSet {
|
||||||
m := maps.Clone(ts)
|
m := maps.Clone(ts)
|
||||||
m[t] = v
|
m[t] = F(v)
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ type Game struct {
|
|||||||
Turn uint `json:"turn"`
|
Turn uint `json:"turn"`
|
||||||
Map Map `json:"map"`
|
Map Map `json:"map"`
|
||||||
Race []Race `json:"races"`
|
Race []Race `json:"races"`
|
||||||
Votes float64 `json:"votes"`
|
Votes Float `json:"votes"`
|
||||||
ShipGroups []ShipGroup `json:"shipGroup,omitempty"`
|
ShipGroups []ShipGroup `json:"shipGroup,omitempty"`
|
||||||
Fleets []Fleet `json:"fleet,omitempty"`
|
Fleets []Fleet `json:"fleet,omitempty"`
|
||||||
Winner []uuid.UUID `json:"winner,omitempty"`
|
Winner []uuid.UUID `json:"winner,omitempty"`
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
package game
|
|
||||||
|
|
||||||
// import "iter"
|
|
||||||
|
|
||||||
// func (g *Game) CreateShips(ri int, shipTypeName string, planetNumber uint, quantity int) error {
|
|
||||||
// return nil // g.createShips(ri, shipTypeName, int(planetNumber), quantity)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (g Game) ListShipGroups(ri int) iter.Seq[ShipGroup] {
|
|
||||||
// return func(yield func(ShipGroup) bool) {}
|
|
||||||
// // return g.listShipGroups(ri)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (g Game) ListFleets(ri int) iter.Seq[Fleet] {
|
|
||||||
// return func(yield func(Fleet) bool) {}
|
|
||||||
// // return g.listFleets(ri)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (g Game) MustPlanetByNumber(num uint) Planet {
|
|
||||||
// p, err := g.PlanetByNumber(num)
|
|
||||||
// if err != nil {
|
|
||||||
// panic(err)
|
|
||||||
// }
|
|
||||||
// return p
|
|
||||||
// }
|
|
||||||
@@ -69,7 +69,7 @@ type InUpgrade struct {
|
|||||||
func (iu InUpgrade) Cost() float64 {
|
func (iu InUpgrade) Cost() float64 {
|
||||||
var sum float64
|
var sum float64
|
||||||
for i := range iu.UpgradeTech {
|
for i := range iu.UpgradeTech {
|
||||||
sum += iu.UpgradeTech[i].Cost
|
sum += iu.UpgradeTech[i].Cost.F()
|
||||||
}
|
}
|
||||||
return sum
|
return sum
|
||||||
}
|
}
|
||||||
@@ -77,16 +77,16 @@ func (iu InUpgrade) Cost() float64 {
|
|||||||
func (iu InUpgrade) TechCost(t Tech) float64 {
|
func (iu InUpgrade) TechCost(t Tech) float64 {
|
||||||
for i := range iu.UpgradeTech {
|
for i := range iu.UpgradeTech {
|
||||||
if iu.UpgradeTech[i].Tech == t {
|
if iu.UpgradeTech[i].Tech == t {
|
||||||
return iu.UpgradeTech[i].Cost
|
return iu.UpgradeTech[i].Cost.F()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0.
|
return 0.
|
||||||
}
|
}
|
||||||
|
|
||||||
type UpgradePreference struct {
|
type UpgradePreference struct {
|
||||||
Tech Tech `json:"tech"`
|
Tech Tech `json:"tech"`
|
||||||
Level float64 `json:"level"`
|
Level Float `json:"level"`
|
||||||
Cost float64 `json:"cost"`
|
Cost Float `json:"cost"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Tech string
|
type Tech string
|
||||||
@@ -177,7 +177,7 @@ func (sg ShipGroup) Equal(other ShipGroup) bool {
|
|||||||
|
|
||||||
// Грузоподъёмность
|
// Грузоподъёмность
|
||||||
func (sg ShipGroup) CargoCapacity(st *ShipType) float64 {
|
func (sg ShipGroup) CargoCapacity(st *ShipType) float64 {
|
||||||
return sg.TechLevel(TechCargo).F() * (st.Cargo + (st.Cargo*st.Cargo)/20) * float64(sg.Number)
|
return sg.TechLevel(TechCargo).F() * (st.Cargo.F() + (st.Cargo.F()*st.Cargo.F())/20) * float64(sg.Number)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Масса перевозимого груза -
|
// Масса перевозимого груза -
|
||||||
@@ -200,7 +200,7 @@ func (sg ShipGroup) FullMass(st *ShipType) float64 {
|
|||||||
// Эффективность двигателя -
|
// Эффективность двигателя -
|
||||||
// равна мощности Двигателей, умноженной на технологический уровень блока Двигателей
|
// равна мощности Двигателей, умноженной на технологический уровень блока Двигателей
|
||||||
func (sg ShipGroup) DriveEffective(st *ShipType) float64 {
|
func (sg ShipGroup) DriveEffective(st *ShipType) float64 {
|
||||||
return st.Drive * sg.TechLevel(TechDrive).F()
|
return st.Drive.F() * sg.TechLevel(TechDrive).F()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Корабли перемещаются за один ход на количество световых лет, равное
|
// Корабли перемещаются за один ход на количество световых лет, равное
|
||||||
@@ -210,7 +210,7 @@ func (sg ShipGroup) Speed(st *ShipType) float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sg ShipGroup) UpgradeDriveCost(st *ShipType, drive float64) float64 {
|
func (sg ShipGroup) UpgradeDriveCost(st *ShipType, drive float64) float64 {
|
||||||
return (1 - sg.TechLevel(TechDrive).F()/drive) * 10 * st.Drive
|
return (1 - sg.TechLevel(TechDrive).F()/drive) * 10 * st.Drive.F()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test on other values
|
// TODO: test on other values
|
||||||
@@ -219,17 +219,17 @@ func (sg ShipGroup) UpgradeWeaponsCost(st *ShipType, weapons float64) float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sg ShipGroup) UpgradeShieldsCost(st *ShipType, shields float64) float64 {
|
func (sg ShipGroup) UpgradeShieldsCost(st *ShipType, shields float64) float64 {
|
||||||
return (1 - sg.TechLevel(TechShields).F()/shields) * 10 * st.Shields
|
return (1 - sg.TechLevel(TechShields).F()/shields) * 10 * st.Shields.F()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sg ShipGroup) UpgradeCargoCost(st *ShipType, cargo float64) float64 {
|
func (sg ShipGroup) UpgradeCargoCost(st *ShipType, cargo float64) float64 {
|
||||||
return (1 - sg.TechLevel(TechCargo).F()/cargo) * 10 * st.Cargo
|
return (1 - sg.TechLevel(TechCargo).F()/cargo) * 10 * st.Cargo.F()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Мощность бомбардировки
|
// Мощность бомбардировки
|
||||||
func (sg ShipGroup) BombingPower(st *ShipType) float64 {
|
func (sg ShipGroup) BombingPower(st *ShipType) float64 {
|
||||||
return (math.Sqrt(st.Weapons*sg.TechLevel(TechWeapons).F())/10. + 1.) *
|
return (math.Sqrt(st.Weapons.F()*sg.TechLevel(TechWeapons).F())/10. + 1.) *
|
||||||
st.Weapons *
|
st.Weapons.F() *
|
||||||
sg.TechLevel(TechWeapons).F() *
|
sg.TechLevel(TechWeapons).F() *
|
||||||
float64(st.Armament) *
|
float64(st.Armament) *
|
||||||
float64(sg.Number)
|
float64(sg.Number)
|
||||||
|
|||||||
@@ -17,15 +17,15 @@ func TestCargoCapacity(t *testing.T) {
|
|||||||
Armament: 1,
|
Armament: 1,
|
||||||
Weapons: 1,
|
Weapons: 1,
|
||||||
Shields: 1,
|
Shields: 1,
|
||||||
Cargo: cargoSize,
|
Cargo: game.F(cargoSize),
|
||||||
}
|
}
|
||||||
sg := game.ShipGroup{
|
sg := game.ShipGroup{
|
||||||
Number: 1,
|
Number: 1,
|
||||||
Tech: map[game.Tech]float64{
|
Tech: map[game.Tech]game.Float{
|
||||||
game.TechDrive: 1.5,
|
game.TechDrive: game.F(1.5),
|
||||||
game.TechWeapons: 1.1,
|
game.TechWeapons: game.F(1.1),
|
||||||
game.TechShields: 2.0,
|
game.TechShields: game.F(2.0),
|
||||||
game.TechCargo: 1.0,
|
game.TechCargo: game.F(1.0),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
assert.Equal(t, expectCapacity, sg.CargoCapacity(&ship))
|
assert.Equal(t, expectCapacity, sg.CargoCapacity(&ship))
|
||||||
@@ -48,11 +48,11 @@ func TestCarryingAndFullMass(t *testing.T) {
|
|||||||
}
|
}
|
||||||
sg := &game.ShipGroup{
|
sg := &game.ShipGroup{
|
||||||
Number: 1,
|
Number: 1,
|
||||||
Tech: map[game.Tech]float64{
|
Tech: map[game.Tech]game.Float{
|
||||||
game.TechDrive: 1.0,
|
game.TechDrive: game.F(1.0),
|
||||||
game.TechWeapons: 1.0,
|
game.TechWeapons: game.F(1.0),
|
||||||
game.TechShields: 1.0,
|
game.TechShields: game.F(1.0),
|
||||||
game.TechCargo: 1.0,
|
game.TechCargo: game.F(1.0),
|
||||||
},
|
},
|
||||||
Load: 0.0,
|
Load: 0.0,
|
||||||
}
|
}
|
||||||
@@ -80,11 +80,11 @@ func TestSpeed(t *testing.T) {
|
|||||||
}
|
}
|
||||||
sg := &game.ShipGroup{
|
sg := &game.ShipGroup{
|
||||||
Number: 1,
|
Number: 1,
|
||||||
Tech: map[game.Tech]float64{
|
Tech: map[game.Tech]game.Float{
|
||||||
game.TechDrive: 1.0,
|
game.TechDrive: game.F(1.0),
|
||||||
game.TechWeapons: 1.0,
|
game.TechWeapons: game.F(1.0),
|
||||||
game.TechShields: 1.0,
|
game.TechShields: game.F(1.0),
|
||||||
game.TechCargo: 1.0,
|
game.TechCargo: game.F(1.0),
|
||||||
},
|
},
|
||||||
Load: 0.0,
|
Load: 0.0,
|
||||||
}
|
}
|
||||||
@@ -109,11 +109,11 @@ func TestBombingPower(t *testing.T) {
|
|||||||
}
|
}
|
||||||
sg := game.ShipGroup{
|
sg := game.ShipGroup{
|
||||||
Number: 1,
|
Number: 1,
|
||||||
Tech: map[game.Tech]float64{
|
Tech: map[game.Tech]game.Float{
|
||||||
game.TechDrive: 1.0,
|
game.TechDrive: game.F(1.0),
|
||||||
game.TechWeapons: 1.0,
|
game.TechWeapons: game.F(1.0),
|
||||||
game.TechShields: 1.0,
|
game.TechShields: game.F(1.0),
|
||||||
game.TechCargo: 1.0,
|
game.TechCargo: game.F(1.0),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
assert.Equal(t, 139.295, number.Fixed3(sg.BombingPower(&BattleStation)))
|
assert.Equal(t, 139.295, number.Fixed3(sg.BombingPower(&BattleStation)))
|
||||||
@@ -123,9 +123,9 @@ func TestBombingPower(t *testing.T) {
|
|||||||
|
|
||||||
func TestDriveEffective(t *testing.T) {
|
func TestDriveEffective(t *testing.T) {
|
||||||
tc := []struct {
|
tc := []struct {
|
||||||
driveShipType float64
|
driveShipType game.Float
|
||||||
driveTech float64
|
driveTech game.Float
|
||||||
expectDriveEffective float64
|
expectDriveEffective game.Float
|
||||||
}{
|
}{
|
||||||
{1, 1, 1},
|
{1, 1, 1},
|
||||||
{1, 2, 2},
|
{1, 2, 2},
|
||||||
@@ -139,20 +139,20 @@ func TestDriveEffective(t *testing.T) {
|
|||||||
someShip := game.ShipType{
|
someShip := game.ShipType{
|
||||||
Drive: tc[i].driveShipType,
|
Drive: tc[i].driveShipType,
|
||||||
Armament: rand.UintN(30) + 1,
|
Armament: rand.UintN(30) + 1,
|
||||||
Weapons: rand.Float64()*30 + 1,
|
Weapons: game.F(rand.Float64()*30 + 1),
|
||||||
Shields: rand.Float64()*100 + 1,
|
Shields: game.F(rand.Float64()*100 + 1),
|
||||||
Cargo: rand.Float64()*20 + 1,
|
Cargo: game.F(rand.Float64()*20 + 1),
|
||||||
}
|
}
|
||||||
sg := game.ShipGroup{
|
sg := game.ShipGroup{
|
||||||
Number: rand.UintN(4) + 1,
|
Number: rand.UintN(4) + 1,
|
||||||
Tech: map[game.Tech]float64{
|
Tech: map[game.Tech]game.Float{
|
||||||
game.TechDrive: tc[i].driveTech,
|
game.TechDrive: tc[i].driveTech,
|
||||||
game.TechWeapons: rand.Float64()*5 + 1,
|
game.TechWeapons: game.F(rand.Float64()*5 + 1),
|
||||||
game.TechShields: rand.Float64()*5 + 1,
|
game.TechShields: game.F(rand.Float64()*5 + 1),
|
||||||
game.TechCargo: rand.Float64()*5 + 1,
|
game.TechCargo: game.F(rand.Float64()*5 + 1),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
assert.Equal(t, tc[i].expectDriveEffective, sg.DriveEffective(&someShip))
|
assert.Equal(t, tc[i].expectDriveEffective.F(), sg.DriveEffective(&someShip))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,7 +170,7 @@ func TestShipGroupEqual(t *testing.T) {
|
|||||||
FleetID: &fleetId,
|
FleetID: &fleetId,
|
||||||
CargoType: &mat,
|
CargoType: &mat,
|
||||||
Load: 123.45,
|
Load: 123.45,
|
||||||
Tech: map[game.Tech]float64{
|
Tech: map[game.Tech]game.Float{
|
||||||
game.TechDrive: 1.0,
|
game.TechDrive: 1.0,
|
||||||
game.TechWeapons: 1.0,
|
game.TechWeapons: 1.0,
|
||||||
game.TechShields: 1.0,
|
game.TechShields: 1.0,
|
||||||
|
|||||||
@@ -1,90 +0,0 @@
|
|||||||
package game
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
"slices"
|
|
||||||
)
|
|
||||||
|
|
||||||
type UpgradeCalc struct {
|
|
||||||
Cost map[Tech]float64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (uc UpgradeCalc) UpgradeCost(ships uint) float64 {
|
|
||||||
var sum float64
|
|
||||||
for _, v := range uc.Cost {
|
|
||||||
sum += v
|
|
||||||
}
|
|
||||||
return sum * float64(ships)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (uc UpgradeCalc) UpgradeMaxShips(resources float64) uint {
|
|
||||||
return uint(math.Floor(resources / uc.UpgradeCost(1)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func BlockUpgradeCost(blockMass, currentBlockTech, targetBlockTech float64) float64 {
|
|
||||||
if blockMass == 0 || targetBlockTech <= currentBlockTech {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return (1 - currentBlockTech/targetBlockTech) * 10 * blockMass
|
|
||||||
}
|
|
||||||
|
|
||||||
func GroupUpgradeCost(sg *ShipGroup, st ShipType, drive, weapons, shields, cargo float64) UpgradeCalc {
|
|
||||||
uc := &UpgradeCalc{Cost: make(map[Tech]float64)}
|
|
||||||
if drive > 0 {
|
|
||||||
uc.Cost[TechDrive] = BlockUpgradeCost(st.DriveBlockMass(), sg.TechLevel(TechDrive).F(), drive)
|
|
||||||
}
|
|
||||||
if weapons > 0 {
|
|
||||||
uc.Cost[TechWeapons] = BlockUpgradeCost(st.WeaponsBlockMass(), sg.TechLevel(TechWeapons).F(), weapons)
|
|
||||||
}
|
|
||||||
if shields > 0 {
|
|
||||||
uc.Cost[TechShields] = BlockUpgradeCost(st.ShieldsBlockMass(), sg.TechLevel(TechShields).F(), shields)
|
|
||||||
}
|
|
||||||
if cargo > 0 {
|
|
||||||
uc.Cost[TechCargo] = BlockUpgradeCost(st.CargoBlockMass(), sg.TechLevel(TechCargo).F(), cargo)
|
|
||||||
}
|
|
||||||
return *uc
|
|
||||||
}
|
|
||||||
|
|
||||||
func CurrentUpgradingLevel(sg *ShipGroup, tech Tech) float64 {
|
|
||||||
if sg.StateUpgrade == nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
ti := slices.IndexFunc(sg.StateUpgrade.UpgradeTech, func(pref UpgradePreference) bool { return pref.Tech == tech })
|
|
||||||
if ti >= 0 {
|
|
||||||
return sg.StateUpgrade.UpgradeTech[ti].Level
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func FutureUpgradeLevel(raceLevel, groupLevel, limit float64) float64 {
|
|
||||||
target := limit
|
|
||||||
if target == 0 || target > raceLevel {
|
|
||||||
target = raceLevel
|
|
||||||
}
|
|
||||||
if groupLevel == target {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return target
|
|
||||||
}
|
|
||||||
|
|
||||||
func UpgradeGroupPreference(sg ShipGroup, st ShipType, tech Tech, v float64) ShipGroup {
|
|
||||||
if v <= 0 || st.BlockMass(tech) == 0 || sg.TechLevel(tech).F() >= v {
|
|
||||||
return sg
|
|
||||||
}
|
|
||||||
var su InUpgrade
|
|
||||||
if sg.StateUpgrade != nil {
|
|
||||||
su = *sg.StateUpgrade
|
|
||||||
} else {
|
|
||||||
su = InUpgrade{UpgradeTech: []UpgradePreference{}}
|
|
||||||
}
|
|
||||||
ti := slices.IndexFunc(su.UpgradeTech, func(pref UpgradePreference) bool { return pref.Tech == tech })
|
|
||||||
if ti < 0 {
|
|
||||||
su.UpgradeTech = append(su.UpgradeTech, UpgradePreference{Tech: tech})
|
|
||||||
ti = len(su.UpgradeTech) - 1
|
|
||||||
}
|
|
||||||
su.UpgradeTech[ti].Level = v
|
|
||||||
su.UpgradeTech[ti].Cost = BlockUpgradeCost(st.BlockMass(tech), sg.TechLevel(tech).F(), v) * float64(sg.Number)
|
|
||||||
|
|
||||||
sg.StateUpgrade = &su
|
|
||||||
return sg
|
|
||||||
}
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
package game_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/iliadenisov/galaxy/internal/model/game"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
Cruiser = game.ShipType{
|
|
||||||
Name: "Cruiser",
|
|
||||||
Drive: 15,
|
|
||||||
Armament: 1,
|
|
||||||
Weapons: 15,
|
|
||||||
Shields: 15,
|
|
||||||
Cargo: 0,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestBlockUpgradeCost(t *testing.T) {
|
|
||||||
assert.Equal(t, 00.0, game.BlockUpgradeCost(1, 1.0, 1.0))
|
|
||||||
assert.Equal(t, 25.0, game.BlockUpgradeCost(5, 1.0, 2.0))
|
|
||||||
assert.Equal(t, 50.0, game.BlockUpgradeCost(10, 1.0, 2.0))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGroupUpgradeCost(t *testing.T) {
|
|
||||||
sg := &game.ShipGroup{
|
|
||||||
Tech: map[game.Tech]float64{
|
|
||||||
game.TechDrive: 1.0,
|
|
||||||
game.TechWeapons: 1.0,
|
|
||||||
game.TechShields: 1.0,
|
|
||||||
game.TechCargo: 1.0,
|
|
||||||
},
|
|
||||||
Number: 1,
|
|
||||||
}
|
|
||||||
assert.Equal(t, 225.0, game.GroupUpgradeCost(sg, Cruiser, 2.0, 2.0, 2.0, 2.0).UpgradeCost(1))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUpgradeMaxShips(t *testing.T) {
|
|
||||||
sg := &game.ShipGroup{
|
|
||||||
Tech: map[game.Tech]float64{
|
|
||||||
game.TechDrive: 1.0,
|
|
||||||
game.TechWeapons: 1.0,
|
|
||||||
game.TechShields: 1.0,
|
|
||||||
game.TechCargo: 1.0,
|
|
||||||
},
|
|
||||||
Number: 10,
|
|
||||||
}
|
|
||||||
uc := game.GroupUpgradeCost(sg, Cruiser, 2.0, 2.0, 2.0, 2.0)
|
|
||||||
assert.Equal(t, uint(4), uc.UpgradeMaxShips(1000))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCurrentUpgradingLevel(t *testing.T) {
|
|
||||||
sg := &game.ShipGroup{
|
|
||||||
StateUpgrade: nil,
|
|
||||||
}
|
|
||||||
assert.Equal(t, 0.0, game.CurrentUpgradingLevel(sg, game.TechDrive))
|
|
||||||
assert.Equal(t, 0.0, game.CurrentUpgradingLevel(sg, game.TechWeapons))
|
|
||||||
assert.Equal(t, 0.0, game.CurrentUpgradingLevel(sg, game.TechShields))
|
|
||||||
assert.Equal(t, 0.0, game.CurrentUpgradingLevel(sg, game.TechCargo))
|
|
||||||
|
|
||||||
sg.StateUpgrade = &game.InUpgrade{
|
|
||||||
UpgradeTech: []game.UpgradePreference{
|
|
||||||
{Tech: game.TechDrive, Level: 1.5, Cost: 100.1},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
assert.Equal(t, 1.5, game.CurrentUpgradingLevel(sg, game.TechDrive))
|
|
||||||
assert.Equal(t, 0.0, game.CurrentUpgradingLevel(sg, game.TechWeapons))
|
|
||||||
assert.Equal(t, 0.0, game.CurrentUpgradingLevel(sg, game.TechShields))
|
|
||||||
assert.Equal(t, 0.0, game.CurrentUpgradingLevel(sg, game.TechCargo))
|
|
||||||
|
|
||||||
sg.StateUpgrade.UpgradeTech = append(sg.StateUpgrade.UpgradeTech, game.UpgradePreference{Tech: game.TechCargo, Level: 2.2, Cost: 200.2})
|
|
||||||
assert.Equal(t, 1.5, game.CurrentUpgradingLevel(sg, game.TechDrive))
|
|
||||||
assert.Equal(t, 0.0, game.CurrentUpgradingLevel(sg, game.TechWeapons))
|
|
||||||
assert.Equal(t, 0.0, game.CurrentUpgradingLevel(sg, game.TechShields))
|
|
||||||
assert.Equal(t, 2.2, game.CurrentUpgradingLevel(sg, game.TechCargo))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFutureUpgradeLevel(t *testing.T) {
|
|
||||||
assert.Equal(t, 0.0, game.FutureUpgradeLevel(2.0, 2.0, 2.0))
|
|
||||||
assert.Equal(t, 0.0, game.FutureUpgradeLevel(2.0, 2.0, 3.0))
|
|
||||||
assert.Equal(t, 1.5, game.FutureUpgradeLevel(1.5, 2.0, 3.0))
|
|
||||||
assert.Equal(t, 2.0, game.FutureUpgradeLevel(2.5, 1.0, 2.0))
|
|
||||||
assert.Equal(t, 2.5, game.FutureUpgradeLevel(2.5, 1.0, 0.0))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUpgradeGroupPreference(t *testing.T) {
|
|
||||||
sg := game.ShipGroup{
|
|
||||||
Number: 4,
|
|
||||||
Tech: game.TechSet{
|
|
||||||
game.TechDrive: 1.0,
|
|
||||||
game.TechWeapons: 1.0,
|
|
||||||
game.TechShields: 1.0,
|
|
||||||
game.TechCargo: 1.0,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
assert.Nil(t, sg.StateUpgrade)
|
|
||||||
sg = game.UpgradeGroupPreference(sg, Cruiser, game.TechDrive, 0)
|
|
||||||
assert.Nil(t, sg.StateUpgrade)
|
|
||||||
|
|
||||||
sg = game.UpgradeGroupPreference(sg, Cruiser, game.TechDrive, 2.0)
|
|
||||||
assert.NotNil(t, sg.StateUpgrade)
|
|
||||||
assert.Equal(t, 300., sg.StateUpgrade.TechCost(game.TechDrive))
|
|
||||||
assert.Equal(t, 300., sg.StateUpgrade.Cost())
|
|
||||||
|
|
||||||
sg = game.UpgradeGroupPreference(sg, Cruiser, game.TechWeapons, 2.0)
|
|
||||||
assert.NotNil(t, sg.StateUpgrade)
|
|
||||||
assert.Equal(t, 300., sg.StateUpgrade.TechCost(game.TechWeapons))
|
|
||||||
assert.Equal(t, 600., sg.StateUpgrade.Cost())
|
|
||||||
|
|
||||||
sg = game.UpgradeGroupPreference(sg, Cruiser, game.TechShields, 2.0)
|
|
||||||
assert.NotNil(t, sg.StateUpgrade)
|
|
||||||
assert.Equal(t, 300., sg.StateUpgrade.TechCost(game.TechShields))
|
|
||||||
assert.Equal(t, 900., sg.StateUpgrade.Cost())
|
|
||||||
|
|
||||||
sg = game.UpgradeGroupPreference(sg, Cruiser, game.TechCargo, 2.0)
|
|
||||||
assert.NotNil(t, sg.StateUpgrade)
|
|
||||||
assert.Equal(t, 0., sg.StateUpgrade.TechCost(game.TechCargo))
|
|
||||||
assert.Equal(t, 900., sg.StateUpgrade.Cost())
|
|
||||||
}
|
|
||||||
@@ -23,7 +23,7 @@ const (
|
|||||||
type Production struct {
|
type Production struct {
|
||||||
Type ProductionType `json:"type"`
|
Type ProductionType `json:"type"`
|
||||||
SubjectID *uuid.UUID `json:"subjectId"` // TODO: get rid of Nils?
|
SubjectID *uuid.UUID `json:"subjectId"` // TODO: get rid of Nils?
|
||||||
Progress *float64 `json:"progress"`
|
Progress *Float `json:"progress"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p ProductionType) AsType(subject uuid.UUID) Production {
|
func (p ProductionType) AsType(subject uuid.UUID) Production {
|
||||||
|
|||||||
@@ -3,19 +3,15 @@ package game
|
|||||||
import "github.com/google/uuid"
|
import "github.com/google/uuid"
|
||||||
|
|
||||||
type Race struct {
|
type Race struct {
|
||||||
ID uuid.UUID `json:"id"`
|
ID uuid.UUID `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Extinct bool `json:"extinct"`
|
Extinct bool `json:"extinct"`
|
||||||
|
Votes Float `json:"votes"`
|
||||||
Votes float64 `json:"votes"`
|
|
||||||
VoteFor uuid.UUID `json:"voteFor"`
|
VoteFor uuid.UUID `json:"voteFor"`
|
||||||
Relations []RaceRelation `json:"relations"`
|
Relations []RaceRelation `json:"relations"`
|
||||||
|
Tech TechSet `json:"tech"`
|
||||||
Tech TechSet `json:"tech"`
|
Sciences []Science `json:"science,omitempty"`
|
||||||
|
ShipTypes []ShipType `json:"shipType,omitempty"`
|
||||||
Sciences []Science `json:"science,omitempty"`
|
|
||||||
|
|
||||||
ShipTypes []ShipType `json:"shipType,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Relation string
|
type Relation string
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import (
|
|||||||
type Science struct {
|
type Science struct {
|
||||||
ID uuid.UUID `json:"id"`
|
ID uuid.UUID `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Drive float64 `json:"drive"`
|
Drive Float `json:"drive"`
|
||||||
Weapons float64 `json:"weapons"`
|
Weapons Float `json:"weapons"`
|
||||||
Shields float64 `json:"shields"`
|
Shields Float `json:"shields"`
|
||||||
Cargo float64 `json:"cargo"`
|
Cargo Float `json:"cargo"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
package game
|
|
||||||
|
|
||||||
type GameParameter struct {
|
|
||||||
Series string
|
|
||||||
Players uint
|
|
||||||
Public bool
|
|
||||||
}
|
|
||||||
@@ -7,11 +7,11 @@ import (
|
|||||||
type ShipType struct {
|
type ShipType struct {
|
||||||
ID uuid.UUID `json:"id"`
|
ID uuid.UUID `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Drive float64 `json:"drive"`
|
Drive Float `json:"drive"`
|
||||||
Armament uint `json:"armament"`
|
Armament uint `json:"armament"`
|
||||||
Weapons float64 `json:"weapons"`
|
Weapons Float `json:"weapons"`
|
||||||
Shields float64 `json:"shields"`
|
Shields Float `json:"shields"`
|
||||||
Cargo float64 `json:"cargo"`
|
Cargo Float `json:"cargo"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st ShipType) Equal(o ShipType) bool {
|
func (st ShipType) Equal(o ShipType) bool {
|
||||||
@@ -38,22 +38,22 @@ func (st ShipType) BlockMass(t Tech) float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (st ShipType) DriveBlockMass() float64 {
|
func (st ShipType) DriveBlockMass() float64 {
|
||||||
return st.Drive
|
return st.Drive.F()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st ShipType) WeaponsBlockMass() float64 {
|
func (st ShipType) WeaponsBlockMass() float64 {
|
||||||
if st.Armament == 0 || st.Weapons == 0 {
|
if st.Armament == 0 || st.Weapons == 0 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return float64(st.Armament+1) * (st.Weapons / 2)
|
return float64(st.Armament+1) * (st.Weapons.F() / 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st ShipType) ShieldsBlockMass() float64 {
|
func (st ShipType) ShieldsBlockMass() float64 {
|
||||||
return st.Shields
|
return st.Shields.F()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st ShipType) CargoBlockMass() float64 {
|
func (st ShipType) CargoBlockMass() float64 {
|
||||||
return st.Cargo
|
return st.Cargo.F()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st ShipType) EmptyMass() float64 {
|
func (st ShipType) EmptyMass() float64 {
|
||||||
|
|||||||
Reference in New Issue
Block a user