Newer
Older
PixelPaintWar / apps / client / src / scenes / game / entities / map / GameMapModel.ts
/**
 * GameMapModel
 * マップセルの色状態を管理する計算モデル
 * 全体更新と差分更新を適用して描画入力用の状態を保持する
 */
import { config } from "@client/config";
import type { domain } from "@repo/shared";

/** マップセル状態の計算責務を担うモデル */
export class GameMapModel {
  private readonly cellTeamIds: number[];

  /** 設定値に基づいて初期セル状態を構築する */
  constructor() {
    const { GRID_COLS, GRID_ROWS } = config.GAME_CONFIG;
    this.cellTeamIds = new Array(GRID_COLS * GRID_ROWS).fill(-1);
  }

  /** 全体マップ状態を適用する */
  public applyMapState(state: domain.gridMap.MapState): void {
    const maxLength = Math.min(
      this.cellTeamIds.length,
      state.gridColors.length,
    );
    for (let index = 0; index < maxLength; index++) {
      this.cellTeamIds[index] = state.gridColors[index];
    }
  }

  /** 差分セル更新を適用する */
  public applyUpdates(updates: domain.gridMap.CellUpdate[]): void {
    updates.forEach(({ index, teamId }) => {
      if (!this.isValidIndex(index)) return;
      this.cellTeamIds[index] = teamId;
    });
  }

  /** 指定セルのチームIDを取得する */
  public getTeamId(index: number): number | undefined {
    if (!this.isValidIndex(index)) return undefined;
    return this.cellTeamIds[index];
  }

  /** 描画用の全セル状態を取得する */
  public getAllTeamIds(): number[] {
    return [...this.cellTeamIds];
  }

  /** チームごとの塗り率配列を取得する */
  public getPaintRatesByTeam(teamCount: number): number[] {
    if (teamCount <= 0) {
      return [];
    }

    const paintedCounts = new Array<number>(teamCount).fill(0);
    const totalCells = this.cellTeamIds.length;

    this.cellTeamIds.forEach((teamId) => {
      if (!Number.isInteger(teamId) || teamId < 0 || teamId >= teamCount) {
        return;
      }

      paintedCounts[teamId] += 1;
    });

    if (totalCells <= 0) {
      return paintedCounts.map(() => 0);
    }

    return paintedCounts.map((count) => (count / totalCells) * 100);
  }

  /** セル添字が有効範囲内かを判定する */
  private isValidIndex(index: number): boolean {
    return (
      Number.isInteger(index) && index >= 0 && index < this.cellTeamIds.length
    );
  }
}