2.5 KiB
solver/greedy/greedy.ts — deterministic greedy set-cover
(no submodules)
Purpose
This module provides the greedy selector that drives the primary covering
strategy. enhancedGreedyCover picks rectangles from a candidate pool
using a deterministic three-key score (covered count, efficiency, centroid
proximity). perIslandCover runs the same selector independently on each
4-connected island so the algorithm never wastes budget on rectangles that
span the transparent gap between two disjoint islands.
Features
- Three-key score:
covered * 1000 + efficiency * 100 + proximity * 10. The factors are deliberately spaced so a more-covering rect always beats a more-efficient one, and ties are broken by centroid proximity. - Falls back to emitting
1×1rectangles for any residual uncovered pixels — guarantees the cover is complete even when no candidate intersects the residual. perIslandCoverfilters the candidate pool per island so the selector never considers a spanning rect; this halves selection work on multi-island colours.
Usage: Basic
import {
dualAxisMaximalRects,
enhancedGreedyCover,
} from "@suaveplan/emblem-solver/solver";
const candidates = dualAxisMaximalRects(available, rows, cols);
const cover = enhancedGreedyCover(candidates, required, cols, rows);
Usage: Advanced
import {
analyseGrid,
perIslandCover,
dualAxisMaximalRects,
} from "@suaveplan/emblem-solver";
const a = analyseGrid(pixels, w, h);
const info = a.colourAnalysis.get("255,0,0")!;
const candidates = dualAxisMaximalRects(available, h, w);
const cover = perIslandCover(info.islands, candidates, w, h);
API Reference
| Symbol | Kind | Description |
|---|---|---|
enhancedGreedyCover(candidates, required, w, h) |
fn | Greedy cover with three-key score |
perIslandCover(islands, candidates, w, h) |
fn | Independent cover per island |
Implementation Notes
The centroid term is computed against the running set of uncovered
required pixels, not the original set — this keeps selections clustered
even as the residual shrinks. We use a precomputed maxDist = sqrt(w² + h²) so the proximity term is normalised to [0, 1]; without
this, the third tiebreaker could dominate the second on large grids.
perIslandCover materialises a fresh boolean[][] per island; this is
acceptable because the typical island count is small (≤ 10 on the
upstream fixtures) and the allocation cost is dominated by the cover work
inside.