From 423cc7c841ec6d498c5103de73d3f773dc3d88c3 Mon Sep 17 00:00:00 2001 From: hypercross Date: Mon, 20 Apr 2026 11:59:52 +0800 Subject: [PATCH] feat(slay-the-spire-like): add map navigation logic Implement `canMoveTo` and `moveToNode` for navigating the point crawl map, and add `PointCrawlMapNavigator` type. Also reformat map module files to use double quotes. --- .../slay-the-spire-like/system/map/index.ts | 21 +++- .../system/map/navigation.ts | 33 +++++++ .../slay-the-spire-like/system/map/types.ts | 99 ++++++++++--------- 3 files changed, 102 insertions(+), 51 deletions(-) create mode 100644 src/samples/slay-the-spire-like/system/map/navigation.ts diff --git a/src/samples/slay-the-spire-like/system/map/index.ts b/src/samples/slay-the-spire-like/system/map/index.ts index 1cc561e..d821522 100644 --- a/src/samples/slay-the-spire-like/system/map/index.ts +++ b/src/samples/slay-the-spire-like/system/map/index.ts @@ -1,5 +1,18 @@ -export { MapNodeType, MapLayerType } from './types'; -export type { MapNode, MapLayer, PointCrawlMap, MapGenerationConfig } from './types'; +export { MapNodeType, MapLayerType } from "./types"; +export type { + MapNode, + MapLayer, + PointCrawlMap, + MapGenerationConfig, +} from "./types"; -export { generatePointCrawlMap } from './generator'; -export { getNode, getChildren, getParents, hasPath, findAllPaths } from './generator'; +export { generatePointCrawlMap } from "./generator"; +export { + getNode, + getChildren, + getParents, + hasPath, + findAllPaths, +} from "./generator"; + +export { canMoveTo, moveToNode } from "./navigation"; diff --git a/src/samples/slay-the-spire-like/system/map/navigation.ts b/src/samples/slay-the-spire-like/system/map/navigation.ts new file mode 100644 index 0000000..e6a9569 --- /dev/null +++ b/src/samples/slay-the-spire-like/system/map/navigation.ts @@ -0,0 +1,33 @@ +import { getNode } from "./generator"; +import { PointCrawlMap, PointCrawlMapNavigator } from "./types"; + +export function canMoveTo( + navigator: PointCrawlMapNavigator, + map: PointCrawlMap, + targetNodeId: string, +): boolean { + const currentNode = getNode(map, navigator.currentNodeId); + if (!currentNode) return false; + + return currentNode.childIds.includes(targetNodeId); +} + +export function moveToNode( + navigator: PointCrawlMapNavigator, + map: PointCrawlMap, + targetNodeId: string, +): boolean { + if (!canMoveTo(navigator, map, targetNodeId)) { + return false; + } + + const targetNode = getNode(map, targetNodeId); + if (!targetNode) { + return false; + } + + // Update current position + navigator.currentNodeId = targetNodeId; + navigator.visitedNodes.add(targetNodeId); + return true; +} diff --git a/src/samples/slay-the-spire-like/system/map/types.ts b/src/samples/slay-the-spire-like/system/map/types.ts index c9f756f..be9aa56 100644 --- a/src/samples/slay-the-spire-like/system/map/types.ts +++ b/src/samples/slay-the-spire-like/system/map/types.ts @@ -1,83 +1,88 @@ -import {EncounterData} from "@/samples/slay-the-spire-like/system/types"; +import { EncounterData } from "@/samples/slay-the-spire-like/system/types"; /** * Types of nodes that can appear on the point crawl map. */ export enum MapNodeType { - Start = 'start', - End = 'end', - Minion = 'minion', - Elite = 'elite', - Event = 'event', - Camp = 'camp', - Shop = 'shop', - Curio = 'curio', + Start = "start", + End = "end", + Minion = "minion", + Elite = "elite", + Event = "event", + Camp = "camp", + Shop = "shop", + Curio = "curio", } /** * Semantic type of a layer. */ export enum MapLayerType { - Wild = 'wild', - Settlement = 'settlement', + Wild = "wild", + Settlement = "settlement", } /** * A single node on the map. */ export interface MapNode { - /** Unique identifier */ - id: string; - /** Which layer this node belongs to */ - layerIndex: number; - /** Semantic type of the node */ - type: MapNodeType; - /** IDs of nodes in the next layer this node connects to */ - childIds: string[]; - /** Encounter data assigned to this node (from encounter CSV) */ - encounter?: EncounterData; + /** Unique identifier */ + id: string; + /** Which layer this node belongs to */ + layerIndex: number; + /** Semantic type of the node */ + type: MapNodeType; + /** IDs of nodes in the next layer this node connects to */ + childIds: string[]; + /** Encounter data assigned to this node (from encounter CSV) */ + encounter?: EncounterData; } /** * A horizontal layer of nodes at the same progression stage. */ export interface MapLayer { - /** Layer index (0 = start, last = end) */ - index: number; - /** Ordered IDs of nodes in this layer */ - nodeIds: string[]; - /** Semantic type of the layer */ - layerType: MapLayerType | 'start' | 'end'; - /** Direct references to nodes in this layer (for performance) */ - nodes: MapNode[]; + /** Layer index (0 = start, last = end) */ + index: number; + /** Ordered IDs of nodes in this layer */ + nodeIds: string[]; + /** Semantic type of the layer */ + layerType: MapLayerType | "start" | "end"; + /** Direct references to nodes in this layer (for performance) */ + nodes: MapNode[]; } /** * A fully generated point crawl map. */ export interface PointCrawlMap { - /** Layers from start to end */ - layers: MapLayer[]; - /** All nodes keyed by ID */ - nodes: Map; - /** Reverse index: nodeId → parent node IDs (for fast getParent lookup) */ - parentIndex?: Map; + /** Layers from start to end */ + layers: MapLayer[]; + /** All nodes keyed by ID */ + nodes: Map; + /** Reverse index: nodeId → parent node IDs (for fast getParent lookup) */ + parentIndex?: Map; +} + +export interface PointCrawlMapNavigator { + currentNodeId: string; + visitedNodes: Set; } /** * Configuration for map generation. */ export interface MapGenerationConfig { - /** Total number of layers (including start and end) */ - totalLayers: number; - /** Number of nodes in each wild layer */ - wildLayerNodeCount: number; - /** Number of nodes in each settlement layer */ - settlementLayerNodeCount: number; - /** Probability weights for wild node types (should sum to 100) */ - wildNodeTypeWeights: { - [MapNodeType.Minion]: number; - [MapNodeType.Elite]: number; - [MapNodeType.Event]: number; - }; + /** Total number of layers (including start and end) */ + totalLayers: number; + /** Number of nodes in each wild layer */ + wildLayerNodeCount: number; + /** Number of nodes in each settlement layer */ + settlementLayerNodeCount: number; + /** Probability weights for wild node types (should sum to 100) */ + wildNodeTypeWeights: { + [MapNodeType.Minion]: number; + [MapNodeType.Elite]: number; + [MapNodeType.Event]: number; + }; }