refactor(slay-the-spire-like): clean up barrel exports and formatting

- Convert explicit barrel exports to `export *` patterns in several
  systems
- Create a new `utils/index.ts` barrel for the system utils
- Rename `validatePlacement` to `validateShapePlacement` for clarity
- Reformat `shape-collision.ts` to use 2-space indentation and
  consistent
  styling
- Fix import paths in `index.ts`
This commit is contained in:
hypercross 2026-04-21 23:01:19 +08:00
parent 03d367c7b0
commit 97ff61985a
6 changed files with 141 additions and 175 deletions

View File

@ -3,5 +3,5 @@ export * from "./system/deck";
export * from "./system/encounter"; export * from "./system/encounter";
export * from "./system/grid-inventory"; export * from "./system/grid-inventory";
export * from "./system/map"; export * from "./system/map";
export * from "./system/utils/parse-shape"; export * from "./system/utils";
export * from "./system/types"; export * from "./system/types";

View File

@ -1,7 +1,2 @@
export type { GameCard, GameCardMeta, PlayerDeck, DeckRegions } from './types'; export * from "./factory";
export { export * from "./types";
generateDeckFromInventory,
createCard,
createPlayerDeck,
generateCardId,
} from './factory';

View File

@ -1,24 +1,3 @@
export type { export * from "./types";
CellCoordinate, export * from "./transform";
CellKey,
GridInventory,
InventoryItem,
MutationResult,
PlacementResult,
} from "./types";
export type { GameItemMeta, GameItem } from "./types";
export {
createGridInventory,
flipItem,
getAdjacentItems,
getItemAtCell,
getOccupiedCellSet,
moveItem,
placeItem,
removeItem,
rotateItem,
validatePlacement,
} from "./transform";
export * from "./factory"; export * from "./factory";

View File

@ -1,24 +1,3 @@
export { MapNodeType, MapLayerType } from "./types"; export * from "./generator";
export type { export * from "./navigation";
MapNode, export * from "./types";
MapLayer,
PointCrawlMap,
MapGenerationConfig,
} from "./types";
export { generatePointCrawlMap } from "./generator";
export {
getNode,
getChildren,
getParents,
hasPath,
findAllPaths,
} from "./generator";
export {
canMoveTo,
moveToNode,
getReachableChildren,
isAtEndNode,
isAtStartNode,
} from "./navigation";

View File

@ -0,0 +1,2 @@
export * from "./parse-shape";
export * from "./shape-collision";

View File

@ -1,129 +1,132 @@
import type { ParsedShape } from './parse-shape'; import type { ParsedShape } from "./parse-shape";
/** /**
* Represents a 2D point in grid coordinates. * Represents a 2D point in grid coordinates.
*/ */
export interface Point2D { export interface Point2D {
x: number; x: number;
y: number; y: number;
} }
/** /**
* 2D transformation to apply to a shape. * 2D transformation to apply to a shape.
*/ */
export interface Transform2D { export interface Transform2D {
/** Translation offset in grid units */ /** Translation offset in grid units */
offset: Point2D; offset: Point2D;
/** Rotation in degrees (0, 90, 180, 270) */ /** Rotation in degrees (0, 90, 180, 270) */
rotation: number; rotation: number;
/** Whether to flip horizontally */ /** Whether to flip horizontally */
flipX: boolean; flipX: boolean;
/** Whether to flip vertically */ /** Whether to flip vertically */
flipY: boolean; flipY: boolean;
} }
/** /**
* Default transform (identity). * Default transform (identity).
*/ */
export const IDENTITY_TRANSFORM: Transform2D = { export const IDENTITY_TRANSFORM: Transform2D = {
offset: { x: 0, y: 0 }, offset: { x: 0, y: 0 },
rotation: 0, rotation: 0,
flipX: false, flipX: false,
flipY: false, flipY: false,
}; };
/** /**
* Gets all occupied cell coordinates from a shape. * Gets all occupied cell coordinates from a shape.
*/ */
export function getOccupiedCells(shape: ParsedShape): Point2D[] { export function getOccupiedCells(shape: ParsedShape): Point2D[] {
const cells: Point2D[] = []; const cells: Point2D[] = [];
for (let y = 0; y < shape.height; y++) { for (let y = 0; y < shape.height; y++) {
for (let x = 0; x < shape.width; x++) { for (let x = 0; x < shape.width; x++) {
if (shape.grid[y]?.[x]) { if (shape.grid[y]?.[x]) {
cells.push({ x, y }); cells.push({ x, y });
} }
}
} }
return cells; }
return cells;
} }
/** /**
* Applies a 2D transformation to a point. * Applies a 2D transformation to a point.
*/ */
export function transformPoint( export function transformPoint(
point: Point2D, point: Point2D,
transform: Transform2D, transform: Transform2D,
shapeWidth: number, shapeWidth: number,
shapeHeight: number shapeHeight: number,
): Point2D { ): Point2D {
let { x, y } = point; let { x, y } = point;
// Apply flips // Apply flips
if (transform.flipX) { if (transform.flipX) {
x = shapeWidth - 1 - x; x = shapeWidth - 1 - x;
} }
if (transform.flipY) { if (transform.flipY) {
y = shapeHeight - 1 - y; y = shapeHeight - 1 - y;
} }
// Apply rotation (around origin 0,0) // Apply rotation (around origin 0,0)
const rotation = ((transform.rotation % 360) + 360) % 360; const rotation = ((transform.rotation % 360) + 360) % 360;
let rotatedX = x; let rotatedX = x;
let rotatedY = y; let rotatedY = y;
switch (rotation) { switch (rotation) {
case 90: case 90:
rotatedX = y; rotatedX = y;
rotatedY = -x; rotatedY = -x;
break; break;
case 180: case 180:
rotatedX = -x; rotatedX = -x;
rotatedY = -y; rotatedY = -y;
break; break;
case 270: case 270:
rotatedX = -y; rotatedX = -y;
rotatedY = x; rotatedY = x;
break; break;
} }
// Apply offset // Apply offset
return { return {
x: rotatedX + transform.offset.x, x: rotatedX + transform.offset.x,
y: rotatedY + transform.offset.y, y: rotatedY + transform.offset.y,
}; };
} }
/** /**
* Transforms a shape and returnss its occupied cells in world coordinates. * Transforms a shape and returnss its occupied cells in world coordinates.
*/ */
export function transformShape(shape: ParsedShape, transform: Transform2D): Point2D[] { export function transformShape(
const cells = getOccupiedCells(shape); shape: ParsedShape,
return cells.map(cell => transform: Transform2D,
transformPoint(cell, transform, shape.width, shape.height) ): Point2D[] {
); const cells = getOccupiedCells(shape);
return cells.map((cell) =>
transformPoint(cell, transform, shape.width, shape.height),
);
} }
/** /**
* Checks if two transformed shapes collide (share any occupied cell). * Checks if two transformed shapes collide (share any occupied cell).
*/ */
export function checkCollision( export function checkCollision(
shapeA: ParsedShape, shapeA: ParsedShape,
transformA: Transform2D, transformA: Transform2D,
shapeB: ParsedShape, shapeB: ParsedShape,
transformB: Transform2D transformB: Transform2D,
): boolean { ): boolean {
const cellsA = transformShape(shapeA, transformA); const cellsA = transformShape(shapeA, transformA);
const cellsB = transformShape(shapeB, transformB); const cellsB = transformShape(shapeB, transformB);
const setA = new Set(cellsA.map(c => `${c.x},${c.y}`)); const setA = new Set(cellsA.map((c) => `${c.x},${c.y}`));
for (const cell of cellsB) { for (const cell of cellsB) {
if (setA.has(`${cell.x},${cell.y}`)) { if (setA.has(`${cell.x},${cell.y}`)) {
return true; return true;
}
} }
}
return false; return false;
} }
/** /**
@ -133,19 +136,19 @@ export function checkCollision(
* @param occupiedCells Set of occupied board cells in "x,y" format * @param occupiedCells Set of occupied board cells in "x,y" format
*/ */
export function checkBoardCollision( export function checkBoardCollision(
shape: ParsedShape, shape: ParsedShape,
transform: Transform2D, transform: Transform2D,
occupiedCells: Set<string> occupiedCells: Set<string>,
): boolean { ): boolean {
const cells = transformShape(shape, transform); const cells = transformShape(shape, transform);
for (const cell of cells) { for (const cell of cells) {
if (occupiedCells.has(`${cell.x},${cell.y}`)) { if (occupiedCells.has(`${cell.x},${cell.y}`)) {
return true; return true;
}
} }
}
return false; return false;
} }
/** /**
@ -156,42 +159,47 @@ export function checkBoardCollision(
* @param boardHeight Board height * @param boardHeight Board height
*/ */
export function checkBounds( export function checkBounds(
shape: ParsedShape, shape: ParsedShape,
transform: Transform2D, transform: Transform2D,
boardWidth: number, boardWidth: number,
boardHeight: number boardHeight: number,
): boolean { ): boolean {
const cells = transformShape(shape, transform); const cells = transformShape(shape, transform);
for (const cell of cells) { for (const cell of cells) {
if (cell.x < 0 || cell.x >= boardWidth || cell.y < 0 || cell.y >= boardHeight) { if (
return false; cell.x < 0 ||
} cell.x >= boardWidth ||
cell.y < 0 ||
cell.y >= boardHeight
) {
return false;
} }
}
return true; return true;
} }
/** /**
* Validates that a placement is both in bounds and collision-free. * Validates that a placement is both in bounds and collision-free.
* @returns Object with `valid` flag and optional `reason` string * @returns Object with `valid` flag and optional `reason` string
*/ */
export function validatePlacement( export function validateShapePlacement(
shape: ParsedShape, shape: ParsedShape,
transform: Transform2D, transform: Transform2D,
boardWidth: number, boardWidth: number,
boardHeight: number, boardHeight: number,
occupiedCells: Set<string> occupiedCells: Set<string>,
): { valid: true } | { valid: false; reason: string } { ): { valid: true } | { valid: false; reason: string } {
if (!checkBounds(shape, transform, boardWidth, boardHeight)) { if (!checkBounds(shape, transform, boardWidth, boardHeight)) {
return { valid: false, reason: '超出边界' }; return { valid: false, reason: "超出边界" };
} }
if (checkBoardCollision(shape, transform, occupiedCells)) { if (checkBoardCollision(shape, transform, occupiedCells)) {
return { valid: false, reason: '与已有形状重叠' }; return { valid: false, reason: "与已有形状重叠" };
} }
return { valid: true }; return { valid: true };
} }
/** /**
@ -199,29 +207,32 @@ export function validatePlacement(
* @param current The current transform * @param current The current transform
* @param degrees Degrees to rotate (typically 90, 180, or 270) * @param degrees Degrees to rotate (typically 90, 180, or 270)
*/ */
export function rotateTransform(current: Transform2D, degrees: number): Transform2D { export function rotateTransform(
return { current: Transform2D,
...current, degrees: number,
rotation: ((current.rotation + degrees) % 360 + 360) % 360, ): Transform2D {
}; return {
...current,
rotation: (((current.rotation + degrees) % 360) + 360) % 360,
};
} }
/** /**
* Flips a transform horizontally. * Flips a transform horizontally.
*/ */
export function flipXTransform(current: Transform2D): Transform2D { export function flipXTransform(current: Transform2D): Transform2D {
return { return {
...current, ...current,
flipX: !current.flipX, flipX: !current.flipX,
}; };
} }
/** /**
* Flips a transform vertically. * Flips a transform vertically.
*/ */
export function flipYTransform(current: Transform2D): Transform2D { export function flipYTransform(current: Transform2D): Transform2D {
return { return {
...current, ...current,
flipY: !current.flipY, flipY: !current.flipY,
}; };
} }