Spaces:
Sleeping
Sleeping
| 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 | |
| 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 | |
| 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 | |