From 6dc85b443e869fa6cd5e57fbc9dc93ed8a6bb597 Mon Sep 17 00:00:00 2001 From: hyper Date: Sun, 12 Apr 2026 20:26:46 +0800 Subject: [PATCH] feat: shape parsing --- .../slay-the-spire-like/01-overview.md | 4 +- .../slay-the-spire-like/utils/parse-shape.ts | 107 ++++++++++++++++++ 2 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 src/samples/slay-the-spire-like/utils/parse-shape.ts diff --git a/src/samples/slay-the-spire-like/01-overview.md b/src/samples/slay-the-spire-like/01-overview.md index 2e30cb9..606a889 100644 --- a/src/samples/slay-the-spire-like/01-overview.md +++ b/src/samples/slay-the-spire-like/01-overview.md @@ -25,9 +25,9 @@ Zone based Point Crawl: 3种牌(攻击/防御/强化)攻击克强化克防御克攻击,强化比sts强化窄但效果更大 -受伤时伤口先占格子再扣血,牌少的角色受掉血影响大但血更厚 +洗牌堆时洗入两张《疲劳》(1费/消耗) -背包物品指定相邻物品,对其所有卡牌生效 +背包物品可能会引用相邻的物品、同一行的物品、同一列的物品等 部分物品带使用次数限制,药瓶喝完可以在篝火补 diff --git a/src/samples/slay-the-spire-like/utils/parse-shape.ts b/src/samples/slay-the-spire-like/utils/parse-shape.ts new file mode 100644 index 0000000..570b165 --- /dev/null +++ b/src/samples/slay-the-spire-like/utils/parse-shape.ts @@ -0,0 +1,107 @@ +/** + * Parsed shape result containing the grid and sizing information. + */ +export interface ParsedShape { + /** 2D boolean grid representing filled cells */ + grid: boolean[][]; + /** Grid width (number of columns) */ + width: number; + /** Grid height (number of rows) */ + height: number; + /** Origin X coordinate within the grid */ + originX: number; + /** Origin Y coordinate within the grid */ + originY: number; +} + +/** + * Parses a movement string into a 2D boolean grid. + * Rules: + * o: Fill current cell and set origin + * n, s, e, w: Move one step and fill the cell + * r: Return to the previous cell + */ +export function parseShapeString(input: string): ParsedShape { + let curX = 0; + let curY = 0; + let originX = 0; + let originY = 0; + let originSet = false; + + // Track unique filled coordinates + const filledPoints = new Set(); + // Stack to track movement history for the 'r' command + const history: { x: number; y: number }[] = []; + + const fill = (x: number, y: number) => { + filledPoints.add(`${x},${y}`); + history.push({ x, y }); + }; + + for (const char of input.toLowerCase()) { + switch (char) { + case 'o': + if (!originSet) { + originX = curX; + originY = curY; + originSet = true; + } + fill(curX, curY); + break; + case 'n': + curY -= 1; + fill(curX, curY); + break; + case 's': + curY += 1; + fill(curX, curY); + break; + case 'e': + curX += 1; + fill(curX, curY); + break; + case 'w': + curX -= 1; + fill(curX, curY); + break; + case 'r': + if (history.length > 1) { + history.pop(); // Remove current position + const prev = history[history.length - 1]; + curX = prev.x; + curY = prev.y; + } + break; + } + } + + if (filledPoints.size === 0) { + return { grid: [[]], width: 0, height: 1, originX: 0, originY: 0 }; + } + + // Calculate bounding box to normalize the array + const coords = Array.from(filledPoints).map(p => p.split(',').map(Number)); + const minX = Math.min(...coords.map(c => c[0])); + const maxX = Math.max(...coords.map(c => c[0])); + const minY = Math.min(...coords.map(c => c[1])); + const maxY = Math.max(...coords.map(c => c[1])); + + const width = maxX - minX + 1; + const height = maxY - minY + 1; + + // Initialize the grid + const grid: boolean[][] = Array.from({ length: height }, () => + Array(width).fill(false) + ); + + // Map the points into the grid using offsets + for (const [x, y] of coords) { + grid[y - minY][x - minX] = true; + } + + // Normalize origin coordinates relative to the grid + const normalizedOriginX = originX - minX; + const normalizedOriginY = originY - minY; + + return { grid, width, height, originX: normalizedOriginX, originY: normalizedOriginY }; +} \ No newline at end of file