Add artifact win condition #3
253
src/test/ArtifactWinConditionTest.cpp
Normal file
253
src/test/ArtifactWinConditionTest.cpp
Normal file
@@ -0,0 +1,253 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
#include "ConfigLoader.h"
|
||||
#include "FactionComponent.h"
|
||||
#include "Formula.h"
|
||||
#include "GameConfig.h"
|
||||
#include "HealthComponent.h"
|
||||
#include "SchematicChoiceOption.h"
|
||||
#include "Simulation.h"
|
||||
#include "StationBodyComponent.h"
|
||||
|
||||
static GameConfig loadConfig()
|
||||
{
|
||||
return ConfigLoader::loadFromDirectory(CONFIG_DIR);
|
||||
}
|
||||
|
||||
static void killEnemyStations(Simulation& sim)
|
||||
{
|
||||
sim.admin().forEach<StationBodyComponent, FactionComponent, HealthComponent>(
|
||||
[](entt::entity, StationBodyComponent&, FactionComponent& faction, HealthComponent& health)
|
||||
{
|
||||
if (faction.isEnemy)
|
||||
{
|
||||
health.hp = 0.0f;
|
||||
}
|
||||
});
|
||||
sim.tick();
|
||||
}
|
||||
|
||||
// Returns the index of the Artifact option in the pending choices, or -1 if absent.
|
||||
static int findArtifactChoiceIndex(const Simulation& sim)
|
||||
{
|
||||
const auto& choices = sim.getPendingSchematicChoices();
|
||||
for (int i = 0; i < static_cast<int>(choices.size()); ++i)
|
||||
{
|
||||
if (choices[static_cast<std::size_t>(i)].type == SchematicType::Artifact)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Config: new artifact fields are parsed correctly (REQ-WIN-ARTIFACT-COUNT)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("ArtifactWinCondition: artifact_chance_formula and artifact_win_count are loaded",
|
||||
"[artifact_win]")
|
||||
{
|
||||
const GameConfig cfg = loadConfig();
|
||||
CHECK(cfg.world.artifacts.artifactWinCount == 3);
|
||||
// 0.05 * x at x=2 should be 0.1
|
||||
CHECK(cfg.world.artifacts.artifactChanceFormula.evaluate(2.0) == Approx(0.1));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Simulation initial state
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("ArtifactWinCondition: artifact count is 0 and isWon is false at game start",
|
||||
"[artifact_win]")
|
||||
{
|
||||
const Simulation sim(loadConfig());
|
||||
CHECK(sim.artifactCount() == 0);
|
||||
CHECK_FALSE(sim.isWon());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Artifact option presence in schematic choices
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("ArtifactWinCondition: artifact option appears when chance formula returns 1",
|
||||
"[artifact_win]")
|
||||
{
|
||||
GameConfig cfg = loadConfig();
|
||||
cfg.world.artifacts.artifactChanceFormula = Formula::compile("1");
|
||||
Simulation sim(std::move(cfg));
|
||||
|
||||
killEnemyStations(sim);
|
||||
|
||||
REQUIRE(sim.hasSchematicChoicesPending());
|
||||
const auto& choices = sim.getPendingSchematicChoices();
|
||||
|
||||
const long artifactCount = std::count_if(choices.begin(), choices.end(),
|
||||
[](const SchematicChoiceOption& opt) { return opt.type == SchematicType::Artifact; });
|
||||
CHECK(artifactCount == 1);
|
||||
// Exactly 2 schematic picks + 1 artifact (or fewer if pool was small)
|
||||
CHECK(choices.size() <= 3);
|
||||
}
|
||||
|
||||
TEST_CASE("ArtifactWinCondition: at most 2 schematic options accompany the artifact",
|
||||
"[artifact_win]")
|
||||
{
|
||||
GameConfig cfg = loadConfig();
|
||||
cfg.world.artifacts.artifactChanceFormula = Formula::compile("1");
|
||||
Simulation sim(std::move(cfg));
|
||||
|
||||
killEnemyStations(sim);
|
||||
|
||||
REQUIRE(sim.hasSchematicChoicesPending());
|
||||
const auto& choices = sim.getPendingSchematicChoices();
|
||||
|
||||
const long schematicCount = std::count_if(choices.begin(), choices.end(),
|
||||
[](const SchematicChoiceOption& opt) { return opt.type != SchematicType::Artifact; });
|
||||
CHECK(schematicCount <= 2);
|
||||
}
|
||||
|
||||
TEST_CASE("ArtifactWinCondition: no artifact option when chance formula returns 0",
|
||||
"[artifact_win]")
|
||||
{
|
||||
GameConfig cfg = loadConfig();
|
||||
cfg.world.artifacts.artifactChanceFormula = Formula::compile("0");
|
||||
Simulation sim(std::move(cfg));
|
||||
|
||||
for (int i = 0; i < 20; ++i)
|
||||
{
|
||||
killEnemyStations(sim);
|
||||
if (!sim.hasSchematicChoicesPending()) { continue; }
|
||||
|
||||
CHECK(findArtifactChoiceIndex(sim) == -1);
|
||||
sim.applySchematicChoice(0);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Selecting the artifact option
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("ArtifactWinCondition: selecting artifact increments artifact count",
|
||||
"[artifact_win]")
|
||||
{
|
||||
GameConfig cfg = loadConfig();
|
||||
cfg.world.artifacts.artifactChanceFormula = Formula::compile("1");
|
||||
Simulation sim(std::move(cfg));
|
||||
|
||||
killEnemyStations(sim);
|
||||
REQUIRE(sim.hasSchematicChoicesPending());
|
||||
|
||||
const int index = findArtifactChoiceIndex(sim);
|
||||
REQUIRE(index >= 0);
|
||||
|
||||
sim.applySchematicChoice(index);
|
||||
|
||||
CHECK(sim.artifactCount() == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("ArtifactWinCondition: selecting a non-artifact option does not increment artifact count",
|
||||
"[artifact_win]")
|
||||
{
|
||||
GameConfig cfg = loadConfig();
|
||||
cfg.world.artifacts.artifactChanceFormula = Formula::compile("1");
|
||||
Simulation sim(std::move(cfg));
|
||||
|
||||
killEnemyStations(sim);
|
||||
REQUIRE(sim.hasSchematicChoicesPending());
|
||||
|
||||
// Pick the first non-artifact choice.
|
||||
const auto& choices = sim.getPendingSchematicChoices();
|
||||
const auto it = std::find_if(choices.begin(), choices.end(),
|
||||
[](const SchematicChoiceOption& opt) { return opt.type != SchematicType::Artifact; });
|
||||
REQUIRE(it != choices.end());
|
||||
|
||||
sim.applySchematicChoice(static_cast<int>(it - choices.begin()));
|
||||
|
||||
CHECK(sim.artifactCount() == 0);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Win condition (REQ-WIN-ARTIFACT-COUNT)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("ArtifactWinCondition: isWon becomes true when artifact count reaches win count",
|
||||
"[artifact_win]")
|
||||
{
|
||||
GameConfig cfg = loadConfig();
|
||||
cfg.world.artifacts.artifactChanceFormula = Formula::compile("1");
|
||||
cfg.world.artifacts.artifactWinCount = 1;
|
||||
Simulation sim(std::move(cfg));
|
||||
|
||||
CHECK_FALSE(sim.isWon());
|
||||
|
||||
killEnemyStations(sim);
|
||||
REQUIRE(sim.hasSchematicChoicesPending());
|
||||
|
||||
const int index = findArtifactChoiceIndex(sim);
|
||||
REQUIRE(index >= 0);
|
||||
sim.applySchematicChoice(index);
|
||||
|
||||
CHECK(sim.isWon());
|
||||
}
|
||||
|
||||
TEST_CASE("ArtifactWinCondition: isWon stays false when artifact count is below win count",
|
||||
"[artifact_win]")
|
||||
{
|
||||
GameConfig cfg = loadConfig();
|
||||
cfg.world.artifacts.artifactChanceFormula = Formula::compile("1");
|
||||
cfg.world.artifacts.artifactWinCount = 2;
|
||||
Simulation sim(std::move(cfg));
|
||||
|
||||
killEnemyStations(sim);
|
||||
REQUIRE(sim.hasSchematicChoicesPending());
|
||||
sim.applySchematicChoice(findArtifactChoiceIndex(sim));
|
||||
|
||||
CHECK(sim.artifactCount() == 1);
|
||||
CHECK_FALSE(sim.isWon());
|
||||
}
|
||||
|
||||
TEST_CASE("ArtifactWinCondition: isWon becomes true after collecting required number of artifacts",
|
||||
"[artifact_win]")
|
||||
{
|
||||
GameConfig cfg = loadConfig();
|
||||
cfg.world.artifacts.artifactChanceFormula = Formula::compile("1");
|
||||
cfg.world.artifacts.artifactWinCount = 2;
|
||||
Simulation sim(std::move(cfg));
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
killEnemyStations(sim);
|
||||
REQUIRE(sim.hasSchematicChoicesPending());
|
||||
const int index = findArtifactChoiceIndex(sim);
|
||||
REQUIRE(index >= 0);
|
||||
sim.applySchematicChoice(index);
|
||||
}
|
||||
|
||||
CHECK(sim.artifactCount() == 2);
|
||||
CHECK(sim.isWon());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// reset() restores initial state (REQ-CFG-RELOAD)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("ArtifactWinCondition: reset clears artifact count and win state",
|
||||
"[artifact_win]")
|
||||
{
|
||||
GameConfig cfg = loadConfig();
|
||||
cfg.world.artifacts.artifactChanceFormula = Formula::compile("1");
|
||||
cfg.world.artifacts.artifactWinCount = 1;
|
||||
Simulation sim(std::move(cfg));
|
||||
|
||||
killEnemyStations(sim);
|
||||
REQUIRE(sim.hasSchematicChoicesPending());
|
||||
sim.applySchematicChoice(findArtifactChoiceIndex(sim));
|
||||
REQUIRE(sim.isWon());
|
||||
|
||||
sim.reset();
|
||||
|
||||
CHECK(sim.artifactCount() == 0);
|
||||
CHECK_FALSE(sim.isWon());
|
||||
}
|
||||
@@ -21,4 +21,5 @@ add_files(
|
||||
ShipModuleTest.cpp
|
||||
ThreatCostCalculatorTest.cpp
|
||||
RecipeSchematicTest.cpp
|
||||
ArtifactWinConditionTest.cpp
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user