move method

LudoEngineMoveResult move(
  1. LudoGameState state,
  2. int pieceId
)

Implementation

LudoEngineMoveResult move(LudoGameState state, int pieceId) {
  final chosen    = state.legalMoves.firstWhere((m) => m.pieceId == pieceId);
  final piece     = state.pieces.firstWhere((p) => p.id == pieceId);
  final movedPiece = piece.copyWith(trackPosition: chosen.toPosition);

  var pieces = [
    for (final p in state.pieces) p.id == pieceId ? movedPiece : p,
  ];

  // ── captures ─────────────────────────────────────────────────
  final captured = captureOpponents(
    pieces: pieces,
    mover: movedPiece,
    teams: teams,
  );
  if (captured.isNotEmpty) {
    final capturedIds = captured.map((c) => c.id).toSet();
    pieces = [
      for (final p in pieces)
        capturedIds.contains(p.id)
            ? p.copyWith(trackPosition: LudoPiece.home)
            : p,
    ];
  }

  final diceValue    = state.diceValue!;
  final totalPlayers = state.players.length;

  // ── individual player win ─────────────────────────────────────
  final justWon = hasPlayerWon(pieces, movedPiece.playerIndex) &&
      !state.winners.contains(movedPiece.playerIndex);

  var winners = state.winners;
  if (justWon) {
    winners = [...winners, movedPiece.playerIndex];
  }

  // ── team win check ────────────────────────────────────────────
  bool teamJustWon = false;
  if (teams != null && justWon) {
    final myTeam = teamOf(movedPiece.playerIndex, teams);
    if (myTeam != null && hasTeamWon(pieces, myTeam)) {
      teamJustWon = true;
      // Also add teammate to winners list if not already there
      final mate = myTeam.teammateOf(movedPiece.playerIndex);
      if (!winners.contains(mate)) {
        winners = [...winners, mate];
      }
    }
  }

  // ── game finished ─────────────────────────────────────────────
  final gameFinished = isGameFinished(
    winners.length,
    totalPlayers,
    teams: teams,
    pieces: pieces,
  );

  // Auto-add last-place player(s) in standard mode
  if (gameFinished && teams == null && winners.length == totalPlayers - 1) {
    final last = List<int>.generate(totalPlayers, (i) => i)
        .firstWhere((i) => !winners.contains(i));
    winners = [...winners, last];
  }

  // In teams mode, auto-add losing team to winners (last place)
  if (gameFinished && teams != null) {
    for (final t in teams!) {
      for (final pi in t.playerIndices) {
        if (!winners.contains(pi)) winners = [...winners, pi];
      }
    }
  }

  final extraTurn  = !gameFinished && diceRules.grantsExtraTurn(diceValue);
  final turnPassed = !gameFinished && !extraTurn;

  final nextPlayerIndex = gameFinished || extraTurn
      ? state.currentPlayerIndex
      : _nextPlayer(
          state.copyWith(winners: winners),
          state.currentPlayerIndex,
        );

  final newState = state.copyWith(
    pieces: pieces,
    winners: winners,
    currentPlayerIndex: nextPlayerIndex,
    phase: gameFinished ? LudoTurnPhase.gameOver : LudoTurnPhase.awaitingRoll,
    legalMoves: const [],
    clearDiceValue: true,
  );

  return LudoEngineMoveResult(
    state: newState,
    movedPiece: movedPiece,
    fromPosition: chosen.fromPosition,
    toPosition: chosen.toPosition,
    capturedPieces: captured,
    playerWon: justWon,
    teamWon: teamJustWon,
    turnPassed: turnPassed,
    gameFinished: gameFinished,
  );
}