SearchAlgorithms / backend /app /core /delivery_search.py
Kacemath's picture
feat: update with latest changes
47bba68
"""DeliverySearch - Search problem for package delivery."""
from typing import List, Tuple, Optional, Dict
from .generic_search import GenericSearch
from ..models.grid import Grid
from ..models.entities import Tunnel
from ..models.state import PathResult, SearchStep
from ..heuristics import create_tunnel_aware_heuristic
class DeliverySearch(GenericSearch):
"""
Search problem for finding path from a store to a destination.
Implements the GenericSearch interface for the package delivery problem.
Supports movement in 4 directions (up/down/left/right) and tunnel travel.
"""
def __init__(
self,
grid: Grid,
start: Tuple[int, int],
goal: Tuple[int, int],
tunnels: Optional[List[Tunnel]] = None,
):
"""
Initialize the delivery search problem.
Args:
grid: The city grid with traffic information
start: Starting position (store location)
goal: Goal position (destination location)
tunnels: List of available tunnels
"""
self.grid = grid
self.start = start
self.goal = goal
self.tunnels = tunnels or []
# Create tunnel lookup by entrance position
self._tunnel_entrances: Dict[Tuple[int, int], Tunnel] = {}
for tunnel in self.tunnels:
self._tunnel_entrances[tunnel.entrance1] = tunnel
self._tunnel_entrances[tunnel.entrance2] = tunnel
# Create tunnel-aware heuristic
self._tunnel_heuristic = create_tunnel_aware_heuristic(self.tunnels)
def initial_state(self) -> Tuple[int, int]:
"""Return the starting position."""
return self.start
def goal_test(self, state: Tuple[int, int]) -> bool:
"""Check if current state is the goal."""
return state == self.goal
def actions(self, state: Tuple[int, int]) -> List[str]:
"""
Return list of valid actions from current state.
Actions:
- up: Move up (y+1)
- down: Move down (y-1)
- left: Move left (x-1)
- right: Move right (x+1)
- tunnel: Use tunnel if at entrance
Returns:
List of valid action strings
"""
x, y = state
valid_actions = []
# Check each direction
directions = [
("up", (x, y + 1)),
("down", (x, y - 1)),
("left", (x - 1, y)),
("right", (x + 1, y)),
]
for action, new_pos in directions:
if self.grid.is_valid_position(new_pos):
if not self.grid.is_blocked(state, new_pos):
valid_actions.append(action)
# Check for tunnel
if state in self._tunnel_entrances:
valid_actions.append("tunnel")
return valid_actions
def result(self, state: Tuple[int, int], action: str) -> Tuple[int, int]:
"""
Apply action to state and return new state.
Args:
state: Current position
action: Action to take
Returns:
New position after action
"""
x, y = state
if action == "up":
return (x, y + 1)
elif action == "down":
return (x, y - 1)
elif action == "left":
return (x - 1, y)
elif action == "right":
return (x + 1, y)
elif action == "tunnel":
if state in self._tunnel_entrances:
tunnel = self._tunnel_entrances[state]
return tunnel.get_other_entrance(state)
else:
raise ValueError(f"No tunnel entrance at {state}")
else:
raise ValueError(f"Unknown action: {action}")
def step_cost(
self, state: Tuple[int, int], action: str, next_state: Tuple[int, int]
) -> float:
"""
Return the cost of taking an action.
For regular moves: cost = traffic level of the segment
For tunnels: cost = Manhattan distance between entrances
Args:
state: Current position
action: Action taken
next_state: Resulting position
Returns:
Cost of the action
"""
if action == "tunnel":
tunnel = self._tunnel_entrances.get(state)
if tunnel:
return tunnel.cost
return 0.0
else:
# Regular movement - cost is traffic level
return self.grid.get_traffic(state, next_state)
def heuristic(self, state: Tuple[int, int]) -> float:
"""
Tunnel-aware heuristic for A* search.
Args:
state: Current position
Returns:
Estimated cost to goal
"""
return self._tunnel_heuristic(state, self.goal)
@staticmethod
def path(
grid: Grid,
start: Tuple[int, int],
goal: Tuple[int, int],
tunnels: List[Tunnel],
strategy: str,
visualize: bool = False,
) -> Tuple[PathResult, Optional[List[SearchStep]]]:
"""
Find path from start to goal using specified strategy.
Args:
grid: The city grid
start: Starting position
goal: Goal position
tunnels: Available tunnels
strategy: Search strategy (BF, DF, ID, UC, GR1, GR2, AS1, AS2)
visualize: If True, collect visualization steps
Returns:
Tuple of (PathResult, Optional[List[SearchStep]])
"""
search = DeliverySearch(grid, start, goal, tunnels)
return search.solve(strategy, visualize)