Files
galaxy-game/ui/core/calc/solve_test.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

76 lines
2.2 KiB
Go

package calc_test
import (
"testing"
source "galaxy/calc"
bridge "galaxy/core/calc"
"github.com/stretchr/testify/assert"
)
func TestWeaponsForAttackParity(t *testing.T) {
t.Parallel()
cases := []struct{ targetAttack, weaponsTech float64 }{
{18, 1.5}, {0, 1}, {10, 0},
}
for _, c := range cases {
wantV, wantOk := source.WeaponsForAttack(c.targetAttack, c.weaponsTech)
gotV, gotOk := bridge.WeaponsForAttack(c.targetAttack, c.weaponsTech)
assert.Equal(t, wantOk, gotOk)
assert.Equal(t, wantV, gotV)
}
}
func TestDriveForSpeedParity(t *testing.T) {
t.Parallel()
cases := []struct{ targetSpeed, driveTech, restMass float64 }{
{5, 1.2, 35}, {24, 1.2, 35}, {0, 1, 10},
}
for _, c := range cases {
wantV, wantOk := source.DriveForSpeed(c.targetSpeed, c.driveTech, c.restMass)
gotV, gotOk := bridge.DriveForSpeed(c.targetSpeed, c.driveTech, c.restMass)
assert.Equal(t, wantOk, gotOk)
assert.Equal(t, wantV, gotV)
}
}
func TestShieldsForDefenceParity(t *testing.T) {
t.Parallel()
cases := []struct{ targetDefence, shieldsTech, restMass float64 }{
{5, 1, 40}, {0, 1, 40}, {3, 0, 40},
}
for _, c := range cases {
wantV, wantOk := source.ShieldsForDefence(c.targetDefence, c.shieldsTech, c.restMass)
gotV, gotOk := bridge.ShieldsForDefence(c.targetDefence, c.shieldsTech, c.restMass)
assert.Equal(t, wantOk, gotOk)
assert.Equal(t, wantV, gotV)
}
}
func TestCargoForEmptyMassParity(t *testing.T) {
t.Parallel()
cases := []struct{ targetEmptyMass, restMass float64 }{
{42, 30}, {29, 30},
}
for _, c := range cases {
wantV, wantOk := source.CargoForEmptyMass(c.targetEmptyMass, c.restMass)
gotV, gotOk := bridge.CargoForEmptyMass(c.targetEmptyMass, c.restMass)
assert.Equal(t, wantOk, gotOk)
assert.Equal(t, wantV, gotV)
}
}
func TestLoadForFullMassParity(t *testing.T) {
t.Parallel()
cases := []struct{ targetFullMass, emptyMass, cargoTech float64 }{
{65, 45, 1}, {44, 45, 1}, {65, 45, 0},
}
for _, c := range cases {
wantV, wantOk := source.LoadForFullMass(c.targetFullMass, c.emptyMass, c.cargoTech)
gotV, gotOk := bridge.LoadForFullMass(c.targetFullMass, c.emptyMass, c.cargoTech)
assert.Equal(t, wantOk, gotOk)
assert.Equal(t, wantV, gotV)
}
}