blackopsrepl's picture
Upload 31 files
e40294e verified
from dataclasses import dataclass
from enum import Enum
from typing import TYPE_CHECKING, ClassVar
if TYPE_CHECKING:
from .domain import Trolley
class Side(Enum):
"""Available shelving sides where products can be located."""
LEFT = "LEFT"
RIGHT = "RIGHT"
class Column(Enum):
"""Defines the warehouse columns."""
COL_A = 'A'
COL_B = 'B'
COL_C = 'C'
COL_D = 'D'
COL_E = 'E'
class Row(Enum):
"""Defines the warehouse rows."""
ROW_1 = 1
ROW_2 = 2
ROW_3 = 3
@dataclass
class Shelving:
"""
Represents a products container. Each shelving has two sides where
products can be stored, and a number of rows.
"""
id: str
x: int # Absolute x position of shelving's left bottom corner
y: int # Absolute y position of shelving's left bottom corner
ROWS_SIZE: ClassVar[int] = 10
@dataclass
class WarehouseLocation:
"""
Represents a location in the warehouse where a product can be stored.
"""
shelving_id: str
side: Side
row: int
def __str__(self) -> str:
return f"WarehouseLocation(shelving={self.shelving_id}, side={self.side.name}, row={self.row})"
def new_shelving_id(column: Column, row: Row) -> str:
"""Create a shelving ID from column and row."""
return f"({column.value},{row.value})"
# Warehouse constants
SHELVING_WIDTH = 2 # meters
SHELVING_HEIGHT = 10 # meters
SHELVING_PADDING = 3 # spacing between shelvings in meters
# Initialize static shelving map
SHELVING_MAP: dict[str, Shelving] = {}
def _init_shelving_map():
"""Initialize the warehouse shelving grid."""
shelving_x = 0
for col in Column:
shelving_y = 0
for row in Row:
shelving_id = new_shelving_id(col, row)
SHELVING_MAP[shelving_id] = Shelving(
id=shelving_id,
x=shelving_x,
y=shelving_y
)
shelving_y += SHELVING_HEIGHT + SHELVING_PADDING
shelving_x += SHELVING_WIDTH + SHELVING_PADDING
_init_shelving_map()
def get_absolute_x(shelving: Shelving, location: WarehouseLocation) -> int:
"""Calculate absolute X position of a location."""
if location.side == Side.LEFT:
return shelving.x
else:
return shelving.x + SHELVING_WIDTH
def get_absolute_y(shelving: Shelving, location: WarehouseLocation) -> int:
"""Calculate absolute Y position of a location."""
return shelving.y + location.row
def calculate_best_y_distance_in_shelving_row(start_row: int, end_row: int) -> int:
"""Calculate the best Y distance when crossing a shelving."""
north_direction = start_row + end_row
south_direction = (SHELVING_HEIGHT - start_row) + (SHELVING_HEIGHT - end_row)
return min(north_direction, south_direction)
def calculate_distance(start: WarehouseLocation, end: WarehouseLocation) -> int:
"""
Calculate distance in meters between two locations considering warehouse structure.
"""
start_shelving = SHELVING_MAP.get(start.shelving_id)
if start_shelving is None:
raise IndexError(f"Shelving: {start.shelving_id} was not found in current Warehouse structure.")
end_shelving = SHELVING_MAP.get(end.shelving_id)
if end_shelving is None:
raise IndexError(f"Shelving: {end.shelving_id} was not found in current Warehouse structure.")
delta_x = 0
start_x = get_absolute_x(start_shelving, start)
start_y = get_absolute_y(start_shelving, start)
end_x = get_absolute_x(end_shelving, end)
end_y = get_absolute_y(end_shelving, end)
if start_shelving == end_shelving:
# Same shelving
if start.side == end.side:
# Same side - just vertical distance
delta_y = abs(start_y - end_y)
else:
# Different side - calculate shortest walk around
delta_x = SHELVING_WIDTH
delta_y = calculate_best_y_distance_in_shelving_row(start.row, end.row)
elif start_shelving.y == end_shelving.y:
# Different shelvings but on same warehouse row
if abs(start_x - end_x) == SHELVING_PADDING:
# Neighbor shelvings with contiguous sides
delta_x = SHELVING_PADDING
delta_y = abs(start_y - end_y)
else:
# Other combinations in same warehouse row
delta_x = abs(start_x - end_x)
delta_y = calculate_best_y_distance_in_shelving_row(start.row, end.row)
else:
# Shelvings on different warehouse rows
delta_x = abs(start_x - end_x)
delta_y = abs(start_y - end_y)
return delta_x + delta_y
def calculate_distance_to_travel(trolley: "Trolley") -> int:
"""Calculate total distance a trolley needs to travel through its steps."""
distance = 0
previous_location = trolley.location
for step in trolley.steps:
distance += calculate_distance(previous_location, step.location)
previous_location = step.location
# Return trip to origin
distance += calculate_distance(previous_location, trolley.location)
return distance