File size: 2,628 Bytes
6ce4ca6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
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();