wip: refactor controller
This commit is contained in:
@@ -4,9 +4,6 @@ import (
|
||||
"maps"
|
||||
"math"
|
||||
"slices"
|
||||
|
||||
"github.com/google/uuid"
|
||||
e "github.com/iliadenisov/galaxy/internal/error"
|
||||
)
|
||||
|
||||
type UpgradeCalc struct {
|
||||
@@ -49,157 +46,157 @@ func GroupUpgradeCost(sg ShipGroup, st ShipType, drive, weapons, shields, cargo
|
||||
return *uc
|
||||
}
|
||||
|
||||
func (g *Game) UpgradeGroup(raceName string, groupIndex uint, techInput string, limitShips uint, limitLevel float64) error {
|
||||
ri, err := g.raceIndex(raceName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return g.upgradeGroupInternal(ri, groupIndex, techInput, limitShips, limitLevel)
|
||||
}
|
||||
// func (g *Game) UpgradeGroup(raceName string, groupIndex uint, techInput string, limitShips uint, limitLevel float64) error {
|
||||
// ri, err := g.raceIndex(raceName)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// return g.upgradeGroupInternal(ri, groupIndex, techInput, limitShips, limitLevel)
|
||||
// }
|
||||
|
||||
func (g *Game) upgradeGroupInternal(ri int, groupIndex uint, techInput string, limitShips uint, limitLevel float64) error {
|
||||
sgi := -1
|
||||
for i, sg := range g.listIndexShipGroups(ri) {
|
||||
if sgi < 0 && sg.Index == groupIndex {
|
||||
sgi = i
|
||||
}
|
||||
}
|
||||
if sgi < 0 {
|
||||
return e.NewEntityNotExistsError("group #%d", groupIndex)
|
||||
}
|
||||
// func (g *Game) upgradeGroupInternal(ri int, groupIndex uint, techInput string, limitShips uint, limitLevel float64) error {
|
||||
// sgi := -1
|
||||
// for i, sg := range g.listIndexShipGroups(ri) {
|
||||
// if sgi < 0 && sg.Index == groupIndex {
|
||||
// sgi = i
|
||||
// }
|
||||
// }
|
||||
// if sgi < 0 {
|
||||
// return e.NewEntityNotExistsError("group #%d", groupIndex)
|
||||
// }
|
||||
|
||||
var sti int
|
||||
if sti = slices.IndexFunc(g.Race[ri].ShipTypes, func(st ShipType) bool { return st.ID == g.ShipGroups[sgi].TypeID }); sti < 0 {
|
||||
// hard to test, need manual game data invalidation
|
||||
return e.NewGameStateError("not found: ShipType ID=%v", g.ShipGroups[sgi].TypeID)
|
||||
}
|
||||
st := g.Race[ri].ShipTypes[sti]
|
||||
// var sti int
|
||||
// if sti = slices.IndexFunc(g.Race[ri].ShipTypes, func(st ShipType) bool { return st.ID == g.ShipGroups[sgi].TypeID }); sti < 0 {
|
||||
// // hard to test, need manual game data invalidation
|
||||
// return e.NewGameStateError("not found: ShipType ID=%v", g.ShipGroups[sgi].TypeID)
|
||||
// }
|
||||
// st := g.Race[ri].ShipTypes[sti]
|
||||
|
||||
pl := slices.IndexFunc(g.Map.Planet, func(p Planet) bool { return p.Number == g.ShipGroups[sgi].Destination })
|
||||
if pl < 0 {
|
||||
return e.NewGameStateError("planet #%d", g.ShipGroups[sgi].Destination)
|
||||
}
|
||||
if g.Map.Planet[pl].Owner != uuid.Nil && g.Map.Planet[pl].Owner != g.Race[ri].ID {
|
||||
return e.NewEntityNotOwnedError("planet #%d for upgrade group #%d", g.Map.Planet[pl].Number, groupIndex)
|
||||
}
|
||||
// pl := slices.IndexFunc(g.Map.Planet, func(p Planet) bool { return p.Number == g.ShipGroups[sgi].Destination })
|
||||
// if pl < 0 {
|
||||
// return e.NewGameStateError("planet #%d", g.ShipGroups[sgi].Destination)
|
||||
// }
|
||||
// if g.Map.Planet[pl].Owner != uuid.Nil && g.Map.Planet[pl].Owner != g.Race[ri].ID {
|
||||
// return e.NewEntityNotOwnedError("planet #%d for upgrade group #%d", g.Map.Planet[pl].Number, groupIndex)
|
||||
// }
|
||||
|
||||
if g.ShipGroups[sgi].State() != StateInOrbit && g.ShipGroups[sgi].State() != StateUpgrade {
|
||||
return e.NewShipsBusyError()
|
||||
}
|
||||
// if g.ShipGroups[sgi].State() != StateInOrbit && g.ShipGroups[sgi].State() != StateUpgrade {
|
||||
// return e.NewShipsBusyError()
|
||||
// }
|
||||
|
||||
upgradeValidTech := map[string]Tech{
|
||||
TechDrive.String(): TechDrive,
|
||||
TechWeapons.String(): TechWeapons,
|
||||
TechShields.String(): TechShields,
|
||||
TechCargo.String(): TechCargo,
|
||||
TechAll.String(): TechAll,
|
||||
}
|
||||
// upgradeValidTech := map[string]Tech{
|
||||
// TechDrive.String(): TechDrive,
|
||||
// TechWeapons.String(): TechWeapons,
|
||||
// TechShields.String(): TechShields,
|
||||
// TechCargo.String(): TechCargo,
|
||||
// TechAll.String(): TechAll,
|
||||
// }
|
||||
|
||||
techRequest, ok := upgradeValidTech[techInput]
|
||||
if !ok {
|
||||
return e.NewTechUnknownError(techInput)
|
||||
}
|
||||
// techRequest, ok := upgradeValidTech[techInput]
|
||||
// if !ok {
|
||||
// return e.NewTechUnknownError(techInput)
|
||||
// }
|
||||
|
||||
var blockMasses map[Tech]float64 = map[Tech]float64{
|
||||
TechDrive: st.DriveBlockMass(),
|
||||
TechWeapons: st.WeaponsBlockMass(),
|
||||
TechShields: st.ShieldsBlockMass(),
|
||||
TechCargo: st.CargoBlockMass(),
|
||||
}
|
||||
// var blockMasses map[Tech]float64 = map[Tech]float64{
|
||||
// TechDrive: st.DriveBlockMass(),
|
||||
// TechWeapons: st.WeaponsBlockMass(),
|
||||
// TechShields: st.ShieldsBlockMass(),
|
||||
// TechCargo: st.CargoBlockMass(),
|
||||
// }
|
||||
|
||||
switch {
|
||||
case techRequest != TechAll && blockMasses[techRequest] == 0:
|
||||
return e.NewUpgradeShipTechNotUsedError()
|
||||
case techRequest == TechAll && limitLevel != 0:
|
||||
return e.NewUpgradeParameterNotAllowedError("tech=%s max_level=%f", techRequest.String(), limitLevel)
|
||||
}
|
||||
// switch {
|
||||
// case techRequest != TechAll && blockMasses[techRequest] == 0:
|
||||
// return e.NewUpgradeShipTechNotUsedError()
|
||||
// case techRequest == TechAll && limitLevel != 0:
|
||||
// return e.NewUpgradeParameterNotAllowedError("tech=%s max_level=%f", techRequest.String(), limitLevel)
|
||||
// }
|
||||
|
||||
targetLevel := make(map[Tech]float64)
|
||||
var sumLevels float64
|
||||
for _, tech := range []Tech{TechDrive, TechWeapons, TechShields, TechCargo} {
|
||||
if techRequest == TechAll || tech == techRequest {
|
||||
if g.Race[ri].TechLevel(tech) < limitLevel {
|
||||
return e.NewUpgradeTechLevelInsufficientError("%s=%.03f < %.03f", tech.String(), g.Race[ri].TechLevel(tech), limitLevel)
|
||||
}
|
||||
targetLevel[tech] = FutureUpgradeLevel(g.Race[ri].TechLevel(tech), g.ShipGroups[sgi].TechLevel(tech), limitLevel)
|
||||
} else {
|
||||
targetLevel[tech] = CurrentUpgradingLevel(g.ShipGroups[sgi], tech)
|
||||
}
|
||||
sumLevels += targetLevel[tech]
|
||||
}
|
||||
// targetLevel := make(map[Tech]float64)
|
||||
// var sumLevels float64
|
||||
// for _, tech := range []Tech{TechDrive, TechWeapons, TechShields, TechCargo} {
|
||||
// if techRequest == TechAll || tech == techRequest {
|
||||
// if g.Race[ri].TechLevel(tech) < limitLevel {
|
||||
// return e.NewUpgradeTechLevelInsufficientError("%s=%.03f < %.03f", tech.String(), g.Race[ri].TechLevel(tech), limitLevel)
|
||||
// }
|
||||
// targetLevel[tech] = FutureUpgradeLevel(g.Race[ri].TechLevel(tech), g.ShipGroups[sgi].TechLevel(tech), limitLevel)
|
||||
// } else {
|
||||
// targetLevel[tech] = CurrentUpgradingLevel(g.ShipGroups[sgi], tech)
|
||||
// }
|
||||
// sumLevels += targetLevel[tech]
|
||||
// }
|
||||
|
||||
productionCapacity := PlanetProductionCapacity(g, g.Map.Planet[pl].Number)
|
||||
if g.ShipGroups[sgi].State() == StateUpgrade {
|
||||
// to calculate actual capacity we must substract upgrade cost of selected group, if is upgrade state
|
||||
productionCapacity -= g.ShipGroups[sgi].StateUpgrade.Cost()
|
||||
}
|
||||
uc := GroupUpgradeCost(g.ShipGroups[sgi], st, targetLevel[TechDrive], targetLevel[TechWeapons], targetLevel[TechShields], targetLevel[TechCargo])
|
||||
costForShip := uc.UpgradeCost(1)
|
||||
if costForShip == 0 {
|
||||
return e.NewUpgradeShipsAlreadyUpToDateError("%#v", targetLevel)
|
||||
}
|
||||
// productionCapacity := PlanetProductionCapacity(g, g.Map.Planet[pl].Number)
|
||||
// if g.ShipGroups[sgi].State() == StateUpgrade {
|
||||
// // to calculate actual capacity we must substract upgrade cost of selected group, if is upgrade state
|
||||
// productionCapacity -= g.ShipGroups[sgi].StateUpgrade.Cost()
|
||||
// }
|
||||
// uc := GroupUpgradeCost(g.ShipGroups[sgi], st, targetLevel[TechDrive], targetLevel[TechWeapons], targetLevel[TechShields], targetLevel[TechCargo])
|
||||
// costForShip := uc.UpgradeCost(1)
|
||||
// if costForShip == 0 {
|
||||
// return e.NewUpgradeShipsAlreadyUpToDateError("%#v", targetLevel)
|
||||
// }
|
||||
|
||||
shipsToUpgrade := g.ShipGroups[sgi].Number
|
||||
// НЕ БОЛЕЕ УКАЗАННОГО
|
||||
if limitShips > 0 && shipsToUpgrade > limitShips {
|
||||
shipsToUpgrade = limitShips
|
||||
}
|
||||
// shipsToUpgrade := g.ShipGroups[sgi].Number
|
||||
// // НЕ БОЛЕЕ УКАЗАННОГО
|
||||
// if limitShips > 0 && shipsToUpgrade > limitShips {
|
||||
// shipsToUpgrade = limitShips
|
||||
// }
|
||||
|
||||
maxUpgradableShips := uc.UpgradeMaxShips(productionCapacity)
|
||||
// maxUpgradableShips := uc.UpgradeMaxShips(productionCapacity)
|
||||
|
||||
/*
|
||||
1. считаем стоимость модернизации одного корабля
|
||||
2. считаем сколько кораблей можно модернизировать
|
||||
3. если не хватает даже на 1 корабль, ограничиваемся одним кораблём и пересчитываем коэффициент пропорционально массе блоков
|
||||
4. иначе, считаем истинное количество кораблей с учётом ограничения maxShips
|
||||
*/
|
||||
blockMassSum := st.EmptyMass()
|
||||
// /*
|
||||
// 1. считаем стоимость модернизации одного корабля
|
||||
// 2. считаем сколько кораблей можно модернизировать
|
||||
// 3. если не хватает даже на 1 корабль, ограничиваемся одним кораблём и пересчитываем коэффициент пропорционально массе блоков
|
||||
// 4. иначе, считаем истинное количество кораблей с учётом ограничения maxShips
|
||||
// */
|
||||
// blockMassSum := st.EmptyMass()
|
||||
|
||||
coef := productionCapacity / costForShip
|
||||
if maxUpgradableShips == 0 {
|
||||
if limitLevel > 0 {
|
||||
return e.NewUpgradeInsufficientResourcesError("ship cost=%.03f L=%.03f", costForShip, productionCapacity)
|
||||
}
|
||||
sumLevels = sumLevels * coef
|
||||
for tech := range targetLevel {
|
||||
if blockMasses[tech] > 0 {
|
||||
proportional := sumLevels * (blockMasses[tech] / blockMassSum)
|
||||
targetLevel[tech] = proportional
|
||||
}
|
||||
}
|
||||
maxUpgradableShips = 1
|
||||
} else if maxUpgradableShips > shipsToUpgrade {
|
||||
maxUpgradableShips = shipsToUpgrade
|
||||
}
|
||||
// coef := productionCapacity / costForShip
|
||||
// if maxUpgradableShips == 0 {
|
||||
// if limitLevel > 0 {
|
||||
// return e.NewUpgradeInsufficientResourcesError("ship cost=%.03f L=%.03f", costForShip, productionCapacity)
|
||||
// }
|
||||
// sumLevels = sumLevels * coef
|
||||
// for tech := range targetLevel {
|
||||
// if blockMasses[tech] > 0 {
|
||||
// proportional := sumLevels * (blockMasses[tech] / blockMassSum)
|
||||
// targetLevel[tech] = proportional
|
||||
// }
|
||||
// }
|
||||
// maxUpgradableShips = 1
|
||||
// } else if maxUpgradableShips > shipsToUpgrade {
|
||||
// maxUpgradableShips = shipsToUpgrade
|
||||
// }
|
||||
|
||||
// sanity check
|
||||
uc = GroupUpgradeCost(g.ShipGroups[sgi], st, targetLevel[TechDrive], targetLevel[TechWeapons], targetLevel[TechShields], targetLevel[TechCargo])
|
||||
costForGroup := uc.UpgradeCost(maxUpgradableShips)
|
||||
if costForGroup > productionCapacity {
|
||||
e.NewGameStateError("cost recalculation: coef=%f cost(%d)=%f L=%f", coef, maxUpgradableShips, costForGroup, productionCapacity)
|
||||
}
|
||||
// // sanity check
|
||||
// uc = GroupUpgradeCost(g.ShipGroups[sgi], st, targetLevel[TechDrive], targetLevel[TechWeapons], targetLevel[TechShields], targetLevel[TechCargo])
|
||||
// costForGroup := uc.UpgradeCost(maxUpgradableShips)
|
||||
// if costForGroup > productionCapacity {
|
||||
// e.NewGameStateError("cost recalculation: coef=%f cost(%d)=%f L=%f", coef, maxUpgradableShips, costForGroup, productionCapacity)
|
||||
// }
|
||||
|
||||
// break group if needed
|
||||
if maxUpgradableShips < g.ShipGroups[sgi].Number {
|
||||
if g.ShipGroups[sgi].State() == StateUpgrade {
|
||||
return e.NewUpgradeGroupBreakNotAllowedError("ships=%d max=%d", g.ShipGroups[sgi].Number, maxUpgradableShips)
|
||||
}
|
||||
nsgi, err := g.breakGroupSafe(ri, groupIndex, maxUpgradableShips)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sgi = nsgi
|
||||
}
|
||||
// // break group if needed
|
||||
// if maxUpgradableShips < g.ShipGroups[sgi].Number {
|
||||
// if g.ShipGroups[sgi].State() == StateUpgrade {
|
||||
// return e.NewUpgradeGroupBreakNotAllowedError("ships=%d max=%d", g.ShipGroups[sgi].Number, maxUpgradableShips)
|
||||
// }
|
||||
// nsgi, err := g.breakGroupSafe(ri, groupIndex, maxUpgradableShips)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// sgi = nsgi
|
||||
// }
|
||||
|
||||
// finally, fill group upgrade prefs
|
||||
for tech := range targetLevel {
|
||||
if targetLevel[tech] > 0 {
|
||||
g.ShipGroups[sgi] = UpgradeGroupPreference(g.ShipGroups[sgi], st, tech, targetLevel[tech])
|
||||
}
|
||||
}
|
||||
// // finally, fill group upgrade prefs
|
||||
// for tech := range targetLevel {
|
||||
// if targetLevel[tech] > 0 {
|
||||
// g.ShipGroups[sgi] = UpgradeGroupPreference(g.ShipGroups[sgi], st, tech, targetLevel[tech])
|
||||
// }
|
||||
// }
|
||||
|
||||
return nil
|
||||
}
|
||||
// return nil
|
||||
// }
|
||||
|
||||
func CurrentUpgradingLevel(sg ShipGroup, tech Tech) float64 {
|
||||
if sg.StateUpgrade == nil {
|
||||
|
||||
Reference in New Issue
Block a user