Spaces:
Running
Running
| import type { Position3D } from "./positionUtils"; | |
| /** | |
| * Spiral-based position manager | |
| * Assigns positions in a spiral pattern starting from center to avoid overlapping objects | |
| * | |
| * Pattern: Center -> Right -> Up -> Left -> Down -> Right (outward spiral) | |
| * Example positions: (0,0) -> (1,0) -> (1,-1) -> (0,-1) -> (-1,-1) -> (-1,0) -> (-1,1) -> (0,1) -> (1,1) -> (2,1) ... | |
| */ | |
| export class PositionManager { | |
| private static instance: PositionManager; | |
| private gridSize = 5; // Distance between grid points | |
| private spiralGenerator: Generator<{ x: number; z: number }, never, unknown>; | |
| static getInstance(): PositionManager { | |
| if (!PositionManager.instance) { | |
| PositionManager.instance = new PositionManager(); | |
| } | |
| return PositionManager.instance; | |
| } | |
| constructor() { | |
| this.spiralGenerator = this.generateSpiralPositions(); | |
| // Skip the center position since there's already an object there | |
| this.spiralGenerator.next(); | |
| } | |
| /** | |
| * Get next available position in a spiral pattern | |
| * Starts from center (0,0) and spirals outward | |
| */ | |
| getNextPosition(): Position3D { | |
| const { value: coord } = this.spiralGenerator.next(); | |
| return { | |
| x: coord.x * this.gridSize, | |
| y: 0, | |
| z: coord.z * this.gridSize | |
| }; | |
| } | |
| /** | |
| * Generator function that yields spiral positions infinitely | |
| * Uses a simple clockwise spiral starting from origin | |
| */ | |
| private *generateSpiralPositions(): Generator<{ x: number; z: number }, never, unknown> { | |
| let x = 0, | |
| z = 0; | |
| let dx = 1, | |
| dz = 0; // Start moving right | |
| let steps = 1; | |
| let stepCount = 0; | |
| let changeDirection = 0; | |
| // Yield center position first | |
| yield { x, z }; | |
| // Generate spiral positions infinitely | |
| while (true) { | |
| x += dx; | |
| z += dz; | |
| yield { x, z }; | |
| stepCount++; | |
| // Change direction when we've completed the required steps | |
| if (stepCount === steps) { | |
| stepCount = 0; | |
| changeDirection++; | |
| // Rotate 90 degrees clockwise: (dx, dz) -> (dz, -dx) | |
| const temp = dx; | |
| dx = dz; | |
| dz = -temp; | |
| // Increase step count after every two direction changes | |
| if (changeDirection % 2 === 0) { | |
| steps++; | |
| } | |
| } | |
| } | |
| } | |
| /** | |
| * Reset position generator (useful for testing) | |
| */ | |
| reset(): void { | |
| this.spiralGenerator = this.generateSpiralPositions(); | |
| // Skip the center position since there's already an object there | |
| this.spiralGenerator.next(); | |
| } | |
| } | |
| // Global instance | |
| export const positionManager = PositionManager.getInstance(); | |