astar-visualizer 1.0.0

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 ADDED
@@ -0,0 +1,54 @@
1
+ # A* Pathfinding Visualizer
2
+
3
+ A React component for visualizing the A* pathfinding algorithm with an interactive grid interface.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install astar-visualizer
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```tsx
14
+ import { AStarVisualizer } from 'astar-visualizer';
15
+ import 'astar-visualizer/style.css';
16
+
17
+ function App() {
18
+ return (
19
+ <div>
20
+ <AStarVisualizer />
21
+ </div>
22
+ );
23
+ }
24
+
25
+ export default App;
26
+ ```
27
+
28
+ ## Features
29
+
30
+ - Interactive grid for setting start/end points and obstacles
31
+ - Real-time visualization of the A* algorithm
32
+ - Customizable grid size
33
+ - Control panel for algorithm execution
34
+ - Smooth animations with Framer Motion
35
+
36
+ ## Development
37
+
38
+ ```bash
39
+ # Install dependencies
40
+ npm install
41
+
42
+ # Run development server
43
+ npm run dev
44
+
45
+ # Build library for publishing
46
+ npm run build:lib
47
+
48
+ # Run tests
49
+ npm test
50
+ ```
51
+
52
+ ## License
53
+
54
+ MIT
@@ -0,0 +1,791 @@
1
+ import { jsx as S, jsxs as y } from "react/jsx-runtime";
2
+ import D, { useState as H, useEffect as $ } from "react";
3
+ const P = (e) => {
4
+ let t;
5
+ const r = /* @__PURE__ */ new Set(), l = (c, f) => {
6
+ const u = typeof c == "function" ? c(t) : c;
7
+ if (!Object.is(u, t)) {
8
+ const s = t;
9
+ t = f ?? (typeof u != "object" || u === null) ? u : Object.assign({}, t, u), r.forEach((a) => a(t, s));
10
+ }
11
+ }, o = () => t, g = { setState: l, getState: o, getInitialState: () => d, subscribe: (c) => (r.add(c), () => r.delete(c)), destroy: () => {
12
+ r.clear();
13
+ } }, d = t = e(l, o, g);
14
+ return g;
15
+ }, U = (e) => e ? P(e) : P;
16
+ function q(e) {
17
+ return e && e.__esModule && Object.prototype.hasOwnProperty.call(e, "default") ? e.default : e;
18
+ }
19
+ var V = { exports: {} }, R = {}, L = { exports: {} }, A = {};
20
+ /**
21
+ * @license React
22
+ * use-sync-external-store-shim.production.js
23
+ *
24
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
25
+ *
26
+ * This source code is licensed under the MIT license found in the
27
+ * LICENSE file in the root directory of this source tree.
28
+ */
29
+ var x;
30
+ function J() {
31
+ if (x)
32
+ return A;
33
+ x = 1;
34
+ var e = D;
35
+ function t(f, u) {
36
+ return f === u && (f !== 0 || 1 / f === 1 / u) || f !== f && u !== u;
37
+ }
38
+ var r = typeof Object.is == "function" ? Object.is : t, l = e.useState, o = e.useEffect, i = e.useLayoutEffect, m = e.useDebugValue;
39
+ function p(f, u) {
40
+ var s = u(), a = l({ inst: { value: s, getSnapshot: u } }), n = a[0].inst, v = a[1];
41
+ return i(
42
+ function() {
43
+ n.value = s, n.getSnapshot = u, g(n) && v({ inst: n });
44
+ },
45
+ [f, s, u]
46
+ ), o(
47
+ function() {
48
+ return g(n) && v({ inst: n }), f(function() {
49
+ g(n) && v({ inst: n });
50
+ });
51
+ },
52
+ [f]
53
+ ), m(s), s;
54
+ }
55
+ function g(f) {
56
+ var u = f.getSnapshot;
57
+ f = f.value;
58
+ try {
59
+ var s = u();
60
+ return !r(f, s);
61
+ } catch {
62
+ return !0;
63
+ }
64
+ }
65
+ function d(f, u) {
66
+ return u();
67
+ }
68
+ var c = typeof window > "u" || typeof window.document > "u" || typeof window.document.createElement > "u" ? d : p;
69
+ return A.useSyncExternalStore = e.useSyncExternalStore !== void 0 ? e.useSyncExternalStore : c, A;
70
+ }
71
+ var M = {};
72
+ /**
73
+ * @license React
74
+ * use-sync-external-store-shim.development.js
75
+ *
76
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
77
+ *
78
+ * This source code is licensed under the MIT license found in the
79
+ * LICENSE file in the root directory of this source tree.
80
+ */
81
+ var B;
82
+ function Y() {
83
+ return B || (B = 1, process.env.NODE_ENV !== "production" && function() {
84
+ function e(s, a) {
85
+ return s === a && (s !== 0 || 1 / s === 1 / a) || s !== s && a !== a;
86
+ }
87
+ function t(s, a) {
88
+ c || o.startTransition === void 0 || (c = !0, console.error(
89
+ "You are using an outdated, pre-release alpha of React 18 that does not support useSyncExternalStore. The use-sync-external-store shim will not work correctly. Upgrade to a newer pre-release."
90
+ ));
91
+ var n = a();
92
+ if (!f) {
93
+ var v = a();
94
+ i(n, v) || (console.error(
95
+ "The result of getSnapshot should be cached to avoid an infinite loop"
96
+ ), f = !0);
97
+ }
98
+ v = m({
99
+ inst: { value: n, getSnapshot: a }
100
+ });
101
+ var w = v[0].inst, _ = v[1];
102
+ return g(
103
+ function() {
104
+ w.value = n, w.getSnapshot = a, r(w) && _({ inst: w });
105
+ },
106
+ [s, n, a]
107
+ ), p(
108
+ function() {
109
+ return r(w) && _({ inst: w }), s(function() {
110
+ r(w) && _({ inst: w });
111
+ });
112
+ },
113
+ [s]
114
+ ), d(n), n;
115
+ }
116
+ function r(s) {
117
+ var a = s.getSnapshot;
118
+ s = s.value;
119
+ try {
120
+ var n = a();
121
+ return !i(s, n);
122
+ } catch {
123
+ return !0;
124
+ }
125
+ }
126
+ function l(s, a) {
127
+ return a();
128
+ }
129
+ typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ < "u" && typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart == "function" && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
130
+ var o = D, i = typeof Object.is == "function" ? Object.is : e, m = o.useState, p = o.useEffect, g = o.useLayoutEffect, d = o.useDebugValue, c = !1, f = !1, u = typeof window > "u" || typeof window.document > "u" || typeof window.document.createElement > "u" ? l : t;
131
+ M.useSyncExternalStore = o.useSyncExternalStore !== void 0 ? o.useSyncExternalStore : u, typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ < "u" && typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop == "function" && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());
132
+ }()), M;
133
+ }
134
+ var I;
135
+ function F() {
136
+ return I || (I = 1, process.env.NODE_ENV === "production" ? L.exports = J() : L.exports = Y()), L.exports;
137
+ }
138
+ /**
139
+ * @license React
140
+ * use-sync-external-store-shim/with-selector.production.js
141
+ *
142
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
143
+ *
144
+ * This source code is licensed under the MIT license found in the
145
+ * LICENSE file in the root directory of this source tree.
146
+ */
147
+ var j;
148
+ function Q() {
149
+ if (j)
150
+ return R;
151
+ j = 1;
152
+ var e = D, t = F();
153
+ function r(d, c) {
154
+ return d === c && (d !== 0 || 1 / d === 1 / c) || d !== d && c !== c;
155
+ }
156
+ var l = typeof Object.is == "function" ? Object.is : r, o = t.useSyncExternalStore, i = e.useRef, m = e.useEffect, p = e.useMemo, g = e.useDebugValue;
157
+ return R.useSyncExternalStoreWithSelector = function(d, c, f, u, s) {
158
+ var a = i(null);
159
+ if (a.current === null) {
160
+ var n = { hasValue: !1, value: null };
161
+ a.current = n;
162
+ } else
163
+ n = a.current;
164
+ a = p(
165
+ function() {
166
+ function w(b) {
167
+ if (!_) {
168
+ if (_ = !0, O = b, b = u(b), s !== void 0 && n.hasValue) {
169
+ var E = n.value;
170
+ if (s(E, b))
171
+ return N = E;
172
+ }
173
+ return N = b;
174
+ }
175
+ if (E = N, l(O, b))
176
+ return E;
177
+ var T = u(b);
178
+ return s !== void 0 && s(E, T) ? (O = b, E) : (O = b, N = T);
179
+ }
180
+ var _ = !1, O, N, C = f === void 0 ? null : f;
181
+ return [
182
+ function() {
183
+ return w(c());
184
+ },
185
+ C === null ? void 0 : function() {
186
+ return w(C());
187
+ }
188
+ ];
189
+ },
190
+ [c, f, u, s]
191
+ );
192
+ var v = o(d, a[0], a[1]);
193
+ return m(
194
+ function() {
195
+ n.hasValue = !0, n.value = v;
196
+ },
197
+ [v]
198
+ ), g(v), v;
199
+ }, R;
200
+ }
201
+ var z = {};
202
+ /**
203
+ * @license React
204
+ * use-sync-external-store-shim/with-selector.development.js
205
+ *
206
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
207
+ *
208
+ * This source code is licensed under the MIT license found in the
209
+ * LICENSE file in the root directory of this source tree.
210
+ */
211
+ var W;
212
+ function X() {
213
+ return W || (W = 1, process.env.NODE_ENV !== "production" && function() {
214
+ function e(d, c) {
215
+ return d === c && (d !== 0 || 1 / d === 1 / c) || d !== d && c !== c;
216
+ }
217
+ typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ < "u" && typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart == "function" && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
218
+ var t = D, r = F(), l = typeof Object.is == "function" ? Object.is : e, o = r.useSyncExternalStore, i = t.useRef, m = t.useEffect, p = t.useMemo, g = t.useDebugValue;
219
+ z.useSyncExternalStoreWithSelector = function(d, c, f, u, s) {
220
+ var a = i(null);
221
+ if (a.current === null) {
222
+ var n = { hasValue: !1, value: null };
223
+ a.current = n;
224
+ } else
225
+ n = a.current;
226
+ a = p(
227
+ function() {
228
+ function w(b) {
229
+ if (!_) {
230
+ if (_ = !0, O = b, b = u(b), s !== void 0 && n.hasValue) {
231
+ var E = n.value;
232
+ if (s(E, b))
233
+ return N = E;
234
+ }
235
+ return N = b;
236
+ }
237
+ if (E = N, l(O, b))
238
+ return E;
239
+ var T = u(b);
240
+ return s !== void 0 && s(E, T) ? (O = b, E) : (O = b, N = T);
241
+ }
242
+ var _ = !1, O, N, C = f === void 0 ? null : f;
243
+ return [
244
+ function() {
245
+ return w(c());
246
+ },
247
+ C === null ? void 0 : function() {
248
+ return w(C());
249
+ }
250
+ ];
251
+ },
252
+ [c, f, u, s]
253
+ );
254
+ var v = o(d, a[0], a[1]);
255
+ return m(
256
+ function() {
257
+ n.hasValue = !0, n.value = v;
258
+ },
259
+ [v]
260
+ ), g(v), v;
261
+ }, typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ < "u" && typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop == "function" && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());
262
+ }()), z;
263
+ }
264
+ process.env.NODE_ENV === "production" ? V.exports = Q() : V.exports = X();
265
+ var Z = V.exports;
266
+ const ee = /* @__PURE__ */ q(Z), { useDebugValue: te } = D, { useSyncExternalStoreWithSelector: re } = ee;
267
+ const oe = (e) => e;
268
+ function ne(e, t = oe, r) {
269
+ const l = re(
270
+ e.subscribe,
271
+ e.getState,
272
+ e.getServerState || e.getInitialState,
273
+ t,
274
+ r
275
+ );
276
+ return te(l), l;
277
+ }
278
+ const G = (e) => {
279
+ const t = typeof e == "function" ? U(e) : e, r = (l, o) => ne(t, l, o);
280
+ return Object.assign(r, t), r;
281
+ }, se = (e) => e ? G(e) : G;
282
+ var h = /* @__PURE__ */ ((e) => (e[e.Empty = 0] = "Empty", e[e.Start = 1] = "Start", e[e.End = 2] = "End", e[e.Obstacle = 3] = "Obstacle", e[e.Visited = 4] = "Visited", e[e.Path = 5] = "Path", e))(h || {});
283
+ const k = (e, t) => {
284
+ const r = Math.abs(e.row - t.row), l = Math.abs(e.col - t.col);
285
+ return Math.floor(10 * Math.sqrt(r * r + l * l));
286
+ }, ae = (e, t) => ({
287
+ row: e.row,
288
+ col: e.col,
289
+ g: 0,
290
+ h: k(e, t),
291
+ f: k(e, t),
292
+ parent: null
293
+ }), le = (e, t, r) => {
294
+ const l = [
295
+ { row: e.row - 1, col: e.col },
296
+ { row: e.row + 1, col: e.col },
297
+ { row: e.row, col: e.col - 1 },
298
+ { row: e.row, col: e.col + 1 }
299
+ ];
300
+ return r && l.push(
301
+ { row: e.row - 1, col: e.col - 1 },
302
+ { row: e.row - 1, col: e.col + 1 },
303
+ { row: e.row + 1, col: e.col - 1 },
304
+ { row: e.row + 1, col: e.col + 1 }
305
+ ), l.filter((o) => o.row >= 0 && o.row < t.length && o.col >= 0 && o.col < t[0].length && t[o.row][o.col].state !== h.Obstacle).map((o) => ({
306
+ row: o.row,
307
+ col: o.col,
308
+ state: t[o.row][o.col].state
309
+ }));
310
+ }, ie = (e, t, r) => {
311
+ const l = Math.abs(e.row - t.row), o = Math.abs(e.col - t.col), i = e.g + (l === 0 || o === 0 ? 10 : 14), m = k(t, r), p = i + m;
312
+ return { g: i, h: m, f: p };
313
+ }, ce = (e) => {
314
+ const t = [];
315
+ let r = e;
316
+ for (; r; )
317
+ t.push(r), r = r.parent;
318
+ return t.reverse();
319
+ }, ue = (e, t, r, l) => {
320
+ const o = [], i = [], m = ae(t, r);
321
+ for (o.push(m); o.length > 0; ) {
322
+ o.sort((d, c) => d.f - c.f);
323
+ const p = o.shift();
324
+ if (p.row === r.row && p.col === r.col)
325
+ return i.push(p), { path: ce(p), visitedNodes: i };
326
+ i.push(p);
327
+ const g = le(p, e, l);
328
+ for (const d of g) {
329
+ if (i.some((a) => a.row === d.row && a.col === d.col))
330
+ continue;
331
+ const { g: c, h: f, f: u } = ie(p, d, r), s = o.find(
332
+ (a) => a.row === d.row && a.col === d.col
333
+ );
334
+ if (!s || c < s.g) {
335
+ const a = {
336
+ row: d.row,
337
+ col: d.col,
338
+ g: c,
339
+ h: f,
340
+ f: u,
341
+ parent: p
342
+ };
343
+ s ? (s.g = c, s.f = u, s.parent = p) : o.push(a);
344
+ }
345
+ }
346
+ }
347
+ return { path: [], visitedNodes: i };
348
+ }, de = (e) => ({
349
+ cells: Array.from(
350
+ { length: 8 },
351
+ (t, r) => Array.from({ length: 12 }, (l, o) => ({
352
+ row: r,
353
+ col: o,
354
+ state: h.Empty
355
+ }))
356
+ ),
357
+ rows: 8,
358
+ columns: 12,
359
+ startTile: null,
360
+ endTile: null,
361
+ obstacleTiles: [],
362
+ path: [],
363
+ visitedNodes: [],
364
+ setNumberOfColumns: (t) => {
365
+ e((r) => {
366
+ const l = r.cells.map((o) => t > r.columns ? [
367
+ ...o,
368
+ ...Array.from(
369
+ { length: t - r.columns },
370
+ (i, m) => ({
371
+ row: o[0].row,
372
+ col: r.columns + m,
373
+ state: h.Empty
374
+ })
375
+ )
376
+ ] : o.slice(0, t));
377
+ return {
378
+ ...r,
379
+ columns: t,
380
+ cells: l
381
+ };
382
+ });
383
+ },
384
+ setNumberOfRows: (t) => {
385
+ e((r) => {
386
+ let l = [...r.cells];
387
+ return t > r.rows ? l = [
388
+ ...l,
389
+ ...Array.from(
390
+ { length: t - r.rows },
391
+ (o, i) => Array.from({ length: r.columns }, (m, p) => ({
392
+ row: r.rows + i,
393
+ col: p,
394
+ state: h.Empty
395
+ }))
396
+ )
397
+ ] : l = l.slice(0, t), {
398
+ ...r,
399
+ rows: t,
400
+ cells: l
401
+ };
402
+ });
403
+ },
404
+ setCellState: (t, r, l) => {
405
+ e((o) => {
406
+ const i = o.cells.map(
407
+ (d) => d.map((c) => ({ ...c }))
408
+ );
409
+ let m = o.startTile, p = o.endTile, g = [...o.obstacleTiles];
410
+ switch (l === h.Start && o.startTile && (i[o.startTile.row][o.startTile.col].state = h.Empty, m = null), l === h.End && o.endTile && (i[o.endTile.row][o.endTile.col].state = h.Empty, p = null), i[t][r].state = l, l) {
411
+ case h.Start:
412
+ m = { row: t, col: r };
413
+ break;
414
+ case h.End:
415
+ p = { row: t, col: r };
416
+ break;
417
+ case h.Obstacle:
418
+ g.some((d) => d.row === t && d.col === r) || g.push({ row: t, col: r });
419
+ break;
420
+ case h.Empty:
421
+ g = g.filter(
422
+ (d) => !(d.row === t && d.col === r)
423
+ );
424
+ break;
425
+ }
426
+ return {
427
+ ...o,
428
+ cells: i,
429
+ startTile: m,
430
+ endTile: p,
431
+ obstacleTiles: g
432
+ };
433
+ });
434
+ },
435
+ resetCells: () => {
436
+ e((t) => ({
437
+ ...t,
438
+ cells: t.cells.map(
439
+ (r) => r.map((l) => ({
440
+ ...l,
441
+ state: h.Empty
442
+ }))
443
+ ),
444
+ startTile: null,
445
+ endTile: null,
446
+ obstacleTiles: [],
447
+ path: [],
448
+ visitedNodes: []
449
+ }));
450
+ },
451
+ handleFindPath: (t) => {
452
+ e((r) => {
453
+ const l = r.cells.flat().find((i) => i.state === h.Start), o = r.cells.flat().find((i) => i.state === h.End);
454
+ if (l && o) {
455
+ const i = r.cells.map(
456
+ (d) => d.map((c) => ({
457
+ row: c.row,
458
+ col: c.col,
459
+ state: c.state
460
+ }))
461
+ ), { path: m, visitedNodes: p } = ue(i, l, o, t);
462
+ return (async (d, c) => {
463
+ for (let f of c)
464
+ await new Promise((u) => setTimeout(u, 100)), e((u) => {
465
+ const s = u.cells.map(
466
+ (a) => a.map((n) => ({
467
+ ...n,
468
+ state: f.row === n.row && f.col === n.col && n.state === h.Empty ? h.Visited : n.state
469
+ }))
470
+ );
471
+ return {
472
+ ...u,
473
+ cells: s,
474
+ visitedNodes: [...u.visitedNodes, f]
475
+ };
476
+ });
477
+ for (let f of d)
478
+ await new Promise((u) => setTimeout(u, 250)), e((u) => {
479
+ const s = u.cells.map(
480
+ (a) => a.map((n) => ({
481
+ ...n,
482
+ state: f.row === n.row && f.col === n.col ? h.Path : n.state
483
+ }))
484
+ );
485
+ return {
486
+ ...u,
487
+ cells: s,
488
+ path: [...u.path, f]
489
+ };
490
+ });
491
+ })(m, p), { ...r, path: [], visitedNodes: [] };
492
+ }
493
+ return r;
494
+ });
495
+ },
496
+ setPath: (t) => {
497
+ e((r) => {
498
+ const l = r.cells.map(
499
+ (o) => o.map((i) => ({
500
+ ...i,
501
+ state: t.some((m) => m.row === i.row && m.col === i.col) ? h.Path : i.state
502
+ }))
503
+ );
504
+ return {
505
+ ...r,
506
+ cells: l
507
+ };
508
+ });
509
+ },
510
+ setVisitedNodes: (t) => {
511
+ e((r) => {
512
+ const l = r.cells.map(
513
+ (o) => o.map((i) => ({
514
+ ...i,
515
+ state: t.some((m) => m.row === i.row && m.col === i.col) && i.state === h.Empty ? h.Visited : i.state
516
+ }))
517
+ );
518
+ return {
519
+ ...r,
520
+ cells: l
521
+ };
522
+ });
523
+ }
524
+ }), fe = (e) => ({
525
+ activeButton: h.Start,
526
+ setSelectedButtonState: (t) => e({ activeButton: t }),
527
+ canTravelDiagonally: !0,
528
+ setCanTravelDiagonally: (t) => e({ canTravelDiagonally: t })
529
+ }), K = se((e, t, r) => ({
530
+ ...de(e),
531
+ ...fe(e)
532
+ }));
533
+ const he = () => {
534
+ var u;
535
+ const { cells: e, activeButton: t, setCellState: r, setSelectedButtonState: l, visitedNodes: o, path: i } = K(), [m, p] = H({ width: window.innerWidth, height: window.innerHeight });
536
+ $(() => {
537
+ const s = () => {
538
+ p({ width: window.innerWidth, height: window.innerHeight });
539
+ };
540
+ return window.addEventListener("resize", s), () => window.removeEventListener("resize", s);
541
+ }, []);
542
+ const g = (s, a) => {
543
+ switch (r(s, a, t), t) {
544
+ case h.Start:
545
+ l(h.End);
546
+ break;
547
+ case h.End:
548
+ l(h.Obstacle);
549
+ break;
550
+ }
551
+ }, d = (s, a) => {
552
+ const n = o.find((v) => v.row === s && v.col === a);
553
+ return n ? { g: n.g, h: n.h, f: n.f } : { g: null, h: null, f: null };
554
+ }, f = (() => {
555
+ var T;
556
+ const s = m.width < 768, a = m.width < 1024, n = s ? Math.min(m.width * 0.98, 500) : a ? Math.min(m.width * 0.95, 800) : Math.min(m.width * 0.9, 1e3), v = s ? Math.min(m.height * 0.75, 500) : a ? Math.min(m.height * 0.8, 700) : Math.min(m.height * 0.85, 800), w = ((T = e[0]) == null ? void 0 : T.length) || 1, _ = e.length || 1, O = s ? 16 : 24, N = (n - O) / w, C = (v - O) / _;
557
+ return Math.max(s ? 30 : 40, Math.min(N, C, s ? 50 : a ? 70 : 90));
558
+ })();
559
+ return /* @__PURE__ */ S("div", { className: "grid-wrapper", children: /* @__PURE__ */ S(
560
+ "div",
561
+ {
562
+ className: "grid-container",
563
+ style: {
564
+ display: "grid",
565
+ gridTemplateColumns: `repeat(${((u = e[0]) == null ? void 0 : u.length) || 1}, ${f}px)`,
566
+ gridTemplateRows: `repeat(${e.length || 1}, ${f}px)`,
567
+ gap: "1px",
568
+ padding: "8px",
569
+ background: "var(--bg-secondary)",
570
+ borderRadius: "8px",
571
+ boxShadow: "0 2px 8px rgba(0, 0, 0, 0.1)",
572
+ border: "1px solid var(--border-color)"
573
+ },
574
+ children: e.map(
575
+ (s, a) => s.map((n, v) => {
576
+ const w = i.some((E) => E.row === n.row && E.col === n.col), _ = o.some((E) => E.row === n.row && E.col === n.col), { g: O, h: N, f: C } = d(n.row, n.col);
577
+ let b = me(n, _);
578
+ if (w) {
579
+ const E = i.findIndex((T) => T.row === n.row && T.col === n.col);
580
+ E === 0 ? b = "var(--cell-start)" : E === i.length - 1 ? b = "var(--cell-end)" : b = "var(--cell-path)";
581
+ }
582
+ return /* @__PURE__ */ y(
583
+ "div",
584
+ {
585
+ className: "grid-cell",
586
+ onClick: () => g(a, v),
587
+ style: {
588
+ width: f,
589
+ height: f,
590
+ backgroundColor: b,
591
+ border: "1px solid var(--cell-border)",
592
+ cursor: "pointer",
593
+ transition: "all 0.15s ease",
594
+ position: "relative",
595
+ display: "flex",
596
+ justifyContent: "center",
597
+ alignItems: "center",
598
+ borderRadius: "2px"
599
+ },
600
+ onMouseEnter: (E) => {
601
+ n.state === h.Empty && (E.currentTarget.style.backgroundColor = "var(--bg-tertiary)", E.currentTarget.style.transform = "scale(1.02)");
602
+ },
603
+ onMouseLeave: (E) => {
604
+ n.state === h.Empty && (E.currentTarget.style.backgroundColor = b, E.currentTarget.style.transform = "scale(1)");
605
+ },
606
+ children: [
607
+ _ && /* @__PURE__ */ y("div", { className: "cell-values", children: [
608
+ /* @__PURE__ */ y("div", { className: "value-h", children: [
609
+ "h",
610
+ N
611
+ ] }),
612
+ /* @__PURE__ */ y("div", { className: "value-f", children: [
613
+ "f",
614
+ C
615
+ ] }),
616
+ /* @__PURE__ */ y("div", { className: "value-g", children: [
617
+ "g",
618
+ O
619
+ ] })
620
+ ] }),
621
+ n.state === h.Start && /* @__PURE__ */ S("div", { className: "cell-indicator start", children: "●" }),
622
+ n.state === h.End && /* @__PURE__ */ S("div", { className: "cell-indicator end", children: "●" }),
623
+ n.state === h.Obstacle && /* @__PURE__ */ S("div", { className: "cell-indicator obstacle", children: "■" })
624
+ ]
625
+ },
626
+ `${a}-${v}`
627
+ );
628
+ })
629
+ )
630
+ }
631
+ ) });
632
+ }, me = (e, t) => {
633
+ if (t)
634
+ return e.state === h.Start ? "var(--cell-start)" : e.state === h.End ? "var(--cell-end)" : "var(--cell-visited)";
635
+ switch (e.state) {
636
+ case h.Start:
637
+ return "var(--cell-start)";
638
+ case h.End:
639
+ return "var(--cell-end)";
640
+ case h.Obstacle:
641
+ return "var(--cell-obstacle)";
642
+ case h.Empty:
643
+ return "var(--cell-empty)";
644
+ default:
645
+ return "var(--cell-empty)";
646
+ }
647
+ };
648
+ const pe = () => {
649
+ const {
650
+ activeButton: e,
651
+ setSelectedButtonState: t,
652
+ resetCells: r,
653
+ rows: l,
654
+ columns: o,
655
+ setNumberOfRows: i,
656
+ setNumberOfColumns: m,
657
+ handleFindPath: p,
658
+ canTravelDiagonally: g,
659
+ setCanTravelDiagonally: d
660
+ } = K(), [c, f] = H(() => {
661
+ const w = localStorage.getItem("darkMode");
662
+ return w ? JSON.parse(w) : !1;
663
+ });
664
+ $(() => {
665
+ localStorage.setItem("darkMode", JSON.stringify(c)), document.documentElement.setAttribute("data-theme", c ? "dark" : "light");
666
+ }, [c]);
667
+ const u = () => {
668
+ f(!c);
669
+ }, s = [
670
+ { label: "Start", state: h.Start },
671
+ { label: "End", state: h.End },
672
+ { label: "Obstacle", state: h.Obstacle },
673
+ { label: "Clear", state: h.Empty },
674
+ { label: "Reset", state: null }
675
+ ], a = (w) => {
676
+ w === null ? n() : t(w);
677
+ }, n = () => {
678
+ r(), t(h.Start);
679
+ }, v = () => {
680
+ p(g);
681
+ };
682
+ return /* @__PURE__ */ S("div", { className: "control-panel", children: /* @__PURE__ */ y("div", { className: "control-grid", children: [
683
+ /* @__PURE__ */ y("div", { className: "control-group tools", children: [
684
+ /* @__PURE__ */ S("h3", { className: "group-title", children: "Tools" }),
685
+ /* @__PURE__ */ S("div", { className: "button-group", children: s.map((w, _) => /* @__PURE__ */ S(
686
+ "button",
687
+ {
688
+ className: `control-button ${w.label.toLowerCase()} ${e === w.state ? "active" : ""}`,
689
+ onClick: () => a(w.state),
690
+ children: w.label
691
+ },
692
+ _
693
+ )) })
694
+ ] }),
695
+ /* @__PURE__ */ y("div", { className: "control-group actions", children: [
696
+ /* @__PURE__ */ S("h3", { className: "group-title", children: "Actions" }),
697
+ /* @__PURE__ */ y("div", { className: "button-group", children: [
698
+ /* @__PURE__ */ S(
699
+ "button",
700
+ {
701
+ className: "control-button find-path",
702
+ onClick: v,
703
+ children: "Find Path"
704
+ }
705
+ ),
706
+ /* @__PURE__ */ S(
707
+ "button",
708
+ {
709
+ className: `control-button diagonal ${g ? "active" : ""}`,
710
+ onClick: () => d(!g),
711
+ children: g ? "Diagonal On" : "Diagonal Off"
712
+ }
713
+ ),
714
+ /* @__PURE__ */ S(
715
+ "button",
716
+ {
717
+ className: `control-button theme-toggle ${c ? "active" : ""}`,
718
+ onClick: u,
719
+ title: c ? "Switch to light mode" : "Switch to dark mode",
720
+ children: c ? "☀️ Light" : "🌙 Dark"
721
+ }
722
+ )
723
+ ] })
724
+ ] }),
725
+ /* @__PURE__ */ y("div", { className: "control-group size", children: [
726
+ /* @__PURE__ */ S("h3", { className: "group-title", children: "Grid Size" }),
727
+ /* @__PURE__ */ y("div", { className: "size-controls", children: [
728
+ /* @__PURE__ */ y("div", { className: "size-control", children: [
729
+ /* @__PURE__ */ S("label", { className: "size-label", children: "Rows" }),
730
+ /* @__PURE__ */ y("div", { className: "size-buttons", children: [
731
+ /* @__PURE__ */ S(
732
+ "button",
733
+ {
734
+ className: "size-button",
735
+ onClick: () => i(Math.max(5, l - 1)),
736
+ disabled: l <= 5,
737
+ children: "−"
738
+ }
739
+ ),
740
+ /* @__PURE__ */ S("span", { className: "size-value", children: l }),
741
+ /* @__PURE__ */ S(
742
+ "button",
743
+ {
744
+ className: "size-button",
745
+ onClick: () => i(Math.min(50, l + 1)),
746
+ disabled: l >= 50,
747
+ children: "+"
748
+ }
749
+ )
750
+ ] })
751
+ ] }),
752
+ /* @__PURE__ */ y("div", { className: "size-control", children: [
753
+ /* @__PURE__ */ S("label", { className: "size-label", children: "Columns" }),
754
+ /* @__PURE__ */ y("div", { className: "size-buttons", children: [
755
+ /* @__PURE__ */ S(
756
+ "button",
757
+ {
758
+ className: "size-button",
759
+ onClick: () => m(Math.max(5, o - 1)),
760
+ disabled: o <= 5,
761
+ children: "−"
762
+ }
763
+ ),
764
+ /* @__PURE__ */ S("span", { className: "size-value", children: o }),
765
+ /* @__PURE__ */ S(
766
+ "button",
767
+ {
768
+ className: "size-button",
769
+ onClick: () => m(Math.min(50, o + 1)),
770
+ disabled: o >= 50,
771
+ children: "+"
772
+ }
773
+ )
774
+ ] })
775
+ ] })
776
+ ] })
777
+ ] })
778
+ ] }) });
779
+ }, ve = () => /* @__PURE__ */ y("div", { className: "app-container", children: [
780
+ /* @__PURE__ */ S("header", { className: "app-header", children: /* @__PURE__ */ S("h1", { className: "app-title", children: "A* Pathfinding" }) }),
781
+ /* @__PURE__ */ S("main", { className: "app-main", children: /* @__PURE__ */ S(he, {}) }),
782
+ /* @__PURE__ */ S("footer", { className: "app-footer", children: /* @__PURE__ */ S(pe, {}) })
783
+ ] });
784
+ function Se() {
785
+ return /* @__PURE__ */ S(ve, {});
786
+ }
787
+ export {
788
+ Se as AStarVisualizer,
789
+ h as CellState,
790
+ ve as Layout
791
+ };
@@ -0,0 +1,33 @@
1
+ (function(T,u){typeof exports=="object"&&typeof module<"u"?u(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],u):(T=typeof globalThis<"u"?globalThis:T||self,u(T.AStarVisualizer={},T["react/jsx-runtime"],T.React))})(this,function(T,u,C){"use strict";const x=e=>{let t;const r=new Set,l=(i,h)=>{const d=typeof i=="function"?i(t):i;if(!Object.is(d,t)){const s=t;t=h??(typeof d!="object"||d===null)?d:Object.assign({},t,d),r.forEach(a=>a(t,s))}},o=()=>t,g={setState:l,getState:o,getInitialState:()=>f,subscribe:i=>(r.add(i),()=>r.delete(i)),destroy:()=>{r.clear()}},f=t=e(l,o,g);return g},R=e=>e?x(e):x;function q(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var A={exports:{}},M={},L={exports:{}},z={};/**
2
+ * @license React
3
+ * use-sync-external-store-shim.production.js
4
+ *
5
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
6
+ *
7
+ * This source code is licensed under the MIT license found in the
8
+ * LICENSE file in the root directory of this source tree.
9
+ */var B;function J(){if(B)return z;B=1;var e=C;function t(h,d){return h===d&&(h!==0||1/h===1/d)||h!==h&&d!==d}var r=typeof Object.is=="function"?Object.is:t,l=e.useState,o=e.useEffect,c=e.useLayoutEffect,m=e.useDebugValue;function v(h,d){var s=d(),a=l({inst:{value:s,getSnapshot:d}}),n=a[0].inst,w=a[1];return c(function(){n.value=s,n.getSnapshot=d,g(n)&&w({inst:n})},[h,s,d]),o(function(){return g(n)&&w({inst:n}),h(function(){g(n)&&w({inst:n})})},[h]),m(s),s}function g(h){var d=h.getSnapshot;h=h.value;try{var s=d();return!r(h,s)}catch{return!0}}function f(h,d){return d()}var i=typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"?f:v;return z.useSyncExternalStore=e.useSyncExternalStore!==void 0?e.useSyncExternalStore:i,z}var V={};/**
10
+ * @license React
11
+ * use-sync-external-store-shim.development.js
12
+ *
13
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
14
+ *
15
+ * This source code is licensed under the MIT license found in the
16
+ * LICENSE file in the root directory of this source tree.
17
+ */var j;function Y(){return j||(j=1,process.env.NODE_ENV!=="production"&&function(){function e(s,a){return s===a&&(s!==0||1/s===1/a)||s!==s&&a!==a}function t(s,a){i||o.startTransition===void 0||(i=!0,console.error("You are using an outdated, pre-release alpha of React 18 that does not support useSyncExternalStore. The use-sync-external-store shim will not work correctly. Upgrade to a newer pre-release."));var n=a();if(!h){var w=a();c(n,w)||(console.error("The result of getSnapshot should be cached to avoid an infinite loop"),h=!0)}w=m({inst:{value:n,getSnapshot:a}});var S=w[0].inst,_=w[1];return g(function(){S.value=n,S.getSnapshot=a,r(S)&&_({inst:S})},[s,n,a]),v(function(){return r(S)&&_({inst:S}),s(function(){r(S)&&_({inst:S})})},[s]),f(n),n}function r(s){var a=s.getSnapshot;s=s.value;try{var n=a();return!c(s,n)}catch{return!0}}function l(s,a){return a()}typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<"u"&&typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart=="function"&&__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());var o=C,c=typeof Object.is=="function"?Object.is:e,m=o.useState,v=o.useEffect,g=o.useLayoutEffect,f=o.useDebugValue,i=!1,h=!1,d=typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"?l:t;V.useSyncExternalStore=o.useSyncExternalStore!==void 0?o.useSyncExternalStore:d,typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<"u"&&typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop=="function"&&__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error())}()),V}var I;function W(){return I||(I=1,process.env.NODE_ENV==="production"?L.exports=J():L.exports=Y()),L.exports}/**
18
+ * @license React
19
+ * use-sync-external-store-shim/with-selector.production.js
20
+ *
21
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
22
+ *
23
+ * This source code is licensed under the MIT license found in the
24
+ * LICENSE file in the root directory of this source tree.
25
+ */var G;function Q(){if(G)return M;G=1;var e=C,t=W();function r(f,i){return f===i&&(f!==0||1/f===1/i)||f!==f&&i!==i}var l=typeof Object.is=="function"?Object.is:r,o=t.useSyncExternalStore,c=e.useRef,m=e.useEffect,v=e.useMemo,g=e.useDebugValue;return M.useSyncExternalStoreWithSelector=function(f,i,h,d,s){var a=c(null);if(a.current===null){var n={hasValue:!1,value:null};a.current=n}else n=a.current;a=v(function(){function S(b){if(!_){if(_=!0,y=b,b=d(b),s!==void 0&&n.hasValue){var E=n.value;if(s(E,b))return O=E}return O=b}if(E=O,l(y,b))return E;var N=d(b);return s!==void 0&&s(E,N)?(y=b,E):(y=b,O=N)}var _=!1,y,O,D=h===void 0?null:h;return[function(){return S(i())},D===null?void 0:function(){return S(D())}]},[i,h,d,s]);var w=o(f,a[0],a[1]);return m(function(){n.hasValue=!0,n.value=w},[w]),g(w),w},M}var k={};/**
26
+ * @license React
27
+ * use-sync-external-store-shim/with-selector.development.js
28
+ *
29
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
30
+ *
31
+ * This source code is licensed under the MIT license found in the
32
+ * LICENSE file in the root directory of this source tree.
33
+ */var H;function X(){return H||(H=1,process.env.NODE_ENV!=="production"&&function(){function e(f,i){return f===i&&(f!==0||1/f===1/i)||f!==f&&i!==i}typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<"u"&&typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart=="function"&&__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());var t=C,r=W(),l=typeof Object.is=="function"?Object.is:e,o=r.useSyncExternalStore,c=t.useRef,m=t.useEffect,v=t.useMemo,g=t.useDebugValue;k.useSyncExternalStoreWithSelector=function(f,i,h,d,s){var a=c(null);if(a.current===null){var n={hasValue:!1,value:null};a.current=n}else n=a.current;a=v(function(){function S(b){if(!_){if(_=!0,y=b,b=d(b),s!==void 0&&n.hasValue){var E=n.value;if(s(E,b))return O=E}return O=b}if(E=O,l(y,b))return E;var N=d(b);return s!==void 0&&s(E,N)?(y=b,E):(y=b,O=N)}var _=!1,y,O,D=h===void 0?null:h;return[function(){return S(i())},D===null?void 0:function(){return S(D())}]},[i,h,d,s]);var w=o(f,a[0],a[1]);return m(function(){n.hasValue=!0,n.value=w},[w]),g(w),w},typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<"u"&&typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop=="function"&&__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error())}()),k}process.env.NODE_ENV==="production"?A.exports=Q():A.exports=X();var Z=A.exports;const $=q(Z),{useDebugValue:ee}=C,{useSyncExternalStoreWithSelector:te}=$;let ve=!1;const re=e=>e;function oe(e,t=re,r){const l=te(e.subscribe,e.getState,e.getServerState||e.getInitialState,t,r);return ee(l),l}const F=e=>{const t=typeof e=="function"?R(e):e,r=(l,o)=>oe(t,l,o);return Object.assign(r,t),r},ne=e=>e?F(e):F;var p=(e=>(e[e.Empty=0]="Empty",e[e.Start=1]="Start",e[e.End=2]="End",e[e.Obstacle=3]="Obstacle",e[e.Visited=4]="Visited",e[e.Path=5]="Path",e))(p||{});const P=(e,t)=>{const r=Math.abs(e.row-t.row),l=Math.abs(e.col-t.col);return Math.floor(10*Math.sqrt(r*r+l*l))},se=(e,t)=>({row:e.row,col:e.col,g:0,h:P(e,t),f:P(e,t),parent:null}),ae=(e,t,r)=>{const l=[{row:e.row-1,col:e.col},{row:e.row+1,col:e.col},{row:e.row,col:e.col-1},{row:e.row,col:e.col+1}];return r&&l.push({row:e.row-1,col:e.col-1},{row:e.row-1,col:e.col+1},{row:e.row+1,col:e.col-1},{row:e.row+1,col:e.col+1}),l.filter(o=>o.row>=0&&o.row<t.length&&o.col>=0&&o.col<t[0].length&&t[o.row][o.col].state!==p.Obstacle).map(o=>({row:o.row,col:o.col,state:t[o.row][o.col].state}))},le=(e,t,r)=>{const l=Math.abs(e.row-t.row),o=Math.abs(e.col-t.col),c=e.g+(l===0||o===0?10:14),m=P(t,r),v=c+m;return{g:c,h:m,f:v}},ce=e=>{const t=[];let r=e;for(;r;)t.push(r),r=r.parent;return t.reverse()},ie=(e,t,r,l)=>{const o=[],c=[],m=se(t,r);for(o.push(m);o.length>0;){o.sort((f,i)=>f.f-i.f);const v=o.shift();if(v.row===r.row&&v.col===r.col)return c.push(v),{path:ce(v),visitedNodes:c};c.push(v);const g=ae(v,e,l);for(const f of g){if(c.some(a=>a.row===f.row&&a.col===f.col))continue;const{g:i,h,f:d}=le(v,f,r),s=o.find(a=>a.row===f.row&&a.col===f.col);if(!s||i<s.g){const a={row:f.row,col:f.col,g:i,h,f:d,parent:v};s?(s.g=i,s.f=d,s.parent=v):o.push(a)}}}return{path:[],visitedNodes:c}},ue=e=>({cells:Array.from({length:8},(t,r)=>Array.from({length:12},(l,o)=>({row:r,col:o,state:p.Empty}))),rows:8,columns:12,startTile:null,endTile:null,obstacleTiles:[],path:[],visitedNodes:[],setNumberOfColumns:t=>{e(r=>{const l=r.cells.map(o=>t>r.columns?[...o,...Array.from({length:t-r.columns},(c,m)=>({row:o[0].row,col:r.columns+m,state:p.Empty}))]:o.slice(0,t));return{...r,columns:t,cells:l}})},setNumberOfRows:t=>{e(r=>{let l=[...r.cells];return t>r.rows?l=[...l,...Array.from({length:t-r.rows},(o,c)=>Array.from({length:r.columns},(m,v)=>({row:r.rows+c,col:v,state:p.Empty})))]:l=l.slice(0,t),{...r,rows:t,cells:l}})},setCellState:(t,r,l)=>{e(o=>{const c=o.cells.map(f=>f.map(i=>({...i})));let m=o.startTile,v=o.endTile,g=[...o.obstacleTiles];switch(l===p.Start&&o.startTile&&(c[o.startTile.row][o.startTile.col].state=p.Empty,m=null),l===p.End&&o.endTile&&(c[o.endTile.row][o.endTile.col].state=p.Empty,v=null),c[t][r].state=l,l){case p.Start:m={row:t,col:r};break;case p.End:v={row:t,col:r};break;case p.Obstacle:g.some(f=>f.row===t&&f.col===r)||g.push({row:t,col:r});break;case p.Empty:g=g.filter(f=>!(f.row===t&&f.col===r));break}return{...o,cells:c,startTile:m,endTile:v,obstacleTiles:g}})},resetCells:()=>{e(t=>({...t,cells:t.cells.map(r=>r.map(l=>({...l,state:p.Empty}))),startTile:null,endTile:null,obstacleTiles:[],path:[],visitedNodes:[]}))},handleFindPath:t=>{e(r=>{const l=r.cells.flat().find(c=>c.state===p.Start),o=r.cells.flat().find(c=>c.state===p.End);if(l&&o){const c=r.cells.map(f=>f.map(i=>({row:i.row,col:i.col,state:i.state}))),{path:m,visitedNodes:v}=ie(c,l,o,t);return(async(f,i)=>{for(let h of i)await new Promise(d=>setTimeout(d,100)),e(d=>{const s=d.cells.map(a=>a.map(n=>({...n,state:h.row===n.row&&h.col===n.col&&n.state===p.Empty?p.Visited:n.state})));return{...d,cells:s,visitedNodes:[...d.visitedNodes,h]}});for(let h of f)await new Promise(d=>setTimeout(d,250)),e(d=>{const s=d.cells.map(a=>a.map(n=>({...n,state:h.row===n.row&&h.col===n.col?p.Path:n.state})));return{...d,cells:s,path:[...d.path,h]}})})(m,v),{...r,path:[],visitedNodes:[]}}return r})},setPath:t=>{e(r=>{const l=r.cells.map(o=>o.map(c=>({...c,state:t.some(m=>m.row===c.row&&m.col===c.col)?p.Path:c.state})));return{...r,cells:l}})},setVisitedNodes:t=>{e(r=>{const l=r.cells.map(o=>o.map(c=>({...c,state:t.some(m=>m.row===c.row&&m.col===c.col)&&c.state===p.Empty?p.Visited:c.state})));return{...r,cells:l}})}}),de=e=>({activeButton:p.Start,setSelectedButtonState:t=>e({activeButton:t}),canTravelDiagonally:!0,setCanTravelDiagonally:t=>e({canTravelDiagonally:t})}),K=ne((e,t,r)=>({...ue(e),...de(e)})),we="",fe=()=>{var d;const{cells:e,activeButton:t,setCellState:r,setSelectedButtonState:l,visitedNodes:o,path:c}=K(),[m,v]=C.useState({width:window.innerWidth,height:window.innerHeight});C.useEffect(()=>{const s=()=>{v({width:window.innerWidth,height:window.innerHeight})};return window.addEventListener("resize",s),()=>window.removeEventListener("resize",s)},[]);const g=(s,a)=>{switch(r(s,a,t),t){case p.Start:l(p.End);break;case p.End:l(p.Obstacle);break}},f=(s,a)=>{const n=o.find(w=>w.row===s&&w.col===a);return n?{g:n.g,h:n.h,f:n.f}:{g:null,h:null,f:null}},h=(()=>{var N;const s=m.width<768,a=m.width<1024,n=s?Math.min(m.width*.98,500):a?Math.min(m.width*.95,800):Math.min(m.width*.9,1e3),w=s?Math.min(m.height*.75,500):a?Math.min(m.height*.8,700):Math.min(m.height*.85,800),S=((N=e[0])==null?void 0:N.length)||1,_=e.length||1,y=s?16:24,O=(n-y)/S,D=(w-y)/_;return Math.max(s?30:40,Math.min(O,D,s?50:a?70:90))})();return u.jsx("div",{className:"grid-wrapper",children:u.jsx("div",{className:"grid-container",style:{display:"grid",gridTemplateColumns:`repeat(${((d=e[0])==null?void 0:d.length)||1}, ${h}px)`,gridTemplateRows:`repeat(${e.length||1}, ${h}px)`,gap:"1px",padding:"8px",background:"var(--bg-secondary)",borderRadius:"8px",boxShadow:"0 2px 8px rgba(0, 0, 0, 0.1)",border:"1px solid var(--border-color)"},children:e.map((s,a)=>s.map((n,w)=>{const S=c.some(E=>E.row===n.row&&E.col===n.col),_=o.some(E=>E.row===n.row&&E.col===n.col),{g:y,h:O,f:D}=f(n.row,n.col);let b=he(n,_);if(S){const E=c.findIndex(N=>N.row===n.row&&N.col===n.col);E===0?b="var(--cell-start)":E===c.length-1?b="var(--cell-end)":b="var(--cell-path)"}return u.jsxs("div",{className:"grid-cell",onClick:()=>g(a,w),style:{width:h,height:h,backgroundColor:b,border:"1px solid var(--cell-border)",cursor:"pointer",transition:"all 0.15s ease",position:"relative",display:"flex",justifyContent:"center",alignItems:"center",borderRadius:"2px"},onMouseEnter:E=>{n.state===p.Empty&&(E.currentTarget.style.backgroundColor="var(--bg-tertiary)",E.currentTarget.style.transform="scale(1.02)")},onMouseLeave:E=>{n.state===p.Empty&&(E.currentTarget.style.backgroundColor=b,E.currentTarget.style.transform="scale(1)")},children:[_&&u.jsxs("div",{className:"cell-values",children:[u.jsxs("div",{className:"value-h",children:["h",O]}),u.jsxs("div",{className:"value-f",children:["f",D]}),u.jsxs("div",{className:"value-g",children:["g",y]})]}),n.state===p.Start&&u.jsx("div",{className:"cell-indicator start",children:"●"}),n.state===p.End&&u.jsx("div",{className:"cell-indicator end",children:"●"}),n.state===p.Obstacle&&u.jsx("div",{className:"cell-indicator obstacle",children:"■"})]},`${a}-${w}`)}))})})},he=(e,t)=>{if(t)return e.state===p.Start?"var(--cell-start)":e.state===p.End?"var(--cell-end)":"var(--cell-visited)";switch(e.state){case p.Start:return"var(--cell-start)";case p.End:return"var(--cell-end)";case p.Obstacle:return"var(--cell-obstacle)";case p.Empty:return"var(--cell-empty)";default:return"var(--cell-empty)"}},Se="",pe=()=>{const{activeButton:e,setSelectedButtonState:t,resetCells:r,rows:l,columns:o,setNumberOfRows:c,setNumberOfColumns:m,handleFindPath:v,canTravelDiagonally:g,setCanTravelDiagonally:f}=K(),[i,h]=C.useState(()=>{const S=localStorage.getItem("darkMode");return S?JSON.parse(S):!1});C.useEffect(()=>{localStorage.setItem("darkMode",JSON.stringify(i)),document.documentElement.setAttribute("data-theme",i?"dark":"light")},[i]);const d=()=>{h(!i)},s=[{label:"Start",state:p.Start},{label:"End",state:p.End},{label:"Obstacle",state:p.Obstacle},{label:"Clear",state:p.Empty},{label:"Reset",state:null}],a=S=>{S===null?n():t(S)},n=()=>{r(),t(p.Start)},w=()=>{v(g)};return u.jsx("div",{className:"control-panel",children:u.jsxs("div",{className:"control-grid",children:[u.jsxs("div",{className:"control-group tools",children:[u.jsx("h3",{className:"group-title",children:"Tools"}),u.jsx("div",{className:"button-group",children:s.map((S,_)=>u.jsx("button",{className:`control-button ${S.label.toLowerCase()} ${e===S.state?"active":""}`,onClick:()=>a(S.state),children:S.label},_))})]}),u.jsxs("div",{className:"control-group actions",children:[u.jsx("h3",{className:"group-title",children:"Actions"}),u.jsxs("div",{className:"button-group",children:[u.jsx("button",{className:"control-button find-path",onClick:w,children:"Find Path"}),u.jsx("button",{className:`control-button diagonal ${g?"active":""}`,onClick:()=>f(!g),children:g?"Diagonal On":"Diagonal Off"}),u.jsx("button",{className:`control-button theme-toggle ${i?"active":""}`,onClick:d,title:i?"Switch to light mode":"Switch to dark mode",children:i?"☀️ Light":"🌙 Dark"})]})]}),u.jsxs("div",{className:"control-group size",children:[u.jsx("h3",{className:"group-title",children:"Grid Size"}),u.jsxs("div",{className:"size-controls",children:[u.jsxs("div",{className:"size-control",children:[u.jsx("label",{className:"size-label",children:"Rows"}),u.jsxs("div",{className:"size-buttons",children:[u.jsx("button",{className:"size-button",onClick:()=>c(Math.max(5,l-1)),disabled:l<=5,children:"−"}),u.jsx("span",{className:"size-value",children:l}),u.jsx("button",{className:"size-button",onClick:()=>c(Math.min(50,l+1)),disabled:l>=50,children:"+"})]})]}),u.jsxs("div",{className:"size-control",children:[u.jsx("label",{className:"size-label",children:"Columns"}),u.jsxs("div",{className:"size-buttons",children:[u.jsx("button",{className:"size-button",onClick:()=>m(Math.max(5,o-1)),disabled:o<=5,children:"−"}),u.jsx("span",{className:"size-value",children:o}),u.jsx("button",{className:"size-button",onClick:()=>m(Math.min(50,o+1)),disabled:o>=50,children:"+"})]})]})]})]})]})})},U=()=>u.jsxs("div",{className:"app-container",children:[u.jsx("header",{className:"app-header",children:u.jsx("h1",{className:"app-title",children:"A* Pathfinding"})}),u.jsx("main",{className:"app-main",children:u.jsx(fe,{})}),u.jsx("footer",{className:"app-footer",children:u.jsx(pe,{})})]});function me(){return u.jsx(U,{})}T.AStarVisualizer=me,T.CellState=p,T.Layout=U,Object.defineProperty(T,Symbol.toStringTag,{value:"Module"})});
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ .grid-wrapper{display:flex;justify-content:center;align-items:center;width:100%;height:100%}.grid-container{display:grid;gap:1px;padding:8px;background:var(--bg-secondary);border-radius:8px;box-shadow:0 2px 8px #0000001a;border:1px solid var(--border-color)}.grid-cell{position:relative;display:flex;justify-content:center;align-items:center;border:1px solid var(--cell-border);cursor:pointer;transition:all .15s ease;border-radius:2px;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.grid-cell:hover{transform:scale(1.02)}.grid-cell:active{transform:scale(.98)}.cell-values{position:absolute;top:0;left:0;right:0;bottom:0;display:grid;grid-template-columns:1fr 1fr 1fr;grid-template-rows:1fr 1fr;font-size:.75rem;font-weight:700;color:#fff;text-shadow:0 2px 4px rgba(0,0,0,.9);pointer-events:none}.value-h{grid-column:1;grid-row:1;display:flex;align-items:center;justify-content:center;font-size:.65rem}.value-f{grid-column:3;grid-row:1;display:flex;align-items:center;justify-content:center;font-size:.65rem}.value-g{grid-column:2;grid-row:2;display:flex;align-items:center;justify-content:center;font-size:.65rem}.cell-indicator{font-size:1.2rem;font-weight:700;color:#fff;text-shadow:0 2px 4px rgba(0,0,0,.9)}.cell-indicator.start,.cell-indicator.end,.cell-indicator.obstacle{color:#fff}@media (max-width: 768px){.cell-values{font-size:.6rem}.value-h,.value-f,.value-g{font-size:.5rem}.cell-indicator{font-size:1rem}}@media (max-width: 480px){.cell-values{font-size:.5rem}.value-h,.value-f,.value-g{font-size:.4rem}.cell-indicator{font-size:.9rem}}.control-panel{padding:1rem;background:var(--bg-secondary);border-radius:8px;border:1px solid var(--border-color);box-shadow:0 2px 8px #0000001a}.control-grid{display:grid;grid-template-columns:1fr;gap:1.5rem;align-items:start}.control-group{display:flex;flex-direction:column;gap:.75rem}.group-title{font-size:.875rem;font-weight:600;color:var(--text-secondary);text-transform:uppercase;letter-spacing:.05em;margin:0;padding-bottom:.5rem;border-bottom:1px solid var(--border-color)}.button-group{display:flex;flex-wrap:wrap;gap:.5rem;align-items:center;justify-content:center}.control-button{padding:.5rem 1rem;font-size:.875rem;font-weight:500;color:var(--text-primary);background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:6px;cursor:pointer;transition:all .2s ease;outline:none;min-width:fit-content}.control-button:hover{border-color:var(--border-hover);background:var(--bg-tertiary)}.control-button:active{transform:translateY(1px)}.control-button:focus-visible{outline:2px solid var(--primary);outline-offset:2px}.control-button.start.active{background:var(--success);border-color:var(--success);color:#fff}.control-button.end.active{background:var(--danger);border-color:var(--danger);color:#fff}.control-button.obstacle.active{background:var(--text-primary);border-color:var(--text-primary);color:#fff}.control-button.clear.active{background:var(--text-muted);border-color:var(--text-muted);color:#fff}.control-button.reset{background:var(--danger);border-color:var(--danger);color:#fff}.control-button.reset:hover{background:var(--danger-hover);border-color:var(--danger-hover)}.control-button.find-path{background:var(--primary);border-color:var(--primary);color:#fff}.control-button.find-path:hover{background:var(--primary-hover);border-color:var(--primary-hover)}.control-button.diagonal.active{background:var(--warning);border-color:var(--warning);color:#fff}.control-button.diagonal:hover{background:var(--warning-hover);border-color:var(--warning-hover)}.control-button.theme-toggle{background:var(--text-muted);border-color:var(--text-muted);color:#fff}.control-button.theme-toggle:hover{background:var(--text-secondary);border-color:var(--text-secondary)}.control-button.theme-toggle.active{background:var(--warning);border-color:var(--warning);color:#fff}.control-button.theme-toggle.active:hover{background:var(--warning-hover);border-color:var(--warning-hover)}.size-controls{display:flex;flex-direction:column;gap:.75rem;align-items:center}.size-control{display:flex;flex-direction:column;gap:.25rem;align-items:center}.size-label{font-size:.75rem;font-weight:500;color:var(--text-secondary);text-transform:uppercase;letter-spacing:.05em}.size-buttons{display:flex;align-items:center;gap:.5rem}.size-button{display:flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;font-size:1rem;font-weight:600;color:var(--text-primary);background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:4px;cursor:pointer;transition:all .2s ease;outline:none}.size-button:hover:not(:disabled){background:var(--primary);border-color:var(--primary);color:#fff}.size-button:active:not(:disabled){transform:scale(.95)}.size-button:disabled{opacity:.4;cursor:not-allowed}.size-button:focus-visible{outline:2px solid var(--primary);outline-offset:2px}.size-value{display:flex;align-items:center;justify-content:center;min-width:2.5rem;height:1.75rem;font-size:.875rem;font-weight:600;color:var(--text-primary);background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:4px}@media (min-width: 1024px){.control-grid{grid-template-columns:2fr 1fr 1fr;gap:2rem}.control-group.tools{grid-column:1}.control-group.actions{grid-column:2}.control-group.size{grid-column:3}}@media (min-width: 768px) and (max-width: 1023px){.control-grid{grid-template-columns:1fr 1fr;gap:1.5rem}.control-group.tools{grid-column:1 / -1}.control-group.actions{grid-column:1}.control-group.size{grid-column:2}}@media (max-width: 768px){.control-panel{padding:.75rem}.control-grid{gap:1rem}.button-group{gap:.375rem}.control-button{padding:.375rem .75rem;font-size:.8125rem}.size-controls{gap:.5rem}.size-buttons{gap:.375rem}.size-button{width:1.5rem;height:1.5rem;font-size:.875rem}.size-value{min-width:2rem;height:1.5rem;font-size:.8125rem}}@media (max-width: 480px){.control-panel{padding:.5rem}.control-grid{gap:.75rem}.button-group{flex-direction:column;gap:.25rem}.control-button{width:100%;padding:.5rem;font-size:.75rem}.size-controls{gap:.375rem}.size-buttons{gap:.25rem}.size-button{width:1.25rem;height:1.25rem;font-size:.75rem}.size-value{min-width:1.75rem;height:1.25rem;font-size:.75rem}}
package/dist/vite.svg ADDED
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "astar-visualizer",
3
+ "private": false,
4
+ "version": "1.0.0",
5
+ "type": "module",
6
+ "description": "A React component for visualizing A* pathfinding algorithm",
7
+ "main": "./dist/astar-visualizer.umd.cjs",
8
+ "module": "./dist/astar-visualizer.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "import": "./dist/astar-visualizer.js",
13
+ "require": "./dist/astar-visualizer.umd.cjs",
14
+ "types": "./dist/index.d.ts"
15
+ },
16
+ "./style.css": "./dist/style.css"
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "keywords": [
22
+ "astar",
23
+ "pathfinding",
24
+ "visualizer",
25
+ "react",
26
+ "algorithm",
27
+ "visualization"
28
+ ],
29
+ "author": "",
30
+ "license": "MIT",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": ""
34
+ },
35
+ "scripts": {
36
+ "dev": "vite",
37
+ "build": "tsc && vite build",
38
+ "build:lib": "tsc --project tsconfig.lib.json && vite build --config vite.config.lib.ts",
39
+ "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
40
+ "preview": "vite preview",
41
+ "storybook": "storybook dev -p 6006",
42
+ "build-storybook": "storybook build",
43
+ "format": "prettier --write .",
44
+ "test": "vitest",
45
+ "prepublishOnly": "npm run build:lib"
46
+ },
47
+ "peerDependencies": {
48
+ "react": "^18.2.0",
49
+ "react-dom": "^18.2.0"
50
+ },
51
+ "dependencies": {
52
+ "framer-motion": "^10.16.4",
53
+ "zustand": "^4.4.1"
54
+ },
55
+ "devDependencies": {
56
+ "@types/react": "^18.2.15",
57
+ "@types/react-dom": "^18.2.7",
58
+ "@typescript-eslint/eslint-plugin": "^6.21.0",
59
+ "@typescript-eslint/parser": "^6.21.0",
60
+ "@vitejs/plugin-react": "^4.0.3",
61
+ "eslint": "^8.57.1",
62
+ "eslint-config-prettier": "^9.0.0",
63
+ "eslint-plugin-prettier": "^5.0.0",
64
+ "eslint-plugin-react-hooks": "^4.6.0",
65
+ "eslint-plugin-react-refresh": "^0.4.3",
66
+ "husky": "^8.0.3",
67
+ "lint-staged": "^14.0.1",
68
+ "storybook": "^7.4.2",
69
+ "typescript": "^5.0.2",
70
+ "vite": "^4.4.5",
71
+ "vitest": "^3.0.4"
72
+ }
73
+ }