diff --git a/templates/solver.html b/templates/solver.html index dad7ffe..5099dee 100644 --- a/templates/solver.html +++ b/templates/solver.html @@ -414,6 +414,47 @@ + +
+

Objective

+

+ Factor = exponent in product mode, weight in sum mode. A factor of 0 excludes that + resource from the objective (it is not forced to zero). Negative factors are only + allowed in sum mode. Factors are unaffected by the internal x10 resource scaling. +

+
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+

Solver Settings

@@ -699,6 +740,17 @@ data[input.name] = input.checked; }); + // Collect objective mode and factors (only nonzero factors; missing = excluded) + data.objective_mode = document.getElementById('objective_mode').value; + const objectiveFactors = {}; + ['E', 'B', 'S', 'C'].forEach(r => { + const factor = parseInt(document.getElementById(`objective_factor_${r}`).value); + if (factor) { + objectiveFactors[r] = factor; + } + }); + data.objective_factors = objectiveFactors; + // Collect fixed action constraints const fixedActions = {}; form.querySelectorAll('[id^="action-constraint-"]').forEach(row => { diff --git a/web_solve.py b/web_solve.py index 7cb520d..7267171 100644 --- a/web_solve.py +++ b/web_solve.py @@ -21,6 +21,8 @@ def index(): actions=solve.ENABLED_ACTIONS, agents=solve.AGENT_AVAILABILITY, num_steps=solve.NUM_STEPS, + objective_factors=solve.OBJECTIVE_FACTORS, + objective_mode=solve.OBJECTIVE_MODE, ) @@ -138,6 +140,18 @@ def solve_handler(): city, step = int(city), int(step) fixed_choices["governors"][(city, step, agent)] = enabled + # Parse objective (factor = exponent in "product" mode, weight in + # "sum" mode; missing keys = resource excluded). Factors are NOT x10 + # scaled — they apply to the scaled resource totals and the report + # descales the objective. None falls back to solve.py's defaults. + objective_mode = data.get("objective_mode") or None + objective_factors = None + objective_factors_data = data.get("objective_factors") + if objective_factors_data is not None: + # All-zero dict passes through so solve()'s validation rejects it + # with a clear error instead of silently using the defaults. + objective_factors = {r: int(f) for r, f in objective_factors_data.items()} + # Parse resource constraints resource_constraints = None resource_constraints_data = data.get("resource_constraints", []) @@ -165,6 +179,8 @@ def solve_handler(): verbose=verbose, fixed_choices=fixed_choices, resource_constraints=resource_constraints, + objective_factors=objective_factors, + objective_mode=objective_mode, ) output = output_buffer.getvalue()