maze-test 0.3.0 → 0.4.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-CN.md +6 -0
- package/README.md +6 -0
- package/dist/cli.cjs +64 -5
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +64 -5
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +64 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +64 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -339,7 +339,8 @@ function analyzeSolidCellMaze(maze) {
|
|
|
339
339
|
const distances = bfsDistances(maze.entry, graph);
|
|
340
340
|
const degreeValues = [...graph.values()].map((items) => items.length);
|
|
341
341
|
const edgeCount = degreeValues.reduce((sum, value) => sum + value, 0) / 2;
|
|
342
|
-
const mainPath =
|
|
342
|
+
const mainPath = shortestPathInGraph(graph, maze.entry, maze.goal);
|
|
343
|
+
const entryGoalSeparators = separatingCellKeys(graph, maze.entry, maze.goal);
|
|
343
344
|
const objectCounts = {};
|
|
344
345
|
for (const object of maze.objects ?? []) {
|
|
345
346
|
objectCounts[object.type] = (objectCounts[object.type] ?? 0) + 1;
|
|
@@ -357,7 +358,7 @@ function analyzeSolidCellMaze(maze) {
|
|
|
357
358
|
entryGoalDistance: mainPath.length > 0 ? mainPath.length - 1 : null,
|
|
358
359
|
doorCount: maze.doors.length,
|
|
359
360
|
gatingDoorCount: maze.doors.filter(
|
|
360
|
-
(door) =>
|
|
361
|
+
(door) => entryGoalSeparators.has(cellKey(door.position))
|
|
361
362
|
).length,
|
|
362
363
|
objectCounts
|
|
363
364
|
};
|
|
@@ -427,6 +428,9 @@ function validateSolidCellMaze(maze) {
|
|
|
427
428
|
function shortestPath(maze, start, goal, excludedCell = null) {
|
|
428
429
|
if (excludedCell && (sameCell(start, excludedCell) || sameCell(goal, excludedCell))) return [];
|
|
429
430
|
const graph = adjacency(maze, excludedCell);
|
|
431
|
+
return shortestPathInGraph(graph, start, goal);
|
|
432
|
+
}
|
|
433
|
+
function shortestPathInGraph(graph, start, goal) {
|
|
430
434
|
const queue = [start];
|
|
431
435
|
const parent = /* @__PURE__ */ new Map([[cellKey(start), null]]);
|
|
432
436
|
const values = /* @__PURE__ */ new Map([[cellKey(start), start]]);
|
|
@@ -558,12 +562,14 @@ function degreeMap(maze) {
|
|
|
558
562
|
}
|
|
559
563
|
function selectGatingDoorIndices(maze, mainPath, count) {
|
|
560
564
|
if (count === 0) return [];
|
|
561
|
-
const
|
|
565
|
+
const graph = adjacency(maze);
|
|
566
|
+
const separators = separatingCellKeys(graph, maze.entry, maze.goal);
|
|
562
567
|
const candidates = [];
|
|
563
568
|
for (let index = 3; index < mainPath.length - 3; index += 1) {
|
|
564
569
|
const pathCell = mainPath[index];
|
|
565
|
-
if (!pathCell
|
|
566
|
-
|
|
570
|
+
if (!pathCell) continue;
|
|
571
|
+
const key = cellKey(pathCell);
|
|
572
|
+
if ((graph.get(key)?.length ?? 0) === 2 && separators.has(key)) candidates.push(index);
|
|
567
573
|
}
|
|
568
574
|
if (candidates.length < count) {
|
|
569
575
|
throw new Error(`Only ${candidates.length} non-bypassable path cells are available for ${count} doors.`);
|
|
@@ -582,6 +588,59 @@ function selectGatingDoorIndices(maze, mainPath, count) {
|
|
|
582
588
|
if (selected.length !== count) throw new Error(`Could not space ${count} doors along the main path.`);
|
|
583
589
|
return selected.sort((left, right) => left - right);
|
|
584
590
|
}
|
|
591
|
+
function separatingCellKeys(graph, start, goal) {
|
|
592
|
+
const startKey = cellKey(start);
|
|
593
|
+
const goalKey = cellKey(goal);
|
|
594
|
+
if (!graph.has(startKey) || !graph.has(goalKey)) return /* @__PURE__ */ new Set();
|
|
595
|
+
const discovered = /* @__PURE__ */ new Map();
|
|
596
|
+
const low = /* @__PURE__ */ new Map();
|
|
597
|
+
const parent = /* @__PURE__ */ new Map([[startKey, null]]);
|
|
598
|
+
const stack = [
|
|
599
|
+
{ key: startKey, nextNeighbor: 0 }
|
|
600
|
+
];
|
|
601
|
+
let order = 1;
|
|
602
|
+
discovered.set(startKey, order);
|
|
603
|
+
low.set(startKey, order);
|
|
604
|
+
while (stack.length > 0) {
|
|
605
|
+
const frame = stack.at(-1);
|
|
606
|
+
if (!frame) break;
|
|
607
|
+
const adjacent = graph.get(frame.key) ?? [];
|
|
608
|
+
const next = adjacent[frame.nextNeighbor];
|
|
609
|
+
if (next) {
|
|
610
|
+
frame.nextNeighbor += 1;
|
|
611
|
+
const nextKey = cellKey(next);
|
|
612
|
+
if (!discovered.has(nextKey)) {
|
|
613
|
+
order += 1;
|
|
614
|
+
discovered.set(nextKey, order);
|
|
615
|
+
low.set(nextKey, order);
|
|
616
|
+
parent.set(nextKey, frame.key);
|
|
617
|
+
stack.push({ key: nextKey, nextNeighbor: 0 });
|
|
618
|
+
continue;
|
|
619
|
+
}
|
|
620
|
+
if (nextKey !== parent.get(frame.key)) {
|
|
621
|
+
low.set(frame.key, Math.min(low.get(frame.key) ?? order, discovered.get(nextKey) ?? order));
|
|
622
|
+
}
|
|
623
|
+
continue;
|
|
624
|
+
}
|
|
625
|
+
stack.pop();
|
|
626
|
+
const parentKey = parent.get(frame.key);
|
|
627
|
+
if (parentKey) {
|
|
628
|
+
low.set(parentKey, Math.min(low.get(parentKey) ?? order, low.get(frame.key) ?? order));
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
if (!discovered.has(goalKey)) return /* @__PURE__ */ new Set();
|
|
632
|
+
const separators = /* @__PURE__ */ new Set();
|
|
633
|
+
let childKey = goalKey;
|
|
634
|
+
while (childKey !== startKey) {
|
|
635
|
+
const parentKey = parent.get(childKey);
|
|
636
|
+
if (!parentKey) break;
|
|
637
|
+
if (parentKey !== startKey && (low.get(childKey) ?? Number.POSITIVE_INFINITY) >= (discovered.get(parentKey) ?? Number.NEGATIVE_INFINITY)) {
|
|
638
|
+
separators.add(parentKey);
|
|
639
|
+
}
|
|
640
|
+
childKey = parentKey;
|
|
641
|
+
}
|
|
642
|
+
return separators;
|
|
643
|
+
}
|
|
585
644
|
function freePathCellBefore(mainPath, preferredIndex, occupied) {
|
|
586
645
|
for (let distance = 0; distance < mainPath.length; distance += 1) {
|
|
587
646
|
for (const index of [preferredIndex - distance, preferredIndex + distance]) {
|