diff --git a/main.py b/main.py index 85bc6f8..68eabbd 100644 --- a/main.py +++ b/main.py @@ -23,6 +23,44 @@ import printer # Display in _report divides by 10. INITIAL = (30, 30, 30, 30) +# fixed_choices = { +# "actions": { +# (city_idx, step): "action_name", # e.g., (0, 2): "collect" +# # ... +# }, +# "governors": { +# (city_idx, step, agent_name): bool, # e.g., (1, 1, "provisioner"): True +# # ... +# } +# } +# +# None for nothing +# FIXED_CHOICES = None +FIXED_CHOICES = { + "actions": { + (0, 1): "renovate_h", + (1, 1): "renovate_h", + (2, 1): "renovate_h", + (3, 1): "overwork", + (0, 2): "collect", + (1, 2): "collect", + (2, 2): "overwork", + (3, 2): "upgrade_a", + (0, 3): "collect", + (1, 3): "collect", + (2, 3): "upgrade_a", + (3, 3): "overwork", + (0, 4): "collect", + (1, 4): "collect", + (2, 4): "overwork", + (3, 4): "upgrade_b", + (0, 5): "collect", + (1, 5): "collect", + (2, 5): "upgrade_b", + (3, 5): "overwork", + } +} + # Arrival schedule. Key = step (1..5), value = list of city types that arrive # at the START of that step. Types: 'H' Hub, 'F' Foundry, 'M' Metropolis, 'N' Monument. # Total cities across all steps must be <= 7. Arriving cities act that same step. @@ -37,7 +75,7 @@ ARRIVALS = { 1: [ {"type": "F", "adjacent_to": []}, {"type": "F", "adjacent_to": []}, - {"type": "F", "adjacent_to": [], "departure_step": 6}, + {"type": "F", "adjacent_to": []}, {"type": "H", "adjacent_to": []}, ], 2: [], @@ -917,6 +955,7 @@ class Fence(EventAgent): def solve( + *, initial=INITIAL, arrivals=ARRIVALS, max_res=MAX_RES, @@ -924,6 +963,7 @@ def solve( time_limit=60.0, num_workers=8, verbose=True, + fixed_choices=FIXED_CHOICES, ): # ---- build the city list ----------------------------------------- @@ -1097,6 +1137,11 @@ def solve( for agent in event_agent_registry: agent.declare_vars(m, _agent_decl_ctx) + if fixed_choices and "governors" in fixed_choices: + for (city, step, agent_name), value in fixed_choices["governors"].items(): + if governor.get((city, step, agent_name)) is not None: + m.Add(governor[city, step, agent_name] == (1 if value else 0)) + # ---- per-city logic ----------------------------------------------- for i in range(N): a_step, a_city = cities[i] @@ -1191,6 +1236,20 @@ def solve( for action in action_registry: action.declare_vars(m, i, t, ctx) + # After declaring all action variables for (i,t) + if fixed_choices and "actions" in fixed_choices: + action_key = (i, t) + if action_key in fixed_choices["actions"]: + fixed_action = fixed_choices["actions"][action_key] + # Set the chosen action to 1, others to 0 + for action in action_registry: + var = action.selector_var(i, t, ctx) + if var is not None: + if action.name == fixed_action: + m.Add(var == 1) + else: + m.Add(var == 0) + # renovations helper (used by multiple actions) ren = m.NewBoolVar("") rH_act = rH.get((i, t)) @@ -1473,12 +1532,16 @@ def solve( solver = cp_model.CpSolver() solver.parameters.max_time_in_seconds = time_limit solver.parameters.num_search_workers = num_workers - status = solver.Solve( - m, - # printer.IntermediateSolutionPrinter( - # {"electrum": finalE, "brass": finalB, "steel": finalS}, scale=0.1 - # ), - ) + status = None + if verbose: + status = solver.Solve( + m, + printer.IntermediateSolutionPrinter( + {"electrum": finalE, "brass": finalB, "steel": finalS}, scale=0.1 + ), + ) + else: + status = solver.Solve(m) if verbose: print(f"(resource ceilings used: E<={capE} B<={capB} S<={capS})")