Constraint-based layout solver for terminal grids
Two solvers behind a LayoutSolver interface: CassowarySolver (simplex-based, optimal, handles stay/edit constraints) and GreedySolver (deterministic 5-phase fallback ported from candy-sprinkles). Swap solvers without touching call-sites. Foundation for candy-sprinkles, sugar-bits, and candy-forms layout.
composer require sugarcraft/candy-layout
use SugarCraft\Layout\{Constraint, Direction, GreedySolver, Region};
$solver = GreedySolver::new();
$region = Region::fromSize(100, 24);
$rects = $solver->solve($region, Direction::Horizontal, [
Constraint::length(20), // exactly 20 cells
Constraint::min(10), // at least 10, takes more if available
Constraint::fill(1), // fills remaining space (weight 1)
Constraint::percentage(30), // 30% of total
Constraint::ratio(1, 3), // 1/3 of remaining after fixed
Constraint::max(50), // ceiling — greedy but clamped
]);
| Class | Method | Description |
|---|---|---|
| LayoutSolver | solve(Region, Direction, list<Constraint>) | Solve constraints against a region in the given direction; returns list of sub-regions |
| LayoutSolver | greedy(): self | Factory: create a GreedySolver |
| LayoutSolver | cassowary(): self | Factory: create a CassowarySolver |
| GreedySolver | new(): self | Default factory |
| CassowarySolver | new(): self | Default factory |
| Direction | Horizontal, Vertical | Enum: split direction |
| Region | fromSize(int, int) | Factory: width, height |
| Constraint | length(int) | Fixed cell count |
| Constraint | min(int) | Floor — at least n cells |
| Constraint | max(int) | Ceiling — at most n cells |
| Constraint | fill(int $weight) | Proportional remainder with weight |
| Constraint | percentage(int 0-100) | Percentage of total |
| Constraint | ratio(int $num, int $denom) | Fractional proportion |