Forging the Perfect Warehouse: A SAT-Powered Packing Engine

The Inspiration

When we looked at the Mecalux Warehouse Bay Placement challenge for HackUPC 2026, we realized this wasn't just a simple bin-packing problem—it was a high-stakes, continuous-space geometry puzzle. We didn't want to write a basic script that spits out a CSV; we wanted to build a relentless, highly optimized physics engine.

What it does

Our project is a Hybrid Orchestrator. Instead of relying on a single algorithm, our local server spins up multiple solvers across parallel CPU cores:

  • An Orthogonal Solver for lightning-fast, grid-aligned packing.
  • A Flex Solver capable of placing bays at any arbitrary rotation to squeeze into micro-gaps.

The orchestrator streams real-time metrics back to our custom dashboard using Server-Sent Events, continuously updating the user and automatically promoting the winning layout.

The Flex solver is also implemented in C++ for better performance.

How we built it

To achieve high speeds in continuous space, we had to rethink collision detection. Instead of treating a bay and its required forklift gap as two separate overlapping polygons, our engine mathematically fuses them into a single, continuous Oriented Bounding Box.

Because of this fused geometry, we could implement the Separating Axis Theorem (SAT). This allows our solver to test thousands of potential placements per second without clipping walls or hitting obstacles, instantly rejecting invalid states.

To actually place the bays, we used Simulated Annealing with a logarithmic cooling schedule, allowing the engine to mutate the warehouse state using five dynamic strategies (Add, Remove, Move, Swap, and Repack).

We implemented to solver engines which utilize multithreading:

  • The hybrid engine, which runs the Orthogonal and the C++ Flex algorithm simultaneously and then selects the better one (lower Q)
  • The ensemble engine utilizes all available CPU cores to run multiple orthogonal and Flex algorithms. As they are non-deterministic algorithms, from multiple executions you can expect different outcomes and also the best of them (lowest Q) gets chosen.

Challenges we ran into

We thought we are tweaking because our algorithm became too smart. We realized our SAT engine was so mathematically strict that it was outsmarting the initial scoring formula provided.

The original quality score formula was: $$ Q=\sum_{bay} \bigg(\frac{price_{bay}} { loads_{bay}}\bigg)^{(2.0−coverage)} $$

Because the base (\(sum_eff\)) grew linearly as we added bays, it overpowered the shrinking exponent. Our engine mathematically proved that the global minimum was achieved by placing exactly one bay. Turns out the formula was already corrected on slack: $$ Q= \bigg(\frac{\sum_{bay} price_{bay}} {\sum_{bay}loads_{bay}} ​ \bigg) ^{(2.0−coverage)} $$

Within seconds of updating our code, our engine adapted and went right back to flawlessly packing the warehouse to the brim.

Accomplishments that we're proud of

  • Sub-second collision detection using SAT in continuous 2D space.

  • A zero-dependency HTML5 canvas visualizer that maps out ceiling heatmaps and bay margins.

  • Catching a critical mathematical loophole in the competition design!+

  • algorithm written in C++

  • Multithreading utilized

3D Warehouse Visualiser (WarehouseOS)

A real-time 3D viewer for the solver output, built as a Next.js app and embedded directly inside the Dashboard.
Tech stack: Next.js 16 · React 19 · Three.js · React Three Fiber · @react-three/drei

How it works:

When the 3D View button is clicked in the dashboard, the Python server converts the solver's output CSV together with the four input CSVs (warehouse perimeter, obstacles, ceiling profile, bay types) into a WorldResponse JSON object. The Next.js page receives the target case name as a URL query parameter (?preload=CaseN), fetches this JSON directly from the Python server, and passes it through world-mapper.ts, which scales all millimetre coordinates into scene units and maps the 2D warehouse plane onto the Three.js XZ ground plane.
The scene renders a procedural warehouse shell (extruded floor polygon, split walls with step-height support, window cutouts), obstacle pillars, a variable ceiling, and each placed bay as a full Mecalux-style shelving unit — upright posts, cross-beams, shelf surfaces, and stacked cargo boxes. An intro orbit camera animation plays on load, and the viewer supports full orbit/zoom controls, a floor-plan toggle, a picture-in-picture mini-map, and per-bay selection with an info panel.

What we learned

We learned that when building heuristic solvers, the algorithm will always blindly optimize for the math you give it, even if that math is fundamentally flawed. We also learned the massive performance benefits of using SAT over standard bounding-box collision detection for rotated polygons.

What's next for the engine

We plan to expand the Flex Solver's spatial grid to support full 3D volumetric collision detection, allowing for stacking logic and multi-tier warehouse routing!

Share this project:

Updates