core/animation-proxy.ts

import { isAnimated } from "./animated.ts";
import { Board } from "./board.ts";
import { GameEvent } from "./game-event.ts";
import { Piece } from "./piece.ts";

/**
 * AnimationProxy — bridges immutable piece singletons and their per-position
 * animation state (frame counter).
 *
 * Mirrors Java's AnimationProxy: every animated piece placed on the board gets
 * its own proxy that tracks (x, y) and an independent frame counter. The piece
 * itself stays immutable; the proxy carries the mutable frame state.
 *
 * The Board maintains a list of these; AnimationManager walks the list each
 * tick instead of scanning every cell.
 */
export class AnimationProxy {
  x: number;
  y: number;
  piece: Piece;
  frame: number;
  constructor(x: number, y: number, piece: Piece, randomSeed = true) {
    this.x = x;
    this.y = y;
    this.piece = piece;
    this.frame = randomSeed ? Math.floor(Math.random() * 100) : 0;
  }

  /** True if this proxy represents the given piece at the given position. */
  proxyFor(x: number, y: number, piece: Piece): boolean {
    return this.x === x && this.y === y && this.piece === piece;
  }

  /**
   * Update position without destroying/recreating the proxy (used when an
   * agent moves to an adjacent cell).
   */
  setXY(x: number, y: number) {
    this.x = x;
    this.y = y;
  }

  /**
   * Execute one animation frame: call piece.onFrame with the current counter,
   * then increment it.
   */
  tick(event: GameEvent, board: Board) {
    const cell = board.getCellAt(this.x, this.y)!;
    if (isAnimated(this.piece)) {
      this.piece.onFrame(event, cell, this.frame);
    }
    this.frame++;
  }
}