@tscircuit/schematic-trace-solver 0.0.8 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,6 +4,8 @@ Solve for the correct positions and routing for schematic traces and net labels.
4
4
 
5
5
  [Online Playground](https://schematic-trace-solver.vercel.app) ・ [tscircuit](https://github.com/tscircuit/tscircuit) ・ [@tscircuit/core](https://github.com/tscircuit/core)
6
6
 
7
+ <img width="1740" height="896" alt="image" src="https://github.com/user-attachments/assets/53032b97-d7b5-4a00-9eab-58b58e3adecc" />
8
+
7
9
  ## Overview
8
10
 
9
11
  The Schematic Trace Solver is a pipeline that figures out how to route schematic traces
package/dist/index.d.ts CHANGED
@@ -191,6 +191,9 @@ declare class SchematicTraceLinesSolver extends BaseSolver {
191
191
  chipMap: Record<string, InputChip>;
192
192
  currentConnectionPair: MspConnectionPair | null;
193
193
  solvedTracePaths: Array<SolvedTracePath>;
194
+ failedConnectionPairs: Array<MspConnectionPair & {
195
+ error?: string;
196
+ }>;
194
197
  activeSubSolver: SchematicTraceSingleLineSolver | null;
195
198
  constructor(params: {
196
199
  mspConnectionPairs: MspConnectionPair[];
@@ -370,6 +373,8 @@ declare class NetLabelPlacementSolver extends BaseSolver {
370
373
  queuedOverlappingSameNetTraceGroups: Array<OverlappingSameNetTraceGroup>;
371
374
  activeSubSolver: SingleNetLabelPlacementSolver | null;
372
375
  netLabelPlacements: Array<NetLabelPlacement>;
376
+ currentGroup: OverlappingSameNetTraceGroup | null;
377
+ triedAnyOrientationFallbackForCurrentGroup: boolean;
373
378
  constructor(params: {
374
379
  inputProblem: InputProblem;
375
380
  inputTraceMap: Record<MspConnectionPairId, SolvedTracePath>;
package/dist/index.js CHANGED
@@ -6694,12 +6694,33 @@ var SchematicTraceSingleLineSolver = class extends BaseSolver {
6694
6694
  return;
6695
6695
  }
6696
6696
  const nextCandidatePath = this.queuedCandidatePaths.shift();
6697
- const obstacleOps = {
6698
- excludeChipIds: [this.pins[0].chipId, this.pins[1].chipId]
6699
- };
6700
6697
  for (let i = 0; i < nextCandidatePath.length - 1; i++) {
6701
6698
  const start = nextCandidatePath[i];
6702
6699
  const end = nextCandidatePath[i + 1];
6700
+ let excludeChipIds = [];
6701
+ const isStartPin = this.pins.some(
6702
+ (pin) => Math.abs(pin.x - start.x) < 1e-10 && Math.abs(pin.y - start.y) < 1e-10
6703
+ );
6704
+ const isEndPin = this.pins.some(
6705
+ (pin) => Math.abs(pin.x - end.x) < 1e-10 && Math.abs(pin.y - end.y) < 1e-10
6706
+ );
6707
+ if (isStartPin) {
6708
+ const startPin = this.pins.find(
6709
+ (pin) => Math.abs(pin.x - start.x) < 1e-10 && Math.abs(pin.y - start.y) < 1e-10
6710
+ );
6711
+ if (startPin && !excludeChipIds.includes(startPin.chipId)) {
6712
+ excludeChipIds.push(startPin.chipId);
6713
+ }
6714
+ }
6715
+ if (isEndPin) {
6716
+ const endPin = this.pins.find(
6717
+ (pin) => Math.abs(pin.x - end.x) < 1e-10 && Math.abs(pin.y - end.y) < 1e-10
6718
+ );
6719
+ if (endPin && !excludeChipIds.includes(endPin.chipId)) {
6720
+ excludeChipIds.push(endPin.chipId);
6721
+ }
6722
+ }
6723
+ const obstacleOps = { excludeChipIds };
6703
6724
  const intersects = this.chipObstacleSpatialIndex.doesOrthogonalLineIntersectChip(
6704
6725
  [start, end],
6705
6726
  obstacleOps
@@ -6780,6 +6801,7 @@ var SchematicTraceLinesSolver = class extends BaseSolver {
6780
6801
  chipMap;
6781
6802
  currentConnectionPair = null;
6782
6803
  solvedTracePaths = [];
6804
+ failedConnectionPairs = [];
6783
6805
  constructor(params) {
6784
6806
  super();
6785
6807
  this.inputProblem = params.inputProblem;
@@ -6810,9 +6832,14 @@ var SchematicTraceLinesSolver = class extends BaseSolver {
6810
6832
  this.currentConnectionPair = null;
6811
6833
  }
6812
6834
  if (this.activeSubSolver?.failed) {
6813
- this.failed = true;
6814
- this.error = this.activeSubSolver.error;
6815
- return;
6835
+ if (this.currentConnectionPair) {
6836
+ this.failedConnectionPairs.push({
6837
+ ...this.currentConnectionPair,
6838
+ error: this.activeSubSolver.error || void 0
6839
+ });
6840
+ }
6841
+ this.activeSubSolver = null;
6842
+ this.currentConnectionPair = null;
6816
6843
  }
6817
6844
  if (this.activeSubSolver) {
6818
6845
  this.activeSubSolver.step();
@@ -6848,6 +6875,17 @@ var SchematicTraceLinesSolver = class extends BaseSolver {
6848
6875
  strokeColor: "green"
6849
6876
  });
6850
6877
  }
6878
+ for (const pair of this.failedConnectionPairs) {
6879
+ graphics.lines.push({
6880
+ points: [
6881
+ { x: pair.pins[0].x, y: pair.pins[0].y },
6882
+ { x: pair.pins[1].x, y: pair.pins[1].y }
6883
+ ],
6884
+ strokeColor: "red",
6885
+ strokeDash: "4 2",
6886
+ strokeWidth: 4e-3
6887
+ });
6888
+ }
6851
6889
  return graphics;
6852
6890
  }
6853
6891
  };
@@ -7642,6 +7680,8 @@ var NetLabelPlacementSolver = class extends BaseSolver {
7642
7680
  overlappingSameNetTraceGroups;
7643
7681
  queuedOverlappingSameNetTraceGroups;
7644
7682
  netLabelPlacements = [];
7683
+ currentGroup = null;
7684
+ triedAnyOrientationFallbackForCurrentGroup = false;
7645
7685
  constructor(params) {
7646
7686
  super();
7647
7687
  this.inputProblem = params.inputProblem;
@@ -7759,9 +7799,24 @@ var NetLabelPlacementSolver = class extends BaseSolver {
7759
7799
  if (this.activeSubSolver?.solved) {
7760
7800
  this.netLabelPlacements.push(this.activeSubSolver.netLabelPlacement);
7761
7801
  this.activeSubSolver = null;
7802
+ this.currentGroup = null;
7803
+ this.triedAnyOrientationFallbackForCurrentGroup = false;
7762
7804
  return;
7763
7805
  }
7764
7806
  if (this.activeSubSolver?.failed) {
7807
+ const fullOrients = ["x+", "x-", "y+", "y-"];
7808
+ const currOrients = this.activeSubSolver.availableOrientations;
7809
+ const isAlreadyFull = currOrients.length === 4 && fullOrients.every((o) => currOrients.includes(o));
7810
+ if (!this.triedAnyOrientationFallbackForCurrentGroup && !isAlreadyFull && this.currentGroup) {
7811
+ this.triedAnyOrientationFallbackForCurrentGroup = true;
7812
+ this.activeSubSolver = new SingleNetLabelPlacementSolver({
7813
+ inputProblem: this.inputProblem,
7814
+ inputTraceMap: this.inputTraceMap,
7815
+ overlappingSameNetTraceGroup: this.currentGroup,
7816
+ availableOrientations: fullOrients
7817
+ });
7818
+ return;
7819
+ }
7765
7820
  this.failed = true;
7766
7821
  this.error = this.activeSubSolver.error;
7767
7822
  return;
@@ -7776,6 +7831,8 @@ var NetLabelPlacementSolver = class extends BaseSolver {
7776
7831
  return;
7777
7832
  }
7778
7833
  const netId = nextOverlappingSameNetTraceGroup.netId ?? nextOverlappingSameNetTraceGroup.globalConnNetId;
7834
+ this.currentGroup = nextOverlappingSameNetTraceGroup;
7835
+ this.triedAnyOrientationFallbackForCurrentGroup = false;
7779
7836
  this.activeSubSolver = new SingleNetLabelPlacementSolver({
7780
7837
  inputProblem: this.inputProblem,
7781
7838
  inputTraceMap: this.inputTraceMap,
@@ -60,6 +60,8 @@ export class NetLabelPlacementSolver extends BaseSolver {
60
60
  declare activeSubSolver: SingleNetLabelPlacementSolver | null
61
61
 
62
62
  netLabelPlacements: Array<NetLabelPlacement> = []
63
+ currentGroup: OverlappingSameNetTraceGroup | null = null
64
+ triedAnyOrientationFallbackForCurrentGroup = false
63
65
 
64
66
  constructor(params: {
65
67
  inputProblem: InputProblem
@@ -209,10 +211,34 @@ export class NetLabelPlacementSolver extends BaseSolver {
209
211
  if (this.activeSubSolver?.solved) {
210
212
  this.netLabelPlacements.push(this.activeSubSolver.netLabelPlacement!)
211
213
  this.activeSubSolver = null
214
+ this.currentGroup = null
215
+ this.triedAnyOrientationFallbackForCurrentGroup = false
212
216
  return
213
217
  }
214
218
 
215
219
  if (this.activeSubSolver?.failed) {
220
+ // Retry once with all orientations as a fallback before failing
221
+ const fullOrients: FacingDirection[] = ["x+", "x-", "y+", "y-"]
222
+ const currOrients = this.activeSubSolver.availableOrientations
223
+ const isAlreadyFull =
224
+ currOrients.length === 4 &&
225
+ fullOrients.every((o) => currOrients.includes(o))
226
+
227
+ if (
228
+ !this.triedAnyOrientationFallbackForCurrentGroup &&
229
+ !isAlreadyFull &&
230
+ this.currentGroup
231
+ ) {
232
+ this.triedAnyOrientationFallbackForCurrentGroup = true
233
+ this.activeSubSolver = new SingleNetLabelPlacementSolver({
234
+ inputProblem: this.inputProblem,
235
+ inputTraceMap: this.inputTraceMap,
236
+ overlappingSameNetTraceGroup: this.currentGroup,
237
+ availableOrientations: fullOrients,
238
+ })
239
+ return
240
+ }
241
+
216
242
  this.failed = true
217
243
  this.error = this.activeSubSolver.error
218
244
  return
@@ -235,6 +261,9 @@ export class NetLabelPlacementSolver extends BaseSolver {
235
261
  nextOverlappingSameNetTraceGroup.netId ??
236
262
  nextOverlappingSameNetTraceGroup.globalConnNetId
237
263
 
264
+ this.currentGroup = nextOverlappingSameNetTraceGroup
265
+ this.triedAnyOrientationFallbackForCurrentGroup = false
266
+
238
267
  this.activeSubSolver = new SingleNetLabelPlacementSolver({
239
268
  inputProblem: this.inputProblem,
240
269
  inputTraceMap: this.inputTraceMap,
@@ -30,6 +30,7 @@ export class SchematicTraceLinesSolver extends BaseSolver {
30
30
  currentConnectionPair: MspConnectionPair | null = null
31
31
 
32
32
  solvedTracePaths: Array<SolvedTracePath> = []
33
+ failedConnectionPairs: Array<MspConnectionPair & { error?: string }> = []
33
34
 
34
35
  declare activeSubSolver: SchematicTraceSingleLineSolver | null
35
36
 
@@ -75,9 +76,16 @@ export class SchematicTraceLinesSolver extends BaseSolver {
75
76
  this.currentConnectionPair = null
76
77
  }
77
78
  if (this.activeSubSolver?.failed) {
78
- this.failed = true
79
- this.error = this.activeSubSolver.error
80
- return
79
+ // Record the failure for this connection and continue to the next pair
80
+ if (this.currentConnectionPair) {
81
+ this.failedConnectionPairs.push({
82
+ ...this.currentConnectionPair,
83
+ error: this.activeSubSolver.error || undefined,
84
+ })
85
+ }
86
+ this.activeSubSolver = null
87
+ this.currentConnectionPair = null
88
+ // Do not fail the whole solver; proceed to schedule the next pair
81
89
  }
82
90
 
83
91
  if (this.activeSubSolver) {
@@ -122,6 +130,19 @@ export class SchematicTraceLinesSolver extends BaseSolver {
122
130
  })
123
131
  }
124
132
 
133
+ // Indicate failed connection pairs with dashed red lines between their pins
134
+ for (const pair of this.failedConnectionPairs) {
135
+ graphics.lines!.push({
136
+ points: [
137
+ { x: pair.pins[0].x, y: pair.pins[0].y },
138
+ { x: pair.pins[1].x, y: pair.pins[1].y },
139
+ ],
140
+ strokeColor: "red",
141
+ strokeDash: "4 2",
142
+ strokeWidth: 0.004,
143
+ })
144
+ }
145
+
125
146
  return graphics
126
147
  }
127
148
  }
@@ -103,12 +103,47 @@ export class SchematicTraceSingleLineSolver extends BaseSolver {
103
103
 
104
104
  const nextCandidatePath = this.queuedCandidatePaths.shift()!
105
105
 
106
- const obstacleOps = {
107
- excludeChipIds: [this.pins[0].chipId, this.pins[1].chipId],
108
- }
109
106
  for (let i = 0; i < nextCandidatePath.length - 1; i++) {
110
107
  const start = nextCandidatePath[i]
111
108
  const end = nextCandidatePath[i + 1]
109
+
110
+ // Determine which chips to exclude for this specific segment
111
+ let excludeChipIds: string[] = []
112
+
113
+ // Always exclude chips that contain the start or end points of this segment
114
+ // if those points are actually pin locations
115
+ const isStartPin = this.pins.some(
116
+ (pin) =>
117
+ Math.abs(pin.x - start.x) < 1e-10 &&
118
+ Math.abs(pin.y - start.y) < 1e-10,
119
+ )
120
+ const isEndPin = this.pins.some(
121
+ (pin) =>
122
+ Math.abs(pin.x - end.x) < 1e-10 && Math.abs(pin.y - end.y) < 1e-10,
123
+ )
124
+
125
+ if (isStartPin) {
126
+ const startPin = this.pins.find(
127
+ (pin) =>
128
+ Math.abs(pin.x - start.x) < 1e-10 &&
129
+ Math.abs(pin.y - start.y) < 1e-10,
130
+ )
131
+ if (startPin && !excludeChipIds.includes(startPin.chipId)) {
132
+ excludeChipIds.push(startPin.chipId)
133
+ }
134
+ }
135
+
136
+ if (isEndPin) {
137
+ const endPin = this.pins.find(
138
+ (pin) =>
139
+ Math.abs(pin.x - end.x) < 1e-10 && Math.abs(pin.y - end.y) < 1e-10,
140
+ )
141
+ if (endPin && !excludeChipIds.includes(endPin.chipId)) {
142
+ excludeChipIds.push(endPin.chipId)
143
+ }
144
+ }
145
+
146
+ const obstacleOps = { excludeChipIds }
112
147
  const intersects =
113
148
  this.chipObstacleSpatialIndex.doesOrthogonalLineIntersectChip(
114
149
  [start, end],
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tscircuit/schematic-trace-solver",
3
3
  "main": "dist/index.js",
4
- "version": "0.0.8",
4
+ "version": "0.0.10",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "start": "cosmos",
@@ -0,0 +1,122 @@
1
+ import { useMemo } from "react"
2
+ import { GenericSolverDebugger } from "../components/GenericSolverDebugger"
3
+ import { SchematicTraceLinesSolver } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
4
+
5
+ const input = {
6
+ mspConnectionPairs: [
7
+ {
8
+ mspPairId: "Q1.1-Q1.2",
9
+ dcConnNetId: "connectivity_net0",
10
+ globalConnNetId: "connectivity_net0",
11
+ userNetId: "V3_3",
12
+ pins: [
13
+ {
14
+ pinId: "Q1.1",
15
+ x: 0.30397715550000004,
16
+ y: 0.5800832909999993,
17
+ _facingDirection: "y+",
18
+ chipId: "schematic_component_0",
19
+ },
20
+ {
21
+ pinId: "Q1.2",
22
+ x: 0.31067575550000137,
23
+ y: -0.5800832909999993,
24
+ _facingDirection: "y-",
25
+ chipId: "schematic_component_0",
26
+ },
27
+ ],
28
+ },
29
+ ],
30
+ dcConnMap: {
31
+ netMap: {
32
+ connectivity_net0: ["Q1.1", "Q1.2"],
33
+ },
34
+ idToNetMap: {},
35
+ },
36
+ globalConnMap: {
37
+ netMap: {
38
+ connectivity_net0: ["Q1.1", "Q1.2"],
39
+ },
40
+ idToNetMap: {
41
+ "Q1.1": "connectivity_net0",
42
+ "Q1.2": "connectivity_net0",
43
+ },
44
+ },
45
+ inputProblem: {
46
+ chips: [
47
+ {
48
+ chipId: "schematic_component_0",
49
+ center: {
50
+ x: 0,
51
+ y: 0,
52
+ },
53
+ width: 0.8935117710000002,
54
+ height: 1.1601665819999987,
55
+ pins: [
56
+ {
57
+ pinId: "Q1.1",
58
+ x: 0.30397715550000004,
59
+ y: 0.5800832909999993,
60
+ },
61
+ {
62
+ pinId: "Q1.2",
63
+ x: 0.31067575550000137,
64
+ y: -0.5800832909999993,
65
+ },
66
+ {
67
+ pinId: "Q1.3",
68
+ x: -0.4467558855000001,
69
+ y: -0.10250625000000019,
70
+ },
71
+ ],
72
+ },
73
+ ],
74
+ directConnections: [],
75
+ netConnections: [
76
+ {
77
+ netId: "V3_3",
78
+ pinIds: ["Q1.1", "Q1.2"],
79
+ },
80
+ ],
81
+ availableNetLabelOrientations: {
82
+ V3_3: ["y+"],
83
+ },
84
+ maxMspPairDistance: 2,
85
+ },
86
+ guidelines: [],
87
+ chipMap: {
88
+ schematic_component_0: {
89
+ chipId: "schematic_component_0",
90
+ center: {
91
+ x: 0,
92
+ y: 0,
93
+ },
94
+ width: 0.8935117710000002,
95
+ height: 1.1601665819999987,
96
+ pins: [
97
+ {
98
+ pinId: "Q1.1",
99
+ x: 0.30397715550000004,
100
+ y: 0.5800832909999993,
101
+ },
102
+ {
103
+ pinId: "Q1.2",
104
+ x: 0.31067575550000137,
105
+ y: -0.5800832909999993,
106
+ },
107
+ {
108
+ pinId: "Q1.3",
109
+ x: -0.4467558855000001,
110
+ y: -0.10250625000000019,
111
+ },
112
+ ],
113
+ },
114
+ },
115
+ }
116
+
117
+ export default () => {
118
+ const solver = useMemo(() => {
119
+ return new SchematicTraceLinesSolver(input as any)
120
+ }, [])
121
+ return <GenericSolverDebugger solver={solver} />
122
+ }
@@ -0,0 +1,16 @@
1
+ import type { BaseSolver } from "lib/solvers/BaseSolver/BaseSolver"
2
+ import type { InputProblem } from "lib/types/InputProblem"
3
+ import { useMemo, useReducer } from "react"
4
+ import { InteractiveGraphics } from "graphics-debug/react"
5
+ import { SolverToolbar } from "./SolverToolbar"
6
+
7
+ export const GenericSolverDebugger = ({ solver }: { solver: BaseSolver }) => {
8
+ const [, incRenderCount] = useReducer((x) => x + 1, 0)
9
+
10
+ return (
11
+ <div>
12
+ <SolverToolbar triggerRender={() => incRenderCount()} solver={solver} />
13
+ <InteractiveGraphics graphics={solver.visualize()} />
14
+ </div>
15
+ )
16
+ }
@@ -0,0 +1,46 @@
1
+ import { PipelineDebugger } from "../components/PipelineDebugger"
2
+ import type { InputProblem } from "lib/types/InputProblem"
3
+
4
+ const inputProblem: InputProblem = {
5
+ chips: [
6
+ {
7
+ chipId: "schematic_component_0",
8
+ center: {
9
+ x: 0,
10
+ y: 0,
11
+ },
12
+ width: 0.8935117710000002,
13
+ height: 1.1601665819999987,
14
+ pins: [
15
+ {
16
+ pinId: "Q1.1",
17
+ x: 0.30397715550000004,
18
+ y: 0.5519248499999994,
19
+ },
20
+ {
21
+ pinId: "Q1.2",
22
+ x: 0.31067575550000137,
23
+ y: -0.5519248499999994,
24
+ },
25
+ {
26
+ pinId: "Q1.3",
27
+ x: -0.41859744450000014,
28
+ y: -0.10250625000000019,
29
+ },
30
+ ],
31
+ },
32
+ ],
33
+ directConnections: [],
34
+ netConnections: [
35
+ {
36
+ netId: "V3_3",
37
+ pinIds: ["Q1.1", "Q1.2"],
38
+ },
39
+ ],
40
+ availableNetLabelOrientations: {
41
+ V3_3: ["y+"],
42
+ },
43
+ maxMspPairDistance: 2,
44
+ }
45
+
46
+ export default () => <PipelineDebugger inputProblem={inputProblem} />
@@ -0,0 +1,88 @@
1
+ {
2
+ "chipMap": {
3
+ "schematic_component_0": {
4
+ "chipId": "schematic_component_0",
5
+ "center": {
6
+ "x": 0,
7
+ "y": 0
8
+ },
9
+ "width": 0.8935117710000002,
10
+ "height": 1.1601665819999987,
11
+ "pins": [
12
+ {
13
+ "pinId": "Q1.1",
14
+ "x": 0.30397715550000004,
15
+ "y": 0.5800832909999993
16
+ },
17
+ {
18
+ "pinId": "Q1.2",
19
+ "x": 0.31067575550000137,
20
+ "y": -0.5800832909999993
21
+ },
22
+ {
23
+ "pinId": "Q1.3",
24
+ "x": -0.4467558855000001,
25
+ "y": -0.10250625000000019
26
+ }
27
+ ]
28
+ }
29
+ },
30
+ "pins": [
31
+ {
32
+ "pinId": "Q1.1",
33
+ "x": 0.30397715550000004,
34
+ "y": 0.5800832909999993,
35
+ "_facingDirection": "y+",
36
+ "chipId": "schematic_component_0"
37
+ },
38
+ {
39
+ "pinId": "Q1.2",
40
+ "x": 0.31067575550000137,
41
+ "y": -0.5800832909999993,
42
+ "_facingDirection": "y-",
43
+ "chipId": "schematic_component_0"
44
+ }
45
+ ],
46
+ "guidelines": [],
47
+ "inputProblem": {
48
+ "chips": [
49
+ {
50
+ "chipId": "schematic_component_0",
51
+ "center": {
52
+ "x": 0,
53
+ "y": 0
54
+ },
55
+ "width": 0.8935117710000002,
56
+ "height": 1.1601665819999987,
57
+ "pins": [
58
+ {
59
+ "pinId": "Q1.1",
60
+ "x": 0.30397715550000004,
61
+ "y": 0.5800832909999993
62
+ },
63
+ {
64
+ "pinId": "Q1.2",
65
+ "x": 0.31067575550000137,
66
+ "y": -0.5800832909999993
67
+ },
68
+ {
69
+ "pinId": "Q1.3",
70
+ "x": -0.4467558855000001,
71
+ "y": -0.10250625000000019
72
+ }
73
+ ]
74
+ }
75
+ ],
76
+ "directConnections": [],
77
+ "netConnections": [
78
+ {
79
+ "netId": "V3_3",
80
+ "pinIds": ["Q1.1", "Q1.2"]
81
+ }
82
+ ],
83
+ "availableNetLabelOrientations": {
84
+ "V3_3": ["y+"]
85
+ },
86
+ "maxMspPairDistance": 2
87
+ }
88
+ }
@@ -0,0 +1,16 @@
1
+ import { test, expect } from "bun:test"
2
+ import input from "./SchematicTraceSingleLineSolver_repro01.json"
3
+ import { SchematicTraceSingleLineSolver } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver/SchematicTraceSingleLineSolver"
4
+
5
+ test("SchematicTraceSingleLineSolver_repro01", () => {
6
+ const solver = new SchematicTraceSingleLineSolver(input as any)
7
+ solver.solve()
8
+
9
+ // The solver should fail because it cannot find a path around the chip
10
+ // without guidelines to help navigate around it
11
+ expect(solver.failed).toBe(true)
12
+ expect(solver.error).toBe(
13
+ "No more candidate elbows, everything had collisions",
14
+ )
15
+ expect(solver.solvedTracePath).toBe(null)
16
+ })