@tscircuit/curvy-trace-solver 0.0.2 → 0.0.4

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.
@@ -1,66 +0,0 @@
1
- import type { GraphicsObject } from "graphics-debug"
2
- import type { CurvyTraceProblem, OutputTrace } from "../types"
3
- import { getColorForNetworkId } from "./index"
4
-
5
- export const visualizeCurvyTraceProblem = (
6
- problem: CurvyTraceProblem,
7
- outputTraces: OutputTrace[] = [],
8
- ): GraphicsObject => {
9
- const graphics = {
10
- arrows: [],
11
- circles: [],
12
- lines: [],
13
- rects: [],
14
- coordinateSystem: "cartesian",
15
- points: [],
16
- texts: [],
17
- title: "Curvy Trace Problem",
18
- } as Required<GraphicsObject>
19
-
20
- // Draw bounds
21
- graphics.lines.push({
22
- points: [
23
- { x: problem.bounds.minX, y: problem.bounds.minY },
24
- { x: problem.bounds.maxX, y: problem.bounds.minY },
25
- { x: problem.bounds.maxX, y: problem.bounds.maxY },
26
- { x: problem.bounds.minX, y: problem.bounds.maxY },
27
- { x: problem.bounds.minX, y: problem.bounds.minY },
28
- ],
29
- strokeColor: "rgba(0, 0, 0, 0.1)",
30
- })
31
-
32
- // Draw waypoint pairs
33
- for (const waypointPair of problem.waypointPairs) {
34
- graphics.points.push({
35
- ...waypointPair.start,
36
- label: `start ${waypointPair.networkId ?? ""}`,
37
- color: getColorForNetworkId(waypointPair.networkId),
38
- })
39
- graphics.points.push({
40
- ...waypointPair.end,
41
- label: `end ${waypointPair.networkId ?? ""}`,
42
- color: getColorForNetworkId(waypointPair.networkId),
43
- })
44
- }
45
-
46
- // Draw obstacles
47
- for (const obstacle of problem.obstacles) {
48
- graphics.rects.push({
49
- center: obstacle.center,
50
- width: obstacle.maxX - obstacle.minX,
51
- height: obstacle.maxY - obstacle.minY,
52
- fill: "rgba(128, 128, 128, 0.3)",
53
- stroke: "rgba(128, 128, 128, 0.8)",
54
- })
55
- }
56
-
57
- // Draw output traces
58
- for (const trace of outputTraces) {
59
- graphics.lines.push({
60
- points: trace.points,
61
- strokeColor: getColorForNetworkId(trace.networkId),
62
- })
63
- }
64
-
65
- return graphics
66
- }
@@ -1,85 +0,0 @@
1
- import { CurvyTraceSolver } from "../../lib/CurvyTraceSolver"
2
- import { generateRandomProblem } from "../../lib/problem-generator"
3
- import { scoreOutputCost } from "../../lib/scoreOutputCost"
4
-
5
- const NUM_PROBLEMS = 25
6
- const MIN_WAYPOINT_PAIRS = 2
7
- const MAX_WAYPOINT_PAIRS = 12
8
-
9
- function runBenchmark() {
10
- const scores: number[] = []
11
- const startTime = performance.now()
12
-
13
- console.log(`Running benchmark with ${NUM_PROBLEMS} problems...`)
14
- console.log(
15
- `Waypoint pairs range: ${MIN_WAYPOINT_PAIRS} to ${MAX_WAYPOINT_PAIRS}\n`,
16
- )
17
-
18
- for (let i = 0; i < NUM_PROBLEMS; i++) {
19
- const numWaypointPairs =
20
- MIN_WAYPOINT_PAIRS +
21
- Math.floor(Math.random() * (MAX_WAYPOINT_PAIRS - MIN_WAYPOINT_PAIRS + 1))
22
-
23
- const problem = generateRandomProblem({
24
- randomSeed: i,
25
- numWaypointPairs,
26
- numObstacles: 2,
27
- minSpacing: 5,
28
- })
29
-
30
- const solver = new CurvyTraceSolver(problem)
31
-
32
- // Run solver until complete (with max iterations to prevent infinite loops)
33
- const MAX_ITERATIONS = 1000
34
- for (let iter = 0; iter < MAX_ITERATIONS && !solver.solved; iter++) {
35
- solver.step()
36
- }
37
-
38
- const score = scoreOutputCost({
39
- problem,
40
- outputTraces: solver.outputTraces,
41
- })
42
-
43
- scores.push(score)
44
-
45
- // Progress indicator for each problem
46
- process.stdout.write(
47
- `\r Progress: ${i + 1}/${NUM_PROBLEMS} problems completed`,
48
- )
49
- }
50
- console.log() // New line after progress
51
-
52
- const endTime = performance.now()
53
- const totalTimeMs = endTime - startTime
54
-
55
- // Calculate statistics
56
- const sortedScores = [...scores].sort((a, b) => a - b)
57
- const averageScore = scores.reduce((a, b) => a + b, 0) / scores.length
58
-
59
- // P95 worst score (95th percentile - higher scores are worse)
60
- const p95Index = Math.ceil(scores.length * 0.95) - 1
61
- const p95WorstScore = sortedScores[p95Index]
62
-
63
- // Additional stats
64
- const minScore = sortedScores[0]
65
- const maxScore = sortedScores[sortedScores.length - 1]
66
- const medianScore = sortedScores[Math.floor(scores.length / 2)]
67
-
68
- console.log("\n" + "=".repeat(50))
69
- console.log("BENCHMARK RESULTS")
70
- console.log("=".repeat(50))
71
- console.log(`Total problems: ${NUM_PROBLEMS}`)
72
- console.log(`Total time: ${(totalTimeMs / 1000).toFixed(2)}s`)
73
- console.log(
74
- `Avg time/problem: ${(totalTimeMs / NUM_PROBLEMS).toFixed(2)}ms`,
75
- )
76
- console.log("-".repeat(50))
77
- console.log(`Average score: ${averageScore.toFixed(2)}`)
78
- console.log(`P95 worst score: ${p95WorstScore.toFixed(2)}`)
79
- console.log(`Median score: ${medianScore.toFixed(2)}`)
80
- console.log(`Min score (best): ${minScore.toFixed(2)}`)
81
- console.log(`Max score (worst): ${maxScore.toFixed(2)}`)
82
- console.log("=".repeat(50))
83
- }
84
-
85
- runBenchmark()
@@ -1,3 +0,0 @@
1
- <svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
2
- <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
3
- </svg>
@@ -1,44 +0,0 @@
1
- <svg width="640" height="640" viewBox="0 0 640 640" xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="white"/><g><circle data-type="point" data-label="start " data-x="0" data-y="10" cx="40" cy="544" r="3" fill="rgba(0, 0, 0, 0.5)"/></g><g><circle data-type="point" data-label="end " data-x="100" data-y="80" cx="600" cy="152" r="3" fill="rgba(0, 0, 0, 0.5)"/></g><g><circle data-type="point" data-label="start " data-x="0" data-y="20" cx="40" cy="488" r="3" fill="rgba(0, 0, 0, 0.5)"/></g><g><circle data-type="point" data-label="end " data-x="100" data-y="90" cx="600" cy="96.00000000000006" r="3" fill="rgba(0, 0, 0, 0.5)"/></g><g><polyline data-points="0,0 100,0 100,100 0,100 0,0" data-type="line" data-label="" points="40,600 600,600 600,40 40,40 40,600" fill="none" stroke="rgba(0, 0, 0, 0.1)" stroke-width="1px"/></g><g><polyline data-points="0,10 6.326174941286477,8.976501626718612 12.606449079429792,8.447595421742497 18.825206321247016,8.41020897760465 24.966830573555256,8.86126988683809 31.01570574317155,9.797705741975811 36.95621573691301,11.216444135550823 42.772744461596716,13.114412660096136 48.44967582403974,15.488538908144754 53.97139373105915,18.335750472229684 59.32228208947204,21.65297494488392 64.48672480609551,25.437139918640487 69.44910578774659,29.685172986032377 74.19380894124241,34.3940017395926 78.7052181734,39.56055377185415 82.9677173910365,45.18175667535007 86.96569050096898,51.25453804261333 90.68352141001446,57.77582546617694 94.10559402499008,64.74254653857393 97.21629225271289,72.15162885233727 100,80" data-type="line" data-label="" points="40,544 75.42657967120428,549.7315908903757 110.59611484480683,552.6934656382421 145.42115539898327,552.902829725414 179.81425121190944,550.3768886337067 213.68795216176068,545.1328478449354 246.95480812671283,537.1879128409154 279.52736898494163,526.5592891034617 311.3181846146225,513.2641821143894 342.23980489393125,497.31979735551374 372.2047797010434,478.7433403086501 401.1256589141348,457.5520164556133 428.91499241138087,433.7630312782187 455.48533007095745,407.3935902582814 480.74922177103997,378.4608988776167 504.61921738980436,346.98216261803964 527.0078668054261,312.97458696136533 547.8277198960809,276.45537738940914 566.9913265399445,237.44173938398598 584.4112366151921,195.95087842691134 600,152" fill="none" stroke="rgba(0, 0, 0, 0.5)" stroke-width="1px"/></g><g><polyline data-points="0,20 1.8621602472871017,27.842208022662724 4.184225975009922,35.25569846142608 6.94459608998554,42.23574515882305 10.121669499031041,48.777621957386685 13.693845108963494,54.876602699649936 17.63952182659999,60.527961228145834 21.9370985587576,65.72697138540741 26.564974212253425,70.46890701396764 31.501547693904516,74.74904195635953 36.725217910527974,78.56265005511608 42.21438376894088,81.90500515277033 47.947444175960285,84.77138109185526 53.902798038403304,87.15705171490386 60.05884426308699,89.05729086444917 66.39398175682845,90.46737238302418 72.88660942644478,91.38257011316193 79.51512617875298,91.79815789739534 86.25793092057022,91.70940957825752 93.09342255871351,91.1115989982814 100,90" data-type="line" data-label="" points="40,488 50.42809738480777,444.0836350730888 63.43166546005556,402.56808861601394 78.88973810391903,363.4798271105909 96.68134919457383,326.84531703863456 116.68553261019557,292.6910248819604 138.78132222895994,261.04341712238335 162.84775192904254,231.92896024171853 188.76385558861918,205.37412072178125 216.4086670858653,181.40536504438666 245.66122029895664,160.04915969134998 276.40054910606887,141.3319711444862 308.5056873853776,125.28026588561056 341.8556690150585,111.92051039653842 376.32952787328713,101.27917115908468 411.8062978382393,93.3827146550646 448.16501278809073,88.2576073662932 485.28470660101664,85.93031577458612 523.0444131551932,86.42730636175793 561.3231663287957,89.77504560962421 600,96.00000000000006" fill="none" stroke="rgba(0, 0, 0, 0.5)" stroke-width="1px"/></g><g id="crosshair" style="display: none"><line id="crosshair-h" y1="0" y2="640" stroke="#666" stroke-width="0.5"/><line id="crosshair-v" x1="0" x2="640" stroke="#666" stroke-width="0.5"/><text id="coordinates" font-family="monospace" font-size="12" fill="#666"></text></g><script><![CDATA[
2
- document.currentScript.parentElement.addEventListener('mousemove', (e) => {
3
- const svg = e.currentTarget;
4
- const rect = svg.getBoundingClientRect();
5
- const x = e.clientX - rect.left;
6
- const y = e.clientY - rect.top;
7
- const crosshair = svg.getElementById('crosshair');
8
- const h = svg.getElementById('crosshair-h');
9
- const v = svg.getElementById('crosshair-v');
10
- const coords = svg.getElementById('coordinates');
11
-
12
- crosshair.style.display = 'block';
13
- h.setAttribute('x1', '0');
14
- h.setAttribute('x2', '640');
15
- h.setAttribute('y1', y);
16
- h.setAttribute('y2', y);
17
- v.setAttribute('x1', x);
18
- v.setAttribute('x2', x);
19
- v.setAttribute('y1', '0');
20
- v.setAttribute('y2', '640');
21
-
22
- // Calculate real coordinates using inverse transformation
23
- const matrix = {"a":5.6,"c":0,"e":40,"b":0,"d":-5.6,"f":600};
24
- // Manually invert and apply the affine transform
25
- // Since we only use translate and scale, we can directly compute:
26
- // x' = (x - tx) / sx
27
- // y' = (y - ty) / sy
28
- const sx = matrix.a;
29
- const sy = matrix.d;
30
- const tx = matrix.e;
31
- const ty = matrix.f;
32
- const realPoint = {
33
- x: (x - tx) / sx,
34
- y: (y - ty) / sy // Flip y back since we used negative scale
35
- }
36
-
37
- coords.textContent = `(${realPoint.x.toFixed(2)}, ${realPoint.y.toFixed(2)})`;
38
- coords.setAttribute('x', (x + 5).toString());
39
- coords.setAttribute('y', (y - 5).toString());
40
- });
41
- document.currentScript.parentElement.addEventListener('mouseleave', () => {
42
- document.currentScript.parentElement.getElementById('crosshair').style.display = 'none';
43
- });
44
- ]]></script></svg>
@@ -1,12 +0,0 @@
1
- import { expect, test } from "bun:test"
2
- import { getSvgFromGraphicsObject } from "graphics-debug"
3
- import { CurvyTraceSolver } from "lib/CurvyTraceSolver"
4
- import problem from "fixtures/basics/basics01-input.json"
5
- import type { CurvyTraceProblem } from "lib/types"
6
-
7
- test("basics01", () => {
8
- const solver = new CurvyTraceSolver(problem as CurvyTraceProblem)
9
- solver.solve()
10
- const svg = getSvgFromGraphicsObject(solver.visualize())
11
- expect(svg).toMatchSvgSnapshot(import.meta.path)
12
- })
@@ -1 +0,0 @@
1
- import "bun-match-svg"
package/tests/svg.test.ts DELETED
@@ -1,12 +0,0 @@
1
- import { expect, test } from "bun:test"
2
-
3
- const testSvg = `<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
4
- <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
5
- </svg>`
6
-
7
- test("svg snapshot example", async () => {
8
- // First run will create the snapshot
9
- // Subsequent runs will compare against the saved snapshot
10
- await expect(testSvg).toMatchSvgSnapshot(import.meta.path)
11
- })
12
-
package/tsconfig.json DELETED
@@ -1,35 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- // Environment setup & latest features
4
- "lib": ["ESNext", "DOM"],
5
- "target": "ESNext",
6
- "module": "Preserve",
7
- "moduleDetection": "force",
8
- "jsx": "react-jsx",
9
- "allowJs": true,
10
- "baseUrl": ".",
11
- "paths": {
12
- "lib/*": ["./lib/*"],
13
- "fixtures/*": ["./fixtures/*"],
14
- "tests/*": ["./tests/*"]
15
- },
16
-
17
- // Bundler mode
18
- "moduleResolution": "bundler",
19
- "allowImportingTsExtensions": true,
20
- "verbatimModuleSyntax": true,
21
- "noEmit": true,
22
-
23
- // Best practices
24
- "strict": true,
25
- "skipLibCheck": true,
26
- "noFallthroughCasesInSwitch": true,
27
- "noUncheckedIndexedAccess": false,
28
- "noImplicitOverride": true,
29
-
30
- // Some stricter flags (disabled by default)
31
- "noUnusedLocals": false,
32
- "noUnusedParameters": false,
33
- "noPropertyAccessFromIndexSignature": false
34
- }
35
- }