Write JavaScript to coordinate robots, manage batteries, and conquer deadlocks—before your simple rules create emergent gridlock
Learn how to write algorithms that control warehouse robots to fulfill orders efficiently.
Your algorithm controls robots to pick items from shelves and deliver them to the shipping zone. You can also manage restocking from the conveyor belt.
{
init: function(robots, warehouse, store) {
// Called once when simulation starts
// Set up any initial state
},
update: function(robots, orders, warehouse, store, conveyorItems) {
// Called every tick
// Assign orders, navigate robots, handle stocking
}
}Simulations are strictly deterministic for a given seed and algorithm. Use rand() or seededMath.random() for randomness.
Real-time APIs like Date,performance, timers, andcrypto, plus network APIs likefetch, and Node globals likeprocess/requireare stubbed or disabled to keep runs reproducible.
Date values are tick-based and normalized to UTC, and performance.now() returns the current tick count for stable timing across machines.
init and update are time-boxed to 50ms. If you exceed the limit, the run stops with an error.
Editing code or config marks the simulation as stale. Hit Reset to apply changes.
Algorithms run on 1,000 canonical seeds. Lower scores rank higher.
score_per_seed = sum(completedAt - createdAt for each completed order) + sum(maxTicks - createdAt for each unfinished order) final_score = average(score_per_seed over all seeds)
The stats bar updates every tick and highlights throughput, delays, and system health.
The event log is your primary debugging tool. It records significant simulation and algorithm events as they happen.
The store is persistent key-value storage that persists across ticks. It also provides atomic locks for coordination.
{
id: "order-42",
item: "📦", // Item type to pick
status: "pending", // "pending" | "in-progress" | "completed"
priority: 1, // 0 (low) .. 2 (high)
createdAt: 150, // Tick when created
assignedRobot: null, // Robot id or null
completedAt: null // Tick when delivered
}{
width: 20, height: 14,
grid: [[0,0,1,...], ...], // 0=walkable, 1=shelf
items: [{ // Items on shelves
id, type, shelfPos, pickupPos, quantity
}, ...],
emptyShelfSpots: [{ // Available for stocking
shelfPos: {x, y}, pickupPos: {x, y}
}, ...],
shippingZone: {x, y, width, height},
chargingZone: {x, y, width, height},
conveyorZone: {x, y, width, height, pickupY}
}{
id: "incoming-150-42",
type: "📱", // Item emoji
x: 20, // X position on conveyor
y: 8.5, // Y position (flows north)
createdAt: 150 // Tick when spawned
}Each robot can use a different pathfinding algorithm. By default, all robots use A*. You can change a robot's pathfinding strategy using robot.pathfindVia().
// In your init or update function: // Use a built-in algorithm (default is 'astar') robot.pathfindVia('astar'); // A* - optimal path robot.pathfindVia('bfs'); // Breadth-first search robot.pathfindVia('greedy'); // Greedy best-first // Or use a custom function robot.pathfindVia(function(grid, start, end, robots, selfId) { // Your custom pathfinding logic return [{x: 1, y: 2}, {x: 2, y: 2}, ...]; // or null }); // Check current algorithm console.log(robot.pathfindAlgorithm); // 'astar', 'bfs', 'greedy', or 'custom'
Different robots can use different algorithms - try A* for precision tasks and Greedy for fast responses!
function customNav(grid, start, end, robots, selfId) { // grid: 2D array (0=walkable, 1=shelf) // start: {x, y} - robot's current position // end: {x, y} - destination // robots: array of all robots (for collision avoidance) // selfId: this robot's id // Return: array of {x, y} waypoints, or null if no path return [{x: 1, y: 2}, {x: 2, y: 2}, ...]; }
isStuck() to detect blocked robotsemptyShelfSpots for available slots