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(); |