move method
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,
);
}