Files
galaxy-game/pkg/calc/ship.go
T
Ilia Denisov 9ae7b88b89
Tests · UI / test (push) Successful in 2m14s
Tests · Go / test (push) Successful in 2m25s
feat(ui): Phase 30 ship-class calculator with goal-seek and reach circles
Fuse the standalone ship-class designer (Phases 17/18) into a sidebar calculator: live mass/speed/attack/defence/bombing results, a planet build-rate readout, single-target goal-seek, a modernization-cost mode, and auto reach circles on the map for the selected planet.

pkg/calc becomes the single source for the new math (no mirroring): extract BombingPower from the engine model and the per-turn ship-production loop from controller.ProduceShip into pkg/calc (engine now delegates), and add inverse goal-seek solvers in pkg/calc/solve.go. Thin-bridge the combat, planet-build, and solver functions through ui/core/calc + ui/wasm and rebuild core.wasm.

Remove the standalone designer view/route; the ship-classes table and the view/bottom menus open the calculator via a shared request store.

Docs: rewrite ui/PLAN.md Phase 30, adjust Phase 34 (realistic forecast + CAP/COL ownership), add ui/docs/calculator-ux.md, extend calc-bridge.md, fix navigation.md; remove ui/CALCULATOR.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 20:04:07 +02:00

108 lines
3.9 KiB
Go

package calc
import "math"
// Эффективность двигателя -
// равна мощности Двигателей, умноженной на технологический уровень блока Двигателей
func DriveEffective(drive, driveTech float64) float64 {
return drive * driveTech
}
// Масса перевозимого груза -
// общее количество единиц груза, деленное на технологический уровень Грузоперевозок
func CarryingMass(load, cargoTech float64) float64 {
if load <= 0 {
return 0
}
return load / cargoTech
}
// Грузоподъёмность одного корабля
func CargoCapacity(cargo, cargoTech float64) float64 {
return cargoTech * (cargo + (cargo*cargo)/20)
}
// Корабли перемещаются за один ход на количество световых лет, равное
// эффективности двигателя, умноженной на 20 и деленной на "Полную массу" корабля
func Speed(driveEffective, fullMass float64) float64 {
if fullMass <= 0 {
return 0
}
return driveEffective * 20 / fullMass
}
// Полная масса -
// массу корабля самого по себе плюс масса перевозимого груза
func FullMass(emptyMass, carryingMass float64) float64 {
return emptyMass + carryingMass
}
func EmptyMass(drive, weapons float64, armament uint, shields, cargo float64) (float64, bool) {
wm, ok := WeaponsBlockMass(weapons, armament)
if !ok {
return 0, false
}
return drive + shields + cargo + wm, true
}
func WeaponsBlockMass(weapons float64, armament uint) (float64, bool) {
if (armament == 0 && weapons != 0) || (armament != 0 && weapons == 0) {
return 0, false
}
return float64(armament+1) * (weapons / 2), true
}
// Стоимость модернизации одного блока корабля -
// доля недостающего технологического уровня (1 - currentBlockTech/targetBlockTech),
// умноженная на массу блока и нормирующий коэффициент 10.
// Возвращает 0, если масса блока равна нулю или целевой уровень не выше текущего.
func BlockUpgradeCost(blockMass, currentBlockTech, targetBlockTech float64) float64 {
if blockMass == 0 || targetBlockTech <= currentBlockTech {
return 0
}
return (1 - currentBlockTech/targetBlockTech) * 10 * blockMass
}
func DestructionProbability(
attackingWeapons,
attackingWeaponsTech,
defendingShields,
defendingShiledsTech,
defendingFullMass float64,
) float64 {
return DestructionProbabilityEffective(
EffectiveAttack(attackingWeapons, attackingWeaponsTech),
EffectiveDefence(defendingShields, defendingShiledsTech, defendingFullMass),
)
}
func DestructionProbabilityEffective(effectiveAttack, effectiveDefence float64) float64 {
return (math.Log10(effectiveAttack/effectiveDefence)/math.Log10(4) + 1) / 2
}
func EffectiveAttack(weapons, weaponsTech float64) float64 {
return weapons * weaponsTech
}
func EffectiveDefence(
defendingShields,
defendingShiledsTech,
defendingFullMass float64,
) float64 {
if defendingFullMass <= 0 {
return 0
}
return defendingShields * defendingShiledsTech / math.Pow(defendingFullMass, 1./3.) * math.Pow(30., 1./3.)
}
// BombingPower returns the bombing power of number ships whose weapons
// block is weapons, built at weapons tech level weaponsTech and carrying
// armament weapon mounts. The leading factor sqrt(weapons*weaponsTech)/10
// + 1 makes the power grow super-linearly with effective weapon strength,
// which then scales linearly with weapons, weaponsTech, armament, and
// number. With zero armament or zero weapons the power is zero.
func BombingPower(weapons, weaponsTech, armament, number float64) float64 {
return (math.Sqrt(weapons*weaponsTech)/10. + 1.) *
weapons * weaponsTech * armament * number
}