refactor: floats, tests
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"math"
|
||||
"slices"
|
||||
|
||||
"github.com/google/uuid"
|
||||
e "github.com/iliadenisov/galaxy/internal/error"
|
||||
"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 {
|
||||
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 {
|
||||
targetLevel[tech] = game.CurrentUpgradingLevel(sg, tech)
|
||||
targetLevel[tech] = CurrentUpgradingLevel(sg, tech)
|
||||
}
|
||||
sumLevels += targetLevel[tech]
|
||||
}
|
||||
|
||||
productionCapacity := c.PlanetProductionCapacity(p.Number)
|
||||
// if sg.State() == game.StateUpgrade {
|
||||
// // 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])
|
||||
uc := GroupUpgradeCost(sg, *st, targetLevel[game.TechDrive], targetLevel[game.TechWeapons], targetLevel[game.TechShields], targetLevel[game.TechCargo])
|
||||
costForShip := uc.UpgradeCost(1)
|
||||
if costForShip == 0 {
|
||||
return e.NewUpgradeShipsAlreadyUpToDateError("%#v", targetLevel)
|
||||
@@ -118,7 +117,7 @@ func (c *Cache) UpgradeGroup(ri int, groupIndex uint, techInput string, limitShi
|
||||
}
|
||||
|
||||
// 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)
|
||||
if 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
|
||||
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)
|
||||
if err != nil {
|
||||
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) {
|
||||
sg := *(c.ShipGroup(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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user