"""Parser service for initial state and traffic strings.""" from typing import Tuple, List from ..models.grid import Grid from ..models.entities import Store, Destination, Tunnel from ..models.state import SearchState def parse_initial_state( initial_state: str, ) -> Tuple[int, int, List[Store], List[Destination], List[Tunnel]]: """ Parse the initial state string. Format: m;n;P;S;CustomerX_1,CustomerY_1,CustomerX_2,CustomerY_2,...; TunnelX_1,TunnelY_1,TunnelX_1',TunnelY_1',TunnelX_2,TunnelY_2,TunnelX_2',TunnelY_2',...; StoreX_1,StoreY_1,StoreX_2,StoreY_2,... Args: initial_state: The initial state string Returns: Tuple of (width, height, stores, destinations, tunnels) """ parts = initial_state.strip().split(";") # Grid dimensions width = int(parts[0]) # m height = int(parts[1]) # n # Number of packages/customers and stores num_packages = int(parts[2]) # P num_stores = int(parts[3]) # S # Parse customer locations destinations: List[Destination] = [] if len(parts) > 4 and parts[4]: customer_coords = parts[4].split(",") for i in range(0, len(customer_coords), 2): if i + 1 < len(customer_coords): x = int(customer_coords[i]) y = int(customer_coords[i + 1]) dest_id = len(destinations) + 1 destinations.append(Destination(id=dest_id, position=(x, y))) # Parse tunnel locations tunnels: List[Tunnel] = [] if len(parts) > 5 and parts[5]: tunnel_coords = parts[5].split(",") for i in range(0, len(tunnel_coords), 4): if i + 3 < len(tunnel_coords): x1 = int(tunnel_coords[i]) y1 = int(tunnel_coords[i + 1]) x2 = int(tunnel_coords[i + 2]) y2 = int(tunnel_coords[i + 3]) tunnels.append(Tunnel(entrance1=(x1, y1), entrance2=(x2, y2))) # Parse store locations stores: List[Store] = [] if len(parts) > 6 and parts[6]: store_coords = parts[6].split(",") for i in range(0, len(store_coords), 2): if i + 1 < len(store_coords): x = int(store_coords[i]) y = int(store_coords[i + 1]) store_id = len(stores) + 1 stores.append(Store(id=store_id, position=(x, y))) return width, height, stores, destinations, tunnels def parse_traffic(traffic_str: str, width: int, height: int) -> Grid: """ Parse the traffic string and create a Grid. Format: SrcX_1,SrcY_1,DstX_1,DstY_1,Traffic_1;SrcX_2,SrcY_2,DstX_2,DstY_2,Traffic_2;... Args: traffic_str: Traffic string width: Grid width height: Grid height Returns: Grid with traffic information """ grid = Grid(width=width, height=height) if not traffic_str: # Initialize all segments with default traffic level 1 _initialize_default_traffic(grid) return grid segments = traffic_str.strip().split(";") for segment in segments: if not segment: continue parts = segment.split(",") if len(parts) >= 5: src_x = int(parts[0]) src_y = int(parts[1]) dst_x = int(parts[2]) dst_y = int(parts[3]) traffic = int(parts[4]) grid.add_segment((src_x, src_y), (dst_x, dst_y), traffic) return grid def _initialize_default_traffic(grid: Grid, default_traffic: int = 1) -> None: """ Initialize all grid segments with default traffic. Creates horizontal and vertical segments between adjacent cells. """ for x in range(grid.width): for y in range(grid.height): # Horizontal segment (right) if x + 1 < grid.width: grid.add_segment((x, y), (x + 1, y), default_traffic) # Vertical segment (up) if y + 1 < grid.height: grid.add_segment((x, y), (x, y + 1), default_traffic) def parse_full_state(initial_state: str, traffic_str: str) -> SearchState: """ Parse both initial state and traffic into a complete SearchState. Args: initial_state: Initial state string traffic_str: Traffic string Returns: Complete SearchState object """ width, height, stores, destinations, tunnels = parse_initial_state(initial_state) grid = parse_traffic(traffic_str, width, height) return SearchState( grid=grid, stores=stores, destinations=destinations, tunnels=tunnels ) def format_initial_state( width: int, height: int, stores: List[Store], destinations: List[Destination], tunnels: List[Tunnel], ) -> str: """ Format state back into initial state string. Args: width: Grid width height: Grid height stores: List of stores destinations: List of destinations tunnels: List of tunnels Returns: Formatted initial state string """ parts = [ str(width), str(height), str(len(destinations)), str(len(stores)), ] # Customer coordinates customer_coords = [] for dest in destinations: customer_coords.extend([str(dest.position[0]), str(dest.position[1])]) parts.append(",".join(customer_coords)) # Tunnel coordinates tunnel_coords = [] for tunnel in tunnels: tunnel_coords.extend( [ str(tunnel.entrance1[0]), str(tunnel.entrance1[1]), str(tunnel.entrance2[0]), str(tunnel.entrance2[1]), ] ) parts.append(",".join(tunnel_coords)) # Store coordinates store_coords = [] for store in stores: store_coords.extend([str(store.position[0]), str(store.position[1])]) parts.append(",".join(store_coords)) return ";".join(parts) def format_traffic(grid: Grid) -> str: """ Format grid traffic into traffic string. Args: grid: Grid with traffic information Returns: Formatted traffic string """ segments = [] for (src, dst), segment in grid.segments.items(): segments.append(f"{src[0]},{src[1]},{dst[0]},{dst[1]},{segment.traffic}") return ";".join(segments)