diff --git a/internal/controller/planet.go b/internal/controller/planet.go index b9212c8..c983c6d 100644 --- a/internal/controller/planet.go +++ b/internal/controller/planet.go @@ -301,12 +301,13 @@ func (c *Cache) putMaterial(pn uint, v float64) { c.MustPlanet(pn).Mat(v) } -func ProduceShip(p *game.Planet, productionAvailable, shipMass float64) uint { +func ProduceShip_old(p *game.Planet, productionAvailable, shipMass float64) uint { if productionAvailable <= 0 { return 0 } - CAP_perShip := shipMass / p.Resources.F() - productionForMass := shipMass * 10. + // CAP_perShip := shipMass / p.Resources.F() + CAP_perShip := ShipCapitalCost(shipMass, float64(p.Resources)) + productionForMass := ShipProductionCost(shipMass) ships := uint(0) flZero := game.F(0.) p.Production.Progress = &flZero @@ -324,8 +325,92 @@ func ProduceShip(p *game.Planet, productionAvailable, shipMass float64) uint { progress := game.F(productionAvailable / productionCost) productionAvailable -= productionCost * progress.F() p.Production.Progress = &progress + + v := (productionForMass + CAP_perShip) * float64(progress) + fmt.Println("P=", v) + // fmt.Println("productionForMass", productionForMass, "CAP_perShip", CAP_perShip, "productionCost", productionCost, "productionAvailable", productionAvailable, "progress", progress) break } } return ships } + +func ProduceShip(p *game.Planet, productionAvailable, shipMass float64) uint { + if productionAvailable <= 0 { + return 0 + } + // MAT_perShip := shipMass / p.Resources.F() + MAT_perShip := ShipMaterialCost(shipMass, float64(p.Resources)) + fmt.Println("MAT_perShip", MAT_perShip) + productionForMass := ShipProductionCost(shipMass) + ships := uint(0) + fval := game.F(0.) + p.Production.Progress = &fval + for productionAvailable > 0 { + var productionExtraMAT float64 + MAT_deficit := float64(p.Material) - MAT_perShip + // fmt.Println("> MAT:", p.Material) + if MAT_deficit < 0 { + productionExtraMAT = (-MAT_deficit) + // p.Mat(0) + } else { + // p.Mat(float64(p.Material) - MAT_deficit) + } + // fmt.Println("< MAT:", p.Material) + productionCost := productionExtraMAT + productionForMass + // fmt.Println("ships:", ships, "cost:", productionCost, "avail:", productionAvailable) + fmt.Println() + fmt.Println("productionExtraMAT", productionExtraMAT) + fmt.Println("productionForMass", productionForMass) + fmt.Println("productionCost", productionCost) + fmt.Println("productionAvailable", productionAvailable) + if productionAvailable >= productionCost { + productionAvailable -= productionCost + // fmt.Println("> MAT:", p.Material) + if MAT_deficit < 0 { + // productionExtraMAT = -MAT_deficit + p.Mat(0) + } else { + p.Mat(float64(p.Material) - MAT_deficit) + } + // fmt.Println("< MAT:", p.Material) + // fmt.Println("> MAT:", p.Material) + // p.Mat(float64(p.Material) - (MAT_perShip - productionExtraMAT)) + // fmt.Println("< MAT:", p.Material) + ships++ + } else { + progress := productionAvailable / productionCost + // productionAvailable -= productionCost * progress + pval := game.F(progress) + p.Production.Progress = &pval + aval := game.F(productionAvailable) + p.Production.FreeProd = &aval + + // fmt.Println("MAT_deficit", MAT_deficit) + + fmt.Println() + fmt.Println("productionExtraMAT", productionExtraMAT) + fmt.Println("productionForMass", productionForMass) + fmt.Println("productionCost", productionCost) + fmt.Println("productionAvailable", productionAvailable) + fmt.Println("progress", progress) + v := ShipProductionCost(MAT_perShip * float64(progress)) + fmt.Println("MAT=", v) + break + } + } + return ships +} + +func ShipProductionCost(shipMass float64) float64 { + return shipMass * 10. +} +func ShipMaterialCost(shipMass, planetResource float64) float64 { + return shipMass / planetResource +} + +func ShipCapitalCost(shipMass, planetResource float64) float64 { + return shipMass / planetResource +} + +// TODO: при смене производства на планете проверить, сколько материалов высвободится в MAT diff --git a/internal/controller/planet_test.go b/internal/controller/planet_test.go index a407255..b760784 100644 --- a/internal/controller/planet_test.go +++ b/internal/controller/planet_test.go @@ -8,7 +8,6 @@ import ( "github.com/iliadenisov/galaxy/internal/controller" e "github.com/iliadenisov/galaxy/internal/error" "github.com/iliadenisov/galaxy/internal/model/game" - "github.com/iliadenisov/galaxy/internal/number" "github.com/stretchr/testify/assert" ) @@ -166,47 +165,114 @@ func TestProduceShips(t *testing.T) { } func TestProduceShip(t *testing.T) { - Drone := game.ShipType{ - Name: "Drone", - Drive: 1, + // Drone := game.ShipType{ + // Name: "Drone", + // Drive: 1, + // Armament: 0, + // Weapons: 0, + // Shields: 0, + // Cargo: 0, + // } + // BattleShip := game.ShipType{ + // Name: "BattleShip", + // Drive: 25, + // Armament: 1, + // Weapons: 30, + // Shields: 35, + // Cargo: 0, + // } + TestDWShip := game.ShipType{ + Name: "DROCOLZ", + Drive: 11.32, Armament: 0, Weapons: 0, Shields: 0, - Cargo: 0, - } - BattleShip := game.ShipType{ - Name: "BattleShip", - Drive: 25, - Armament: 1, - Weapons: 30, - Shields: 35, - Cargo: 0, + Cargo: 1, } id := uuid.New() - p := controller.NewPlanet(0, "Planet_0", &id, 1, 1, 1000, 1000, 1000, 10, game.ProductionShip.AsType(uuid.Nil)) + // p := controller.NewPlanet(0, "Planet_0", &id, 1, 1, 1000, 1000, 1000, 10, game.ProductionShip.AsType(uuid.Nil)) - r := controller.ProduceShip(&p, p.ProductionCapacity(), Drone.EmptyMass()) - assert.Equal(t, uint(99), r) - assert.InDelta(t, 0.0099, (*p.Production.Progress).F(), 0.000001) + // r := controller.ProduceShip(&p, p.ProductionCapacity(), Drone.EmptyMass()) + // assert.Equal(t, uint(99), r) + // assert.InDelta(t, 0.0099, (*p.Production.Progress).F(), 0.000001) - (&p).Production = game.ProductionShip.AsType(uuid.Nil) - (&p).Capital = 10. - r = controller.ProduceShip(&p, p.ProductionCapacity(), Drone.EmptyMass()) - assert.Equal(t, uint(100), r) - 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 + // (&p).Production = game.ProductionShip.AsType(uuid.Nil) + // (&p).Capital = 10. + // r = controller.ProduceShip(&p, p.ProductionCapacity(), Drone.EmptyMass()) + // assert.Equal(t, uint(100), r) + // 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 - (&p).Production = game.ProductionShip.AsType(uuid.Nil) - (&p).Capital = 0. - r = controller.ProduceShip(&p, p.ProductionCapacity(), BattleShip.EmptyMass()) - assert.Equal(t, uint(1), r) - assert.InDelta(t, 0.1, (*p.Production.Progress).F(), 0.001) + // (&p).Production = game.ProductionShip.AsType(uuid.Nil) + // (&p).Capital = 0. + // r = controller.ProduceShip(&p, p.ProductionCapacity(), BattleShip.EmptyMass()) + // assert.Equal(t, uint(1), r) + // assert.InDelta(t, 0.1, (*p.Production.Progress).F(), 0.001) - (&p).Production = game.ProductionShip.AsType(uuid.Nil) - (&p).Capital = 20. - r = controller.ProduceShip(&p, p.ProductionCapacity(), BattleShip.EmptyMass()) - assert.Equal(t, uint(1), r) - assert.Equal(t, 1./9., (*p.Production.Progress).F()) + // (&p).Production = game.ProductionShip.AsType(uuid.Nil) + // (&p).Capital = 20. + // r = controller.ProduceShip(&p, p.ProductionCapacity(), BattleShip.EmptyMass()) + // assert.Equal(t, uint(1), r) + // assert.Equal(t, number.Fixed12(1./9.), (*p.Production.Progress).F()) + + // test "P" for report + dw := controller.NewPlanet(0, "DW_Planet", &id, 1, 1, 500, 500, 500, 10, game.ProductionShip.AsType(uuid.Nil)) + (&dw).Material = 0.32 + r := controller.ProduceShip(&dw, dw.ProductionCapacity(), TestDWShip.EmptyMass()) + assert.Equal(t, uint(4), r) + assert.Equal(t, 2.30, (*dw.Production.Progress).F()) + // TODO: test with insufficient production capacity +} + +func TestProduceShip_Research(t *testing.T) { + TestShipCargo1 := game.ShipType{ + Name: "Cargo1", + Drive: 30.18, + Armament: 0, + Weapons: 0., + Shields: 0., + Cargo: 19., + } + TestShipDROCOLZ := game.ShipType{ + Name: "DROCOLZ", + Drive: 11.32, + Armament: 0, + Weapons: 0, + Shields: 0, + Cargo: 1, + } + _ = TestShipDROCOLZ + _ = TestShipCargo1 + id := uuid.New() + dw1 := controller.NewPlanet(0, "DW2", &id, 1, 1, 500, 500, 500, 10, game.ProductionShip.AsType(uuid.Nil)) + dw2 := controller.NewPlanet(0, "DW1", &id, 1, 1, 500, 500, 500, 10, game.ProductionShip.AsType(uuid.Nil)) + _ = dw1 + + // (&dw1).Material = 0.0 + // r := controller.ProduceShip(&dw1, dw1.ProductionCapacity(), TestShipDROCOLZ.EmptyMass()) + // assert.Equal(t, uint(4), r) + // assert.Equal(t, 2.272, (*dw1.Production.FreeProd).F()) + + // -------- + + var r uint + + // (&dw2).Material = 0.0 + // r = controller.ProduceShip(&dw2, dw2.ProductionCapacity(), TestShipCargo1.EmptyMass()) + // assert.Equal(t, uint(1), r) + // assert.Equal(t, 3.282, (*dw2.Production.FreeProd).F()) + + // // production stopped and extra MAT released + // matPerShip := controller.ShipMaterialCost(TestShipCargo1.EmptyMass(), float64(dw2.Resources)) + // assert.Equal(t, 4.918, matPerShip) + // (&dw2).Material = game.F(controller.ShipProductionCost(matPerShip * float64(*dw2.Production.Progress))) + // assert.Equal(t, 0.32495049505, (&dw2).Material.F()) // old repoert: 0.32 + + // building new ship with extra MAT + (&dw2).Material = game.F(0.32495049505) + r = controller.ProduceShip(&dw2, dw2.ProductionCapacity(), TestShipDROCOLZ.EmptyMass()) + assert.Equal(t, uint(4), r) + assert.Equal(t, 2.3, (*dw2.Production.FreeProd).F()) // TODO: test with insufficient production capacity } @@ -249,7 +315,7 @@ func TestTurnPlanetProductions(t *testing.T) { assert.Equal(t, 0.0, c.MustPlanet(R0_Planet_0_num).Colonists.F()) c.TurnPlanetProductions() assert.InDelta(t, 196., c.MustPlanet(R0_Planet_0_num).Capital.F(), 0.1) - assert.InDelta(t, 10.0, c.MustPlanet(R0_Planet_0_num).Colonists.F(), 0.000001) // FIXME: should store more exact value + assert.Equal(t, 10.0, c.MustPlanet(R0_Planet_0_num).Colonists.F()) assert.NoError(t, g.PlanetProduction(Race_0.Name, pn, "MAT", "")) assert.Equal(t, 0.0, c.MustPlanet(R0_Planet_0_num).Material.F()) @@ -275,7 +341,7 @@ func TestTurnPlanetProductions(t *testing.T) { assert.NoError(t, g.PlanetProduction(Race_0.Name, pn, "CARGO", "")) assert.Equal(t, 1.4, c.Race(Race_0_idx).TechLevel(game.TechCargo)) c.TurnPlanetProductions() - assert.InDelta(t, 1.6, c.Race(Race_0_idx).TechLevel(game.TechCargo), 0.1) // FIXME: 1.5999999999999999 -> 1.6 + assert.Equal(t, 1.6, c.Race(Race_0_idx).TechLevel(game.TechCargo)) assert.NoError(t, g.PlanetProduction(Race_0.Name, pn, "SCIENCE", "Equality")) c.TurnPlanetProductions() diff --git a/internal/controller/report.go b/internal/controller/report.go index 20d5ce2..3a4e4ac 100644 --- a/internal/controller/report.go +++ b/internal/controller/report.go @@ -539,7 +539,7 @@ func (c *Cache) ReportShipProduction(ri int, rep *mr.Report) { free := c.PlanetProductionCapacity(p.Number) rep.ShipProduction[pi].Planet = p.Number rep.ShipProduction[pi].Class = st.Name - rep.ShipProduction[pi].Cost = mr.F(st.EmptyMass()) + rep.ShipProduction[pi].Cost = mr.F(ShipProductionCost(st.EmptyMass())) rep.ShipProduction[pi].Free = mr.F(free) // FIXME: take logic from [ProduceShip] and test at [controller_test.TestProduceShip] diff --git a/internal/model/game/production.go b/internal/model/game/production.go index 8f77885..451807e 100644 --- a/internal/model/game/production.go +++ b/internal/model/game/production.go @@ -24,6 +24,7 @@ type Production struct { Type ProductionType `json:"type"` SubjectID *uuid.UUID `json:"subjectId"` // TODO: get rid of Nils? Progress *Float `json:"progress"` + FreeProd *Float // TODO: rename, store } func (p ProductionType) AsType(subject uuid.UUID) Production {