ADD: Tests for LudoGameMode::computePath

This commit is contained in:
sebastian 2026-08-05 07:47:24 +02:00
parent a278ce14c5
commit 12c617587f
2 changed files with 113 additions and 0 deletions

View File

@ -17,6 +17,15 @@ namespace ludo {
struct PathNode {
PieceState state;
int position;
friend bool operator==(const PathNode& lhs, const PathNode& rhs) {
return lhs.state == rhs.state && lhs.position == rhs.position;
}
static inline void PrintTo(const PathNode& node, std::ostream* os) {
*os << "PathNode{state=" << static_cast<int>(node.state)
<< ", position=" << node.position << "}";
}
};
class LudoGameMode: public engine::TurnBasedGameMode<LudoCommand, LudoEvent, LudoGameState> {

View File

@ -35,4 +35,108 @@ TEST(LudoGameMode, SecondSixMovesOutOfBlockedEntry) {
const auto& piece = mode.getState().getPieces()[0];
EXPECT_EQ(piece.state, ludo::PieceState::OnTrack);
EXPECT_EQ(piece.position, 6);
}
using ColorPosParam = std::tuple<ludo::PlayerColor, int>;
class MoveOutOfHomeTest : public ::testing::TestWithParam<ColorPosParam> {};
void assertPathIsWellFormed(const std::vector<ludo::PathNode>& path) {
using ludo::PieceState;
for (size_t i = 1; i < path.size(); ++i) {
const auto& prev = path[i - 1];
const auto& cur = path[i];
if (prev.state == PieceState::OnTrack && cur.state == PieceState::OnTrack) {
EXPECT_EQ(cur.position, (prev.position + 1) % ludo::kTrackLength) << "at i=" << i;
} else if (prev.state == PieceState::InHomeStretch && cur.state == PieceState::InHomeStretch) {
EXPECT_EQ(cur.position, prev.position + 1) << "at i=" << i;
} else if (prev.state == PieceState::OnTrack && cur.state == PieceState::InHomeStretch) {
EXPECT_EQ(cur.position, 0) << "at i=" << i;
} else if (prev.state == PieceState::InHomeStretch && cur.state == PieceState::Finished) {
EXPECT_EQ(prev.position, ludo::kHomeStretchLength - 1) << "at i=" << i;
} else if (prev.state == PieceState::AtHome && cur.state == PieceState::OnTrack) {
// ok, Position ist der Entry-Offset - separat geprüft
} else {
ADD_FAILURE() << "unerwarteter Zustandswechsel bei i=" << i;
}
}
}
TEST_P(MoveOutOfHomeTest, EntersTrackAtEntryOffset) {
auto [color, startPos] = GetParam();
const int entry = ludo::LudoGameMode::getEntryOffset(color);
auto path = ludo::LudoGameMode::computePath(
color, ludo::PieceState::AtHome, startPos,
ludo::PieceState::OnTrack, entry);
ASSERT_EQ(path.size(), 2u);
EXPECT_EQ(path[0].state, ludo::PieceState::AtHome);
EXPECT_EQ(path[0].position, startPos);
EXPECT_EQ(path[1].state, ludo::PieceState::OnTrack);
EXPECT_EQ(path[1].position, entry);
assertPathIsWellFormed(path);
}
INSTANTIATE_TEST_SUITE_P(
AllColorsAllHomeSlots,
MoveOutOfHomeTest,
::testing::Combine(
::testing::Values(ludo::PlayerColor::Red, ludo::PlayerColor::Blue,
ludo::PlayerColor::Green, ludo::PlayerColor::Yellow),
::testing::Range(0, 4)));
int expectedStepCount(ludo::PlayerColor color, ludo::PieceState fromState, int fromPos, ludo::PieceState toState, int toPos) {
using ludo::PieceState;
const int entry = ludo::LudoGameMode::getEntryOffset(color);
int steps = 0;
PieceState state = fromState;
int pos = fromPos;
if (state == PieceState::AtHome) {
steps += 1;
state = PieceState::OnTrack;
pos = entry;
}
if (state == PieceState::OnTrack) {
if (toState == PieceState::OnTrack) {
return steps + (toPos - pos + ludo::kTrackLength) % ludo::kTrackLength;
}
steps += (entry - pos + ludo::kTrackLength) % ludo::kTrackLength; // bis zum Entry
steps += 1; // Abbiegen in Home Stretch (Pos 0)
state = PieceState::InHomeStretch;
pos = 0;
}
// state == InHomeStretch
if (toState == PieceState::InHomeStretch) {
return steps + (toPos - pos);
}
// toState == Finished
return steps + (ludo::kHomeStretchLength - 1 - pos) + 1;
}
TEST(LudoGameMode, PathLengthMatchesIndependentFormula) {
using namespace ludo;
const std::vector<PlayerColor> colors = {
PlayerColor::Red, PlayerColor::Blue, PlayerColor::Green, PlayerColor::Yellow};
for (auto color : colors) {
for (int start = 0; start < kTrackLength; ++start) {
auto path = LudoGameMode::computePath(
color, PieceState::OnTrack, start,
PieceState::InHomeStretch, 0);
EXPECT_EQ(path.size() - 1,
expectedStepCount(color, PieceState::OnTrack, start,
PieceState::InHomeStretch, 0))
<< "color=" << static_cast<int>(color) << " start=" << start;
EXPECT_EQ(path.front(), (PathNode{PieceState::OnTrack, start}));
EXPECT_EQ(path.back(), (PathNode{PieceState::InHomeStretch, 0}));
assertPathIsWellFormed(path);
}
}
}