Adds crossing_2net.dsn: NET_A is a full-width horizontal wall and NET_B's
pins sit above and below it, so single-layer routing cannot connect NET_B
but two-layer routing succeeds by dipping to the other layer through vias.
Tests assert the multi-layer invariants: single-layer routing leaves a net
unrouted with no vias; multi-layer connects both nets with >= 1 via; the
SES contains a via scope; every via sits at a real layer transition of its
net's path; trace/via endpoints still land on the pads; traces stay on
valid layers and within the outline; and no two different nets cross on the
same layer. Oracle-gated parity tests cover the simple and crossing boards.
Implements a working autorouter and the Java-free replacement for the
freerouting.jar step: dsn_text -> parse_dsn -> build_board -> route ->
write_ses.
GridRouter is a single-layer A* maze search over a uniform occupancy
grid: a cell is blocked by another net's pad (inflated by clearance +
half trace width) or a keepout; each net's ratsnest is connected pin to
pin; a routed trace then blocks other nets. The cell path becomes a
trace polyline whose endpoints are the exact pin locations. Board-unit
paths are converted back to DSN units for the SES (wire (path ...))
scopes.
This is an MVP, not a port of FreeRouting's expansion-room maze:
free-space rooms, rip-up-and-retry, multi-layer via search, and shove
are deferred (they raise quality/coverage, not the connectivity
milestone). It reaches connectivity on boards whose nets route on one
layer without crossing.
Adds tests/dsn/fixtures/simple_2net.dsn (a guaranteed-routable 2-net
board). Invariant tests: both nets route, the emitted SES parses, every
trace stays on a valid layer and within the board outline, and every
routed net's trace endpoints sit exactly on its two pads. An oracle-gated
test asserts connectivity parity with the reference FreeRouting JAR on
the simple board.