Spaces:
Running on Zero
Running on Zero
| from __future__ import annotations | |
| from dataclasses import asdict | |
| from grid_map.graph_loader import legal_moves_from | |
| from .state import CulpritMove, GameState | |
| def choose_rule_based_move(state: GameState) -> CulpritMove: | |
| blocks = [asdict(block) for block in state.active_blocks] | |
| legal_moves = [move for move in legal_moves_from(state.culprit.current_junction, blocks) if not move.blocked] | |
| if not legal_moves: | |
| return CulpritMove( | |
| turn_number=state.turn_number, | |
| from_junction=state.culprit.current_junction, | |
| to_junction=state.culprit.current_junction, | |
| mode="remain", | |
| route=[state.culprit.current_junction], | |
| risk_level="high", | |
| ) | |
| checked = {check.junction_id for check in state.junction_checks[-6:]} | |
| notice_junctions = { | |
| int(plan["junction_id"]) | |
| for notice in state.notices[-3:] | |
| for plan in notice.response_plan | |
| } | |
| search_team_junctions = {t.junction_id for t in state.placed_tactics if t.tactic_type == "search_team"} | |
| patrol_unit_junctions = {t.junction_id for t in state.placed_tactics if t.tactic_type == "patrol_unit"} | |
| def score(move) -> tuple[int, int, str]: | |
| pressure = 0 | |
| if move.destination in search_team_junctions: | |
| pressure += 10 | |
| if move.destination in checked: | |
| pressure += 5 | |
| if move.destination in patrol_unit_junctions: | |
| pressure += 4 | |
| if move.destination in notice_junctions: | |
| pressure += 2 | |
| mode_preference = {"subway": 0, "bus": 1, "taxi": 2}.get(move.mode, 3) | |
| return (pressure, mode_preference, move.mode) | |
| chosen = sorted(legal_moves, key=score)[0] | |
| risk = "low" if score(chosen)[0] == 0 else "medium" | |
| return CulpritMove( | |
| turn_number=state.turn_number, | |
| from_junction=state.culprit.current_junction, | |
| to_junction=chosen.destination, | |
| mode=chosen.mode, | |
| route=list(chosen.via), | |
| risk_level=risk, | |
| ) | |
| def apply_culprit_move(state: GameState, move: CulpritMove) -> None: | |
| state.culprit.current_junction = move.to_junction | |
| state.culprit.route_history.append(move) | |
| state.game_log.append( | |
| { | |
| "turn_number": state.turn_number, | |
| "kind": "culprit_move_private", | |
| "message": f"Culprit moved from {move.from_junction} to {move.to_junction} by {move.mode}.", | |
| } | |
| ) | |