FIX: Correct Handling of Captured Case
This commit is contained in:
parent
cdc6a1f92c
commit
c755d39677
@ -147,10 +147,19 @@ void ludo::LudoGameMode::handle(const MovePieceCommand &command) {
|
|||||||
spdlog::info("MovePieceCommand akzeptiert: pieceIndex={}", command.pieceIndex);
|
spdlog::info("MovePieceCommand akzeptiert: pieceIndex={}", command.pieceIndex);
|
||||||
|
|
||||||
auto result = movePieceInternal(command.pieceIndex, m_gameState.m_diceValue);
|
auto result = movePieceInternal(command.pieceIndex, m_gameState.m_diceValue);
|
||||||
publishEvent(PieceMovedEvent{command.pieceIndex, result.fromPosition, result.toPosition, result.captured, result.targetState, result.startState});
|
publishEvent(PieceMovedEvent::create(command.pieceIndex, result.fromPosition, result.toPosition, result.captured, result.startState, result.targetState));
|
||||||
if (result.captured) {
|
if (result.captured) {
|
||||||
spdlog::info("MovePieceCommand: gegnerische Figur auf {} geworfen", result.toPosition);
|
spdlog::info("MovePieceCommand: gegnerische Figur auf {} geworfen", result.toPosition);
|
||||||
publishEvent(PieceMovedEvent{result.capturedPieceIndex, result.toPosition, -1, false});
|
auto freeHomePositions = m_gameState.getFreeHomePositions(m_gameState.getColorOfPieceIndex(result.capturedPieceIndex));
|
||||||
|
if (!freeHomePositions.empty()) {
|
||||||
|
Piece capturedPiece = m_gameState.m_pieces[result.capturedPieceIndex];
|
||||||
|
PieceMovedEvent event = PieceMovedEvent::create(result.capturedPieceIndex, capturedPiece.position, freeHomePositions.front(), true, capturedPiece.state, PieceState::AtHome);
|
||||||
|
publishEvent(event);
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::format("No free home positions for captured piece {}",std::string(ludo::toString(m_gameState.getColorOfPieceIndex(result.capturedPieceIndex))))
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
finishTurn();
|
finishTurn();
|
||||||
}
|
}
|
||||||
@ -238,9 +247,26 @@ namespace {
|
|||||||
}
|
}
|
||||||
throw std::invalid_argument("computePath: unbekannter PieceState");
|
throw std::invalid_argument("computePath: unbekannter PieceState");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::vector<ludo::PathNode> ludo::LudoGameMode::computePath(PlayerColor color, PieceState startingState, int startPosition, PieceState targetState, int targetPosition) {
|
std::vector<ludo::PathNode> ludo::LudoGameMode::computePath(PlayerColor color, PieceState startingState, int startPosition, PieceState targetState, int targetPosition) {
|
||||||
|
auto errorContext = [&]() {
|
||||||
|
return std::format(
|
||||||
|
"color={}, startState={}, startPosition={}, targetState={}, targetPosition={}, "
|
||||||
|
"kTrackLength={}, kHomeStretchLength={}",
|
||||||
|
toString(color),
|
||||||
|
toString(startingState),
|
||||||
|
startPosition,
|
||||||
|
toString(targetState),
|
||||||
|
targetPosition,
|
||||||
|
kTrackLength,
|
||||||
|
ludo::kHomeStretchLength
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
if (startingState == targetState && startPosition == targetPosition) {
|
if (startingState == targetState && startPosition == targetPosition) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -249,55 +275,131 @@ std::vector<ludo::PathNode> ludo::LudoGameMode::computePath(PlayerColor color, P
|
|||||||
if (targetState == PieceState::AtHome) {
|
if (targetState == PieceState::AtHome) {
|
||||||
if (startingState != PieceState::OnTrack) {
|
if (startingState != PieceState::OnTrack) {
|
||||||
throw std::invalid_argument(
|
throw std::invalid_argument(
|
||||||
"computePath: targetState==AtHome ist nur von OnTrack aus erlaubt (Capture)");
|
std::format(
|
||||||
|
"computePath: targetState==AtHome ist nur von OnTrack aus erlaubt (Capture). {}",
|
||||||
|
errorContext()
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return { PathNode{startingState, startPosition}, PathNode{targetState, targetPosition} };
|
|
||||||
|
return {
|
||||||
|
PathNode{startingState, startPosition},
|
||||||
|
PathNode{targetState, targetPosition}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// --- Nur Vorwärtsbewegungen sind erlaubt ---
|
// --- Nur Vorwärtsbewegungen sind erlaubt ---
|
||||||
if (stateOrder(targetState) < stateOrder(startingState)) {
|
if (stateOrder(targetState) < stateOrder(startingState)) {
|
||||||
throw std::invalid_argument(
|
throw std::invalid_argument(
|
||||||
"computePath: targetState liegt vor startingState (Rueckwaerts nicht unterstuetzt)");
|
std::format(
|
||||||
|
"computePath: targetState liegt vor startingState (Rueckwaerts nicht unterstuetzt). "
|
||||||
|
"stateOrder(start)={}, stateOrder(target)={}. {}",
|
||||||
|
stateOrder(startingState),
|
||||||
|
stateOrder(targetState),
|
||||||
|
errorContext()
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetState == PieceState::AtHome) {
|
|
||||||
throw std::invalid_argument(
|
|
||||||
"computePath: AtHome kann kein Zielzustand sein (ausser Start==Ziel)");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (startingState == PieceState::Finished) {
|
if (startingState == PieceState::Finished) {
|
||||||
// hier nur erreichbar, wenn targetState/targetPosition abweicht (early return greift sonst)
|
|
||||||
throw std::invalid_argument(
|
throw std::invalid_argument(
|
||||||
"computePath: startingState ist bereits Finished, aber Ziel weicht ab");
|
std::format(
|
||||||
|
"computePath: startingState ist bereits Finished, aber Ziel weicht ab. {}",
|
||||||
|
errorContext()
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (startingState == PieceState::InHomeStretch && targetState == PieceState::InHomeStretch
|
|
||||||
&& targetPosition < startPosition) {
|
if (startingState == PieceState::InHomeStretch &&
|
||||||
|
targetState == PieceState::InHomeStretch &&
|
||||||
|
targetPosition < startPosition) {
|
||||||
|
|
||||||
throw std::invalid_argument(
|
throw std::invalid_argument(
|
||||||
"computePath: targetPosition liegt in InHomeStretch vor startPosition");
|
std::format(
|
||||||
|
"computePath: targetPosition liegt im HomeStretch vor startPosition "
|
||||||
|
"(Rueckwaertsbewegung). {}",
|
||||||
|
errorContext()
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// --- Positionsbereiche ---
|
// --- Positionsbereiche ---
|
||||||
if (targetState == PieceState::OnTrack
|
if (targetState == PieceState::OnTrack &&
|
||||||
&& (targetPosition < 0 || targetPosition >= kTrackLength)) {
|
(targetPosition < 0 || targetPosition >= kTrackLength)) {
|
||||||
throw std::invalid_argument("computePath: targetPosition ausserhalb OnTrack-Bereich");
|
|
||||||
}
|
|
||||||
if (targetState == PieceState::InHomeStretch
|
|
||||||
&& (targetPosition < 0 || targetPosition >= kHomeStretchLength)) {
|
|
||||||
throw std::invalid_argument("computePath: targetPosition ausserhalb InHomeStretch-Bereich");
|
|
||||||
}
|
|
||||||
if (targetState == PieceState::Finished && targetPosition != kHomeStretchLength - 1) {
|
|
||||||
// <-- vermutlich dein aktueller Bug
|
|
||||||
throw std::invalid_argument(
|
throw std::invalid_argument(
|
||||||
"computePath: targetPosition fuer Finished muss kHomeStretchLength - 1 sein");
|
std::format(
|
||||||
|
"computePath: targetPosition ausserhalb OnTrack-Bereich. "
|
||||||
|
"Erwartet [0,{}), erhalten {}. {}",
|
||||||
|
kTrackLength,
|
||||||
|
targetPosition,
|
||||||
|
errorContext()
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (startingState == PieceState::OnTrack
|
|
||||||
&& (startPosition < 0 || startPosition >= kTrackLength)) {
|
|
||||||
throw std::invalid_argument("computePath: startPosition ausserhalb OnTrack-Bereich");
|
if (targetState == PieceState::InHomeStretch &&
|
||||||
|
(targetPosition < 0 || targetPosition >= kHomeStretchLength)) {
|
||||||
|
|
||||||
|
throw std::invalid_argument(
|
||||||
|
std::format(
|
||||||
|
"computePath: targetPosition ausserhalb InHomeStretch-Bereich. "
|
||||||
|
"Erwartet [0,{}), erhalten {}. {}",
|
||||||
|
kHomeStretchLength,
|
||||||
|
targetPosition,
|
||||||
|
errorContext()
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (startingState == PieceState::InHomeStretch
|
|
||||||
&& (startPosition < 0 || startPosition >= kHomeStretchLength)) {
|
|
||||||
throw std::invalid_argument("computePath: startPosition ausserhalb InHomeStretch-Bereich");
|
if (targetState == PieceState::Finished &&
|
||||||
|
targetPosition != kHomeStretchLength - 1) {
|
||||||
|
|
||||||
|
throw std::invalid_argument(
|
||||||
|
std::format(
|
||||||
|
"computePath: targetPosition fuer Finished ungueltig. "
|
||||||
|
"Erwartet {}, erhalten {}. {}",
|
||||||
|
kHomeStretchLength - 1,
|
||||||
|
targetPosition,
|
||||||
|
errorContext()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (startingState == PieceState::OnTrack &&
|
||||||
|
(startPosition < 0 || startPosition >= kTrackLength)) {
|
||||||
|
|
||||||
|
throw std::invalid_argument(
|
||||||
|
std::format(
|
||||||
|
"computePath: startPosition ausserhalb OnTrack-Bereich. "
|
||||||
|
"Erwartet [0,{}), erhalten {}. {}",
|
||||||
|
kTrackLength,
|
||||||
|
startPosition,
|
||||||
|
errorContext()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (startingState == PieceState::InHomeStretch &&
|
||||||
|
(startPosition < 0 || startPosition >= kHomeStretchLength)) {
|
||||||
|
|
||||||
|
throw std::invalid_argument(
|
||||||
|
std::format(
|
||||||
|
"computePath: startPosition ausserhalb InHomeStretch-Bereich. "
|
||||||
|
"Erwartet [0,{}), erhalten {}. {}",
|
||||||
|
kHomeStretchLength,
|
||||||
|
startPosition,
|
||||||
|
errorContext()
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<PathNode> path;
|
std::vector<PathNode> path;
|
||||||
|
|||||||
@ -42,6 +42,7 @@ namespace ludo {
|
|||||||
|
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr std::array<PlayerColor, static_cast<size_t>(PlayerColor::Count)> PlayerColors = {
|
constexpr std::array<PlayerColor, static_cast<size_t>(PlayerColor::Count)> PlayerColors = {
|
||||||
PlayerColor::Red,
|
PlayerColor::Red,
|
||||||
PlayerColor::Blue,
|
PlayerColor::Blue,
|
||||||
@ -55,6 +56,22 @@ namespace ludo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum class PieceState : uint8_t { AtHome, OnTrack, InHomeStretch, Finished };
|
enum class PieceState : uint8_t { AtHome, OnTrack, InHomeStretch, Finished };
|
||||||
|
constexpr std::string_view toString(PieceState state)
|
||||||
|
{
|
||||||
|
switch(state)
|
||||||
|
{
|
||||||
|
case PieceState::AtHome:
|
||||||
|
return "AtHome";
|
||||||
|
case PieceState::OnTrack:
|
||||||
|
return "OnTrack";
|
||||||
|
case PieceState::InHomeStretch:
|
||||||
|
return "InHomeStretch";
|
||||||
|
case PieceState::Finished:
|
||||||
|
return "Finished";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
enum class TurnPhase : uint8_t { AwaitingRoll, AwaitingPieceSelection };
|
enum class TurnPhase : uint8_t { AwaitingRoll, AwaitingPieceSelection };
|
||||||
|
|
||||||
struct Piece {
|
struct Piece {
|
||||||
@ -83,6 +100,21 @@ namespace ludo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
PieceMovedEvent(
|
||||||
|
int pieceIndex,
|
||||||
|
int fromPosition,
|
||||||
|
int toPosition,
|
||||||
|
bool captured,
|
||||||
|
PieceState targetState,
|
||||||
|
PieceState startState)
|
||||||
|
:
|
||||||
|
pieceIndex(pieceIndex),
|
||||||
|
fromPosition(fromPosition),
|
||||||
|
toPosition(toPosition),
|
||||||
|
captured(captured),
|
||||||
|
targetState(targetState),
|
||||||
|
startState(startState)
|
||||||
|
{}
|
||||||
static void validate(PieceState startState, int fromPosition,
|
static void validate(PieceState startState, int fromPosition,
|
||||||
PieceState targetState, int toPosition, bool captured) {
|
PieceState targetState, int toPosition, bool captured) {
|
||||||
if (captured && targetState != PieceState::AtHome) {
|
if (captured && targetState != PieceState::AtHome) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user