Initial PuGa toolkit: data layer, econ, depth-aware scan, state sync, plan push
- puga/: cached FIO + PRUNplanner clients, market view with order-book walk, econ formulas ported from PRUNplanner (tested against its suite and live FIO), saturation model v1 (reviewed by Opus) - tools/: scan (depth-aware), price, book, chain, state sync, plan_push (dry run default, [PuGa]-prefixed plans only), legacy prun_scan/prun_cxarb - docs/: mechanics (PRUNplanner is source of truth), roadmap, decisions, saturation design, archived handoff - secrets stay in .env (gitignored); ref/ holds PRUNplanner source (ignored) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
"""Expected values copied from PRUNplanner's own test suite (ref/frontend/src/tests/features/planning/calculations)."""
|
||||
import pytest
|
||||
from puga import econ
|
||||
|
||||
HAB_COSTS = {'HB1': 50283.96581293734, 'HB2': 48183.93380367031, 'HB3': 171236.78856075153, 'HB4': 478742.2978713045,
|
||||
'HB5': 881886.0033487707, 'HBB': 78602.69810873509, 'HBC': 191175.66459235144,
|
||||
'HBM': 759867.355670017, 'HBL': 1210568.4635058648}
|
||||
REQ = {'pioneer': 100, 'settler': 390, 'technician': 490}
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cap,req,l1,l2,exp", [
|
||||
(100, 100, False, False, 0.7944444444444446), (50, 100, False, False, 0.3972222222222223),
|
||||
(100, 50, False, False, 0.7944444444444446), (100, 100, True, False, 0.8666666666666668),
|
||||
(100, 100, False, True, 0.9166666666666667), (100, 100, True, True, 1)])
|
||||
def test_tier_efficiency(cap, req, l1, l2, exp):
|
||||
assert econ.tier_efficiency(cap, req, l1, l2) == pytest.approx(exp)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("n,exp", [(-5, 0), (100, 0), (1, 0.0306), (2, 0.0696), (3, 0.1248), (4, 0.1974), (5, 0.284)])
|
||||
def test_expert_bonus(n, exp):
|
||||
assert econ.expert_bonus(n) == exp
|
||||
|
||||
|
||||
def test_workforce_factor():
|
||||
b = dict(pioneers=40, settlers=30, technicians=20, engineers=10, scientists=5)
|
||||
eff = dict(pioneer=.5, settler=.25, technician=.4, engineer=.1, scientist=1.5)
|
||||
assert econ.workforce_factor(b, eff) == pytest.approx(0.419047619047619)
|
||||
b = dict(pioneers=100, settlers=50, technicians=20, engineers=10, scientists=5)
|
||||
eff = dict(pioneer=1.25, settler=1.625, technician=.4, engineer=.1, scientist=1.5)
|
||||
assert econ.workforce_factor(b, eff) == pytest.approx(1.204054054054054)
|
||||
|
||||
|
||||
def test_faction_bonus():
|
||||
assert econ.faction_multiplier("HORTUS", "AGRICULTURE", 1, 3) == pytest.approx(1.14)
|
||||
assert econ.faction_multiplier("MORIA", "METALLURGY", 20, 21) == pytest.approx(1.0438095238095237)
|
||||
assert econ.faction_multiplier("FOO", "AGRICULTURE", 1, 3) is None
|
||||
assert econ.faction_multiplier("ANTARES", "METALLURGY", 1, 2) is None # Antares is electronics only
|
||||
|
||||
|
||||
def test_hwp_without_technicians_under_metallurgy_cogc():
|
||||
"""HWP 40 settlers + 10 technicians; technicians absent: workforce 0.8 x COGC 1.25 = 1.0 (before expert/HQ)."""
|
||||
hwp = dict(settlers=40, technicians=10)
|
||||
tier = dict(settler=econ.tier_efficiency(40, 40, True, True), technician=0.0)
|
||||
total, el = econ.building_efficiency(hwp, tier, expertise="METALLURGY", cogc="METALLURGY")
|
||||
assert el["WORKFORCE"] == pytest.approx(0.8) and total == pytest.approx(1.0)
|
||||
|
||||
|
||||
def test_extraction_matches_live_deimos():
|
||||
"""Planet data ZV-759c: ALO factor 0.4 (MINERAL), O 0.3 (GASEOUS), H2O 0.2 (LIQUID). APEX/PRUNplanner chips: 28 ALO, 18 O, 14 H2O per day.
|
||||
Live FIO EXT order: 14 ALO per 12.008 h = 28/day."""
|
||||
assert econ.daily_extraction(0.4, "MINERAL") == pytest.approx(28.0)
|
||||
assert econ.daily_extraction(0.3, "GASEOUS") == pytest.approx(18.0)
|
||||
assert econ.daily_extraction(0.2, "LIQUID") == pytest.approx(14.0)
|
||||
t, amt = econ.extraction_cycle("MINERAL", 28.0)
|
||||
assert amt == 14 and t == pytest.approx(12 * 3600e3)
|
||||
|
||||
|
||||
def test_production_io_flux_smelter():
|
||||
r = dict(time_ms=14.9167 * 3600e3, inputs={"ALO": 6, "FLX": 1, "C": 1, "O": 1}, outputs={"AL": 4})
|
||||
io = econ.production_io([r], efficiency=1.0, n_buildings=5)
|
||||
assert io["out"]["AL"] == pytest.approx(4 * 5 * 24 / 14.9167, rel=1e-3) # ~32 AL/day for 5 SME at 100%
|
||||
|
||||
|
||||
def test_workforce_consumption_luxury_gating():
|
||||
d = econ.workforce_consumption("pioneer", 100, 100, lux1=True, lux2=False)
|
||||
assert d == {"DW": 4, "RAT": 4, "OVE": 0.5, "PWO": 0.2}
|
||||
assert econ.workforce_consumption("pioneer", 100, 50, False, False)["DW"] == 2
|
||||
|
||||
|
||||
def test_hab_optimizer_matches_prunplanner():
|
||||
r = econ.optimize_habs(REQ, HAB_COSTS, "cost", max_area=135)
|
||||
assert r["habs"] == {"HB1": 1, "HB2": 4, "HB3": 5} and r["cost"] == pytest.approx(1099203.64383138)
|
||||
r = econ.optimize_habs(REQ, HAB_COSTS, "area")
|
||||
assert r["area"] == 118
|
||||
|
||||
|
||||
def test_matches_live_fio_smelter_efficiency():
|
||||
"""Deimos SME, FIO /production 2026-09-18: Efficiency 1.3360869884. All pioneers, both luxuries met, Metallurgy COGC,
|
||||
2 metallurgy experts, condition 0.9993602633."""
|
||||
tier = dict(pioneer=econ.tier_efficiency(400, 370, True, True))
|
||||
total, el = econ.building_efficiency(dict(pioneers=50), tier, expertise="METALLURGY", cogc="METALLURGY",
|
||||
experts={"METALLURGY": 2}, condition=0.9993602633476257)
|
||||
# model 1.33614 vs FIO 1.33609: agrees to 0.004%; residual unexplained (rounding of expert/condition in game)
|
||||
assert total == pytest.approx(1.3360869884490967, rel=1e-4)
|
||||
Reference in New Issue
Block a user