| name | dock-assignment |
| description | Assign trucks to loading docks in cross-docking operations. Use this skill when managing dock door allocations, handling truck arrivals, minimizing wait times, or optimizing dock utilization. |
Dock Assignment
Assign trucks and shipments to loading dock doors in cross-docking facilities.
Installation
pip install numpy ortools
Quick Start
from dataclasses import dataclass
from typing import List, Dict
from datetime import datetime, timedelta
@dataclass
class Truck:
id: str
arrival_time: datetime
departure_time: datetime
dock_type: str # 'inbound', 'outbound', 'both'
priority: int = 1
@dataclass
class Dock:
id: str
dock_type: str
available_from: datetime
available_until: datetime
def simple_dock_assignment(trucks: List[Truck], docks: List[Dock]) -> Dict:
"""Assign trucks to docks using first-come-first-served."""
assignments = {}
dock_schedules = {d.id: [] for d in docks}
sorted_trucks = sorted(trucks, key=lambda t: (t.arrival_time, -t.priority))
for truck in sorted_trucks:
compatible_docks = [
d for d in docks
if d.dock_type in [truck.dock_type, 'both']
]
for dock in compatible_docks:
# Check if dock is available
conflicts = [
s for s in dock_schedules[dock.id]
if not (truck.departure_time <= s['start'] or
truck.arrival_time >= s['end'])
]
if not conflicts:
assignments[truck.id] = dock.id
dock_schedules[dock.id].append({
'truck': truck.id,
'start': truck.arrival_time,
'end': truck.departure_time
})
break
return assignments
Common Patterns
Optimized Dock Assignment
from ortools.sat.python import cp_model
def optimize_dock_assignment(trucks: List[dict], docks: List[dict],
time_slots: int) -> dict:
"""
Optimize dock assignments using constraint programming.
"""
model = cp_model.CpModel()
# Decision variables: truck -> dock assignment
assignments = {}
for truck in trucks:
truck_docks = []
for dock in docks:
if dock['type'] in [truck['type'], 'both']:
var = model.NewBoolVar(f"truck_{truck['id']}_dock_{dock['id']}")
assignments[(truck['id'], dock['id'])] = var
truck_docks.append(var)
# Each truck assigned to exactly one dock
model.Add(sum(truck_docks) == 1)
# No overlap on same dock
for dock in docks:
for t1 in trucks:
for t2 in trucks:
if t1['id'] < t2['id']:
key1 = (t1['id'], dock['id'])
key2 = (t2['id'], dock['id'])
if key1 in assignments and key2 in assignments:
# Check time overlap
if not (t1['end'] <= t2['start'] or t2['end'] <= t1['start']):
# Can't both be assigned to this dock
model.Add(assignments[key1] + assignments[key2] <= 1)
# Minimize total wait time (arrival to dock start)
# For simplicity, minimize priority-weighted assignments
objective_terms = []
for truck in trucks:
for dock in docks:
key = (truck['id'], dock['id'])
if key in assignments:
# Lower dock index = better (closer to staging)
cost = int(dock['id'].replace('DOCK', '')) * truck.get('priority', 1)
objective_terms.append(assignments[key] * cost)
model.Minimize(sum(objective_terms))
solver = cp_model.CpSolver()
status = solver.Solve(model)
if status in [cp_model.OPTIMAL, cp_model.FEASIBLE]:
result = {}
for (truck_id, dock_id), var in assignments.items():
if solver.Value(var):
result[truck_id] = dock_id
return result
return None
Dynamic Dock Reallocation
class DockManager:
"""Manage dock assignments dynamically as trucks arrive."""
def __init__(self, docks: List[dict]):
self.docks = {d['id']: d for d in docks}
self.assignments = {} # dock_id -> list of (truck_id, start, end)
self.waiting_queue = []
def request_dock(self, truck: dict) -> str:
"""Request a dock for an arriving truck."""
compatible = [
d_id for d_id, d in self.docks.items()
if d['type'] in [truck['type'], 'both']
]
# Find first available dock
for dock_id in compatible:
if self._is_dock_available(dock_id, truck['arrival'], truck['departure']):
self._assign_dock(dock_id, truck)
return dock_id
# No dock available, add to queue
self.waiting_queue.append(truck)
return None
def _is_dock_available(self, dock_id: str, start: datetime, end: datetime) -> bool:
"""Check if dock is available for time period."""
for _, s, e in self.assignments.get(dock_id, []):
if not (end <= s or start >= e):
return False
return True
def _assign_dock(self, dock_id: str, truck: dict):
"""Assign truck to dock."""
if dock_id not in self.assignments:
self.assignments[dock_id] = []
self.assignments[dock_id].append(
(truck['id'], truck['arrival'], truck['departure'])
)
def release_dock(self, dock_id: str, truck_id: str):
"""Release dock when truck departs."""
self.assignments[dock_id] = [
a for a in self.assignments[dock_id]
if a[0] != truck_id
]
# Check waiting queue
self._process_waiting_queue()
def _process_waiting_queue(self):
"""Try to assign docks to waiting trucks."""
still_waiting = []
for truck in self.waiting_queue:
dock = self.request_dock(truck)
if dock is None:
still_waiting.append(truck)
self.waiting_queue = still_waiting
def get_dock_utilization(self, period_start: datetime,
period_end: datetime) -> dict:
"""Calculate dock utilization for a time period."""
period_minutes = (period_end - period_start).total_seconds() / 60
utilization = {}
for dock_id in self.docks:
busy_time = 0
for _, start, end in self.assignments.get(dock_id, []):
overlap_start = max(start, period_start)
overlap_end = min(end, period_end)
if overlap_end > overlap_start:
busy_time += (overlap_end - overlap_start).total_seconds() / 60
utilization[dock_id] = busy_time / period_minutes if period_minutes > 0 else 0
return utilization
Dock Door Zoning
def zone_based_assignment(trucks: List[dict], docks: List[dict],
destination_zones: dict) -> dict:
"""
Assign docks based on destination zones to minimize travel.
destination_zones: {zone_id: [dock_ids]}
"""
assignments = {}
dock_schedules = {d['id']: [] for d in docks}
for truck in sorted(trucks, key=lambda t: t['arrival']):
zone = truck.get('destination_zone')
preferred_docks = destination_zones.get(zone, [d['id'] for d in docks])
assigned = False
# Try preferred docks first
for dock_id in preferred_docks:
if _check_availability(dock_id, truck, dock_schedules):
assignments[truck['id']] = dock_id
dock_schedules[dock_id].append({
'truck': truck['id'],
'start': truck['arrival'],
'end': truck['departure']
})
assigned = True
break
# Fall back to any available dock
if not assigned:
for dock in docks:
if dock['id'] not in preferred_docks:
if _check_availability(dock['id'], truck, dock_schedules):
assignments[truck['id']] = dock['id']
dock_schedules[dock['id']].append({
'truck': truck['id'],
'start': truck['arrival'],
'end': truck['departure']
})
break
return assignments
def _check_availability(dock_id: str, truck: dict, schedules: dict) -> bool:
"""Check if dock is available for truck's time window."""
for slot in schedules.get(dock_id, []):
if not (truck['departure'] <= slot['start'] or
truck['arrival'] >= slot['end']):
return False
return True
Dock Schedule Visualization
def generate_dock_schedule_report(assignments: dict, trucks: dict,
docks: List[str]) -> dict:
"""Generate a dock schedule report."""
schedule_by_dock = {d: [] for d in docks}
for truck_id, dock_id in assignments.items():
truck = trucks[truck_id]
schedule_by_dock[dock_id].append({
'truck': truck_id,
'arrival': truck['arrival'],
'departure': truck['departure'],
'type': truck['type']
})
# Sort each dock's schedule
for dock_id in schedule_by_dock:
schedule_by_dock[dock_id].sort(key=lambda x: x['arrival'])
# Calculate metrics
metrics = {
'total_trucks': len(assignments),
'unassigned': len(trucks) - len(assignments),
'dock_usage': {}
}
for dock_id, slots in schedule_by_dock.items():
metrics['dock_usage'][dock_id] = len(slots)
return {
'schedule': schedule_by_dock,
'metrics': metrics
}