# `optimizer/redundancy/redundancy.ts` — cross-layer redundancy elimination _(no submodules)_ ## Purpose This module owns `eliminateRedundant`, the final cross-layer optimisation the converter runs after every layer's cover has been built. It removes rectangles that produce no visible output: either because higher-z rectangles of any colour overdraw them, or because sibling rectangles in the same layer already cover the same cells. The pass operates in place on the layer list and is the only pass that mutates `layer.rects`. ## Features - Composites every layer into a per-cell `target` grid first (lower-z to higher-z), then walks rect by rect deciding whether removal would change the composited output. - A rect is removed iff *every* one of its required cells is either covered by a sibling rect at the same z-index or overdrawn by a higher-z rect of any colour. - In-place mutation via `Array.prototype.splice` — the converter calls this once per ordering, so the in-place form keeps allocations bounded. ## Usage: Basic ```ts import { eliminateRedundant } from "@suaveplan/emblem-solver"; eliminateRedundant(layers, width, height); ``` ## Usage: Advanced ```ts import { eliminateRedundant } from "@suaveplan/emblem-solver"; const before = layers.reduce((s, l) => s + l.rects.length, 0); eliminateRedundant(layers, width, height); const after = layers.reduce((s, l) => s + l.rects.length, 0); console.log(`pruned ${before - after} redundant rects`); ``` ## API Reference | Symbol | Kind | Description | |---|---|---| | `eliminateRedundant(layers, width, height)` | fn | In-place prune of fully-occluded rects | ## Implementation Notes The compositing step builds a `(string | null)[][]` grid keyed by the canonical colour key — using a string rather than a packed integer makes the per-cell comparison a single `===` against the layer's fill string, which V8 deduplicates aggressively. The two-pass design (composite first, then walk rect by rect) avoids the quadratic blow-up of repeatedly re-compositing after each removal. The removable indices are pushed in ascending order and spliced in reverse, so we never break the index correspondence mid-removal.