from __future__ import annotations from dataclasses import dataclass from typing import Any ActionDict = dict[str, list[Any]] Point = tuple[int, int] @dataclass(frozen=True) class CandidateAssignment: agent_id: str order_id: str score: float estimated_cost: int finish_time: int slack: int reward_value: float reward_density: float feasible_now: bool @dataclass(frozen=True) class CandidateRejection: order_id: str score: float estimated_best_cost: int slack_to_cutoff: int reward_value: float has_idle_agents: bool def _as_point(value: Any) -> Point: x, y = value return int(x), int(y) def _grid_congested_set(state: dict[str, Any]) -> set[Point]: grid = state.get("grid", {}) return {_as_point(point) for point in grid.get("congested_zones", [])} def _hotspot_points(state: dict[str, Any]) -> tuple[Point, ...]: grid = state.get("grid", {}) return tuple(_as_point(point) for point in grid.get("hotspots", [])) def _point_cost(point: Point, congested_zones: set[Point]) -> int: return 2 if point in congested_zones else 1 def _route_cost(start: Point, end: Point, congested_zones: set[Point]) -> int: if start == end: return 0 x1, y1 = start x2, y2 = end def walk(horizontal_first: bool) -> int: cost = 0 x, y = x1, y1 def step_to(nx: int, ny: int) -> None: nonlocal x, y, cost if (nx, ny) == (x, y): return x, y = nx, ny cost += _point_cost((x, y), congested_zones) if horizontal_first: dx = 1 if x2 >= x else -1 while x != x2: step_to(x + dx, y) dy = 1 if y2 >= y else -1 while y != y2: step_to(x, y + dy) else: dy = 1 if y2 >= y else -1 while y != y2: step_to(x, y + dy) dx = 1 if x2 >= x else -1 while x != x2: step_to(x + dx, y) return cost return min(walk(True), walk(False)) def estimate_job_cost( agent_location: Point, pickup_location: Point, drop_location: Point, congested_zones: set[Point], service_time: int = 1, ) -> int: return ( _route_cost(agent_location, pickup_location, congested_zones) + _route_cost(pickup_location, drop_location, congested_zones) + service_time ) def _distance_to_nearest_hotspot(point: Point, hotspots: tuple[Point, ...]) -> int: if not hotspots: return 0 x, y = point return min(abs(x - hx) + abs(y - hy) for hx, hy in hotspots) def _visible_orders(state: dict[str, Any]) -> list[dict[str, Any]]: return [order for order in state.get("orders", []) if order.get("status") == "unassigned"] def _idle_agents(state: dict[str, Any]) -> list[dict[str, Any]]: return [agent for agent in state.get("agents", []) if agent.get("status") == "idle"] def _service_cutoff(order: dict[str, Any]) -> int: cutoff = order.get("service_cutoff_time") if cutoff is not None: return int(cutoff) return int(order["deadline"]) def _baseline_candidate( agent: dict[str, Any], order: dict[str, Any], congested_zones: set[Point], current_time: int, ) -> tuple[int, int, float, str, str]: agent_location = _as_point(agent["location"]) pickup = _as_point(order["pickup_location"]) drop = _as_point(order["drop_location"]) estimated_cost = estimate_job_cost(agent_location, pickup, drop, congested_zones) slack = int(order["deadline"]) - (current_time + estimated_cost) return ( int(order["deadline"]), estimated_cost, -float(order["reward_value"]), str(order["order_id"]), str(agent["agent_id"]), ) def _score_candidate( agent: dict[str, Any], order: dict[str, Any], congested_zones: set[Point], hotspots: tuple[Point, ...], current_time: int, ) -> CandidateAssignment: agent_location = _as_point(agent["location"]) pickup = _as_point(order["pickup_location"]) drop = _as_point(order["drop_location"]) reward_value = float(order["reward_value"]) deadline = int(order["deadline"]) estimated_cost = estimate_job_cost(agent_location, pickup, drop, congested_zones) finish_time = current_time + estimated_cost slack = deadline - finish_time feasible_now = slack >= 0 reward_density = reward_value / max(estimated_cost, 1) lateness_penalty = abs(slack) * 4.0 if slack < 0 else 0.0 urgency_bonus = max(0.0, min(slack, 6)) * 0.8 feasible_bonus = 8.0 if feasible_now else -6.0 hotspot_bonus = max(0, 6 - _distance_to_nearest_hotspot(drop, hotspots)) * 0.7 congestion_drag = max(0, estimated_cost - (_route_cost(agent_location, pickup, set()) + _route_cost(pickup, drop, set()) + 1)) score = ( (2.6 * reward_value) + (11.0 * reward_density) + urgency_bonus + feasible_bonus + hotspot_bonus - (1.45 * estimated_cost) - (1.2 * congestion_drag) - lateness_penalty ) return CandidateAssignment( agent_id=str(agent["agent_id"]), order_id=str(order["order_id"]), score=score, estimated_cost=estimated_cost, finish_time=finish_time, slack=slack, reward_value=reward_value, reward_density=reward_density, feasible_now=feasible_now, ) def _score_rejection_candidate( order: dict[str, Any], idle_agents: list[dict[str, Any]], congested_zones: set[Point], current_time: int, ) -> CandidateRejection: reward_value = float(order["reward_value"]) cutoff = _service_cutoff(order) estimated_costs = [ estimate_job_cost( _as_point(agent["location"]), _as_point(order["pickup_location"]), _as_point(order["drop_location"]), congested_zones, ) for agent in idle_agents ] estimated_best_cost = min(estimated_costs) if estimated_costs else 999 best_finish = current_time + estimated_best_cost slack_to_cutoff = cutoff - best_finish reject_pressure = 0.0 if not idle_agents: reject_pressure += 4.0 if slack_to_cutoff < 0: reject_pressure += 9.0 + (2.2 * abs(slack_to_cutoff)) elif slack_to_cutoff <= 1: reject_pressure += 4.5 if reward_value <= 8: reject_pressure += 2.4 elif reward_value <= 10: reject_pressure += 1.6 elif reward_value >= 16: reject_pressure -= 2.2 reward_density = reward_value / max(estimated_best_cost, 1) if reward_density < 1.0: reject_pressure += 3.6 elif reward_density < 1.35: reject_pressure += 2.4 elif reward_density > 2.5: reject_pressure -= 1.0 return CandidateRejection( order_id=str(order["order_id"]), score=reject_pressure, estimated_best_cost=estimated_best_cost, slack_to_cutoff=slack_to_cutoff, reward_value=reward_value, has_idle_agents=bool(idle_agents), ) def build_action(assignments: list[tuple[str, str]], rejections: list[str] | None = None) -> ActionDict: return { "assignments": [ {"agent_id": agent_id, "order_id": order_id} for agent_id, order_id in assignments ], "rejections": list(rejections or []), } def baseline_policy(state: dict[str, Any]) -> ActionDict: current_time = int(state.get("time", 0)) congested_zones = _grid_congested_set(state) idle_agents = sorted(_idle_agents(state), key=lambda agent: str(agent["agent_id"])) remaining_orders = list(_visible_orders(state)) assignments: list[tuple[str, str]] = [] for agent in idle_agents: if not remaining_orders: break ranked_orders = sorted( remaining_orders, key=lambda order: _baseline_candidate(agent, order, congested_zones, current_time), ) chosen = ranked_orders[0] assignments.append((str(agent["agent_id"]), str(chosen["order_id"]))) remaining_orders = [ order for order in remaining_orders if str(order["order_id"]) != str(chosen["order_id"]) ] return build_action(assignments) def target_policy(state: dict[str, Any]) -> ActionDict: current_time = int(state.get("time", 0)) congested_zones = _grid_congested_set(state) hotspots = _hotspot_points(state) idle_agents = list(_idle_agents(state)) available_orders = list(_visible_orders(state)) candidates = [ _score_candidate(agent, order, congested_zones, hotspots, current_time) for agent in idle_agents for order in available_orders ] candidates.sort( key=lambda item: ( -item.score, not item.feasible_now, -item.reward_density, item.estimated_cost, item.agent_id, item.order_id, ) ) chosen_agents: set[str] = set() chosen_orders: set[str] = set() assignments: list[tuple[str, str]] = [] for candidate in candidates: if candidate.agent_id in chosen_agents or candidate.order_id in chosen_orders: continue if candidate.score < 0 and assignments: continue chosen_agents.add(candidate.agent_id) chosen_orders.add(candidate.order_id) assignments.append((candidate.agent_id, candidate.order_id)) remaining_orders = [ order for order in available_orders if str(order["order_id"]) not in chosen_orders ] rejection_candidates = [ _score_rejection_candidate(order, idle_agents, congested_zones, current_time) for order in remaining_orders ] rejection_candidates.sort( key=lambda item: ( -item.score, item.slack_to_cutoff, item.estimated_best_cost, item.order_id, ) ) rejections: list[str] = [] for candidate in rejection_candidates: if candidate.score < 6.5: continue if candidate.reward_value >= 16 and candidate.slack_to_cutoff >= -2: continue if candidate.reward_value >= 12 and candidate.slack_to_cutoff >= 0 and candidate.estimated_best_cost <= 8: continue rejections.append(candidate.order_id) return build_action(assignments, rejections) __all__ = [ "ActionDict", "CandidateAssignment", "CandidateRejection", "baseline_policy", "build_action", "estimate_job_cost", "target_policy", ]