Spaces:
Sleeping
Sleeping
File size: 5,088 Bytes
e40294e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | 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
|