UPD: Compute MoveResult before mutating state of piece

This commit is contained in:
sebastian 2026-08-05 18:59:36 +02:00
parent f86e1b872a
commit 4ab4ea5262
4 changed files with 62 additions and 52 deletions

View File

@ -20,41 +20,17 @@ std::vector<ludo::LudoEvent> ludo::LudoGameMode::pollEvents() {
return events; return events;
} }
std::optional<int> ludo::LudoGameMode::findLowestHomeSlotPiece(PlayerColor color) const { ludo::LudoRules::MoveResult ludo::LudoGameMode::movePieceInternal(int pieceIndex, int diceValue) {
for (int i = 0; i < static_cast<int>(m_gameState.m_pieces.size()); ++i) { auto result = LudoRules::computeMoveResult(m_gameState, pieceIndex, diceValue);
const auto& piece = m_gameState.m_pieces[i];
if (piece.color == color && piece.state == PieceState::AtHome) {
return i; // erste Übereinstimmung = kleinster Home-Slot, dank Erzeugungsreihenfolge
}
}
return std::nullopt;
}
ludo::LudoGameMode::MoveResult ludo::LudoGameMode::movePieceInternal(int pieceIndex, int diceValue) {
Piece& piece = m_gameState.m_pieces[pieceIndex]; Piece& piece = m_gameState.m_pieces[pieceIndex];
int fromPosition = piece.position; piece.state = result.targetState;
piece.position = result.toPosition;
Destination destination = LudoRules::computeDestination(m_gameState, piece, diceValue).value(); if (result.captured) {
Piece& capturedPiece = m_gameState.m_pieces[result.capturedPieceIndex];
PieceState startState = piece.state; capturedPiece.state = PieceState::AtHome;
PieceState targetState = destination.state; capturedPiece.position = -1;
piece.state = destination.state;
piece.position = destination.position;
MoveResult result{fromPosition, piece.position, false, -1, targetState, startState};
if (piece.state == PieceState::OnTrack) {
for (int i = 0; i < static_cast<int>(m_gameState.m_pieces.size()); ++i) {
if (i == pieceIndex) continue;
Piece& other = m_gameState.m_pieces[i];
if (other.color != piece.color && other.state == PieceState::OnTrack && other.position == piece.position) {
other.state = PieceState::AtHome;
other.position = -1;
result.captured = true;
result.capturedPieceIndex = i;
break; // dank Blockade-Regel kann max. eine gegnerische Figur auf einem Feld stehen
}
}
} }
return result; return result;
@ -78,8 +54,8 @@ void ludo::LudoGameMode::handle(const RollDiceCommand &command) {
publishEvent(DiceRolledEvent(command.player, m_gameState.m_diceValue)); publishEvent(DiceRolledEvent(command.player, m_gameState.m_diceValue));
if (m_gameState.m_diceValue == 6) { if (m_gameState.m_diceValue == 6) {
if (auto homeIndex = findLowestHomeSlotPiece(getColorOf(command.player))) { if (auto homeIndex = LudoRules::findLowestHomeSlotPiece(m_gameState, getColorOf(command.player))) {
if (!LudoRules::isBlockedByOwnPiece(m_gameState, getColorOf(command.player), PieceState::OnTrack, getEntryOffset(getColorOf(command.player)))) { if (!LudoRules::isBlockedByOwnPiece(m_gameState, getColorOf(command.player), PieceState::OnTrack, LudoRules::getEntryOffset(getColorOf(command.player)))) {
autoReleasePiece(*homeIndex); autoReleasePiece(*homeIndex);
finishTurn(); finishTurn();
return; return;
@ -154,10 +130,6 @@ int ludo::LudoGameMode::rollDice() {
return m_diceSource->roll(); return m_diceSource->roll();
} }
int ludo::LudoGameMode::getEntryOffset(PlayerColor color) {
return static_cast<int>(color) * 10;
}
void ludo::LudoGameMode::publishEvent(LudoEvent event) { void ludo::LudoGameMode::publishEvent(LudoEvent event) {
m_pendingEvents.push_back(event); m_pendingEvents.push_back(event);
m_eventBus.publish(event); m_eventBus.publish(event);

View File

@ -13,6 +13,7 @@
#include "LudoTypes.h" #include "LudoTypes.h"
#include "core/events/EventBus.h" #include "core/events/EventBus.h"
#include "game/TurnBasedGameMode.h" #include "game/TurnBasedGameMode.h"
#include "gameMode/LudoRules.h"
namespace ludo { namespace ludo {
@ -26,24 +27,12 @@ namespace ludo {
[[nodiscard]] const LudoGameState& getState() const override { return m_gameState; } [[nodiscard]] const LudoGameState& getState() const override { return m_gameState; }
[[nodiscard]] PlayerColor getColorOf(engine::PlayerID playerID) const; [[nodiscard]] PlayerColor getColorOf(engine::PlayerID playerID) const;
[[nodiscard]] static int getEntryOffset(PlayerColor color);
void setDiceSource(std::unique_ptr<IDiceSource> diceSource) { m_diceSource = std::move(diceSource); } void setDiceSource(std::unique_ptr<IDiceSource> diceSource) { m_diceSource = std::move(diceSource); }
private: private:
engine::EventBus<LudoEvent>& m_eventBus; engine::EventBus<LudoEvent>& m_eventBus;
struct MoveResult {
int fromPosition = 0;
int toPosition = 0;
bool captured = false;
int capturedPieceIndex = -1;
PieceState targetState = PieceState::OnTrack;
PieceState startState = PieceState::OnTrack;
};
[[nodiscard]] std::optional<int> findLowestHomeSlotPiece(PlayerColor color) const;
MoveResult movePieceInternal(int pieceIndex, int diceValue);
LudoRules::MoveResult movePieceInternal(int pieceIndex, int diceValue);
void autoReleasePiece(int pieceIndex); void autoReleasePiece(int pieceIndex);
void handle(const RollDiceCommand &command); void handle(const RollDiceCommand &command);

View File

@ -82,3 +82,39 @@ std::vector<int> ludo::LudoRules::getMoveablePieceIndices(const LudoGameState &s
} }
return moveablePieceIndices; return moveablePieceIndices;
} }
std::optional<int> ludo::LudoRules::findLowestHomeSlotPiece(const LudoGameState &state, PlayerColor color) {
for (int i = 0; i < static_cast<int>(state.getPieces().size()); ++i) {
const auto& piece = state.getPieces()[i];
if (piece.color == color && piece.state == PieceState::AtHome) {
return i; // erste Übereinstimmung = kleinster Home-Slot, dank Erzeugungsreihenfolge
}
}
return std::nullopt;
}
ludo::LudoRules::MoveResult ludo::LudoRules::computeMoveResult(const LudoGameState &state, int pieceIndex, int diceValue) {
const Piece& piece = state.getPieces()[pieceIndex];
int fromPosition = piece.position;
Destination destination = computeDestination(state, piece, diceValue).value();
PieceState startState = piece.state;
PieceState targetState = destination.state;
MoveResult result{fromPosition, destination.position, false, -1, targetState, startState};
if (targetState == PieceState::OnTrack) {
for (int i = 0; i < static_cast<int>(state.getPieces().size()); ++i) {
if (i == pieceIndex) continue;
const Piece& other = state.getPieces()[i];
if (other.color != piece.color && other.state == PieceState::OnTrack && other.position == destination.position) {
result.captured = true;
result.capturedPieceIndex = i;
break; // dank Blockade-Regel max. eine gegnerische Figur pro Feld
}
}
}
return result;
}

View File

@ -33,6 +33,19 @@ namespace ludo {
static std::vector<int> getMoveablePieceIndices(const LudoGameState& state, PlayerColor color, int diceValue); static std::vector<int> getMoveablePieceIndices(const LudoGameState& state, PlayerColor color, int diceValue);
static std::optional<int> findLowestHomeSlotPiece(const LudoGameState& state, PlayerColor color);
struct MoveResult {
int fromPosition = 0;
int toPosition = 0;
bool captured = false;
int capturedPieceIndex = -1;
PieceState targetState = PieceState::OnTrack;
PieceState startState = PieceState::OnTrack;
};
static MoveResult computeMoveResult(const LudoGameState& state, int pieceIndex, int diceValue);
}; };