raycaster/tests/mazes.cpp
2026-03-13 01:55:26 -04:00

175 lines
3.6 KiB
C++

#include <catch2/catch_test_macros.hpp>
#include <fmt/core.h>
#include <string>
#include "algos/matrix.hpp"
#include "algos/rand.hpp"
#include "constants.hpp"
#include "algos/maze.hpp"
#include "algos/stats.hpp"
#define DUMP 0
using std::string;
using matrix::Matrix;
TEST_CASE("hunt-and-kill", "[mazes]") {
Map map(21, 21);
maze::Builder maze(map);
maze.hunt_and_kill();
REQUIRE(maze.repair() == true);
if(DUMP) maze.dump("BASIC MAZE");
maze.randomize_rooms(ROOM_SIZE);
maze.hunt_and_kill();
maze.make_doors();
REQUIRE(maze.repair() == true);
if(DUMP) maze.dump("ROOM MAZE");
REQUIRE(map.$dead_ends.size() > 0);
REQUIRE(map.$rooms.size() > 0);
}
TEST_CASE("hunt-and-kill box", "[mazes]") {
for(int i = 25; i < 65; i += 2) {
Map map(i, i);
maze::Builder maze(map);
maze.hunt_and_kill();
maze.clear();
maze.inner_box(6, 4);
maze.randomize_rooms(ROOM_SIZE);
maze.hunt_and_kill();
maze.open_box(6);
maze.make_doors();
auto valid = maze.repair();
if(i == 41 && DUMP) {
maze.dump(valid ? "INNER BOX" : "FAILED BOX");
}
}
}
TEST_CASE("hunt-and-kill ring", "[mazes]") {
Map map(21, 21);
maze::Builder maze(map);
maze.inner_donut(5.5, 3.5);
maze.hunt_and_kill();
REQUIRE(maze.repair() == true);
if(DUMP) maze.dump("INNER RING");
REQUIRE(maze.$rooms.size() == 0);
}
TEST_CASE("hunt-and-kill fissure", "[mazes]") {
Map map(21, 21);
maze::Builder maze(map);
maze.divide({3,3}, {19,18});
maze.hunt_and_kill();
REQUIRE(maze.repair() == true);
if(DUMP) maze.dump("FISSURE MAZE");
REQUIRE(maze.$rooms.size() == 0);
}
TEST_CASE("hunt-and-kill no-dead-ends", "[mazes]") {
Map map(21, 21);
maze::Builder maze(map);
maze.hunt_and_kill();
maze.remove_dead_ends();
REQUIRE(maze.repair() == true);
if(DUMP) maze.dump("NO DEAD ENDS");
}
TEST_CASE("hunt-and-kill too much", "[mazes]") {
for(int i = 25; i < 65; i += 2) {
Map map(i, i);
maze::Builder maze(map);
maze.hunt_and_kill();
maze.randomize_rooms(ROOM_SIZE);
maze.clear();
maze.inner_donut(9, 4);
maze.divide({3,3}, {15,16});
maze.hunt_and_kill();
maze.make_doors();
auto valid = maze.repair();
if(i == 41 && DUMP && valid) {
maze.dump("COMBINED");
}
}
}
TEST_CASE("hunt-and-kill validator", "[mazes]") {
bool valid = true;
Stats mofm;
for(int i = 0; i < 10; i++) {
Stats door_prob;
do {
Map map(33, 33);
maze::Builder maze(map);
maze.hunt_and_kill();
maze.clear();
maze.inner_box(6, 4);
maze.randomize_rooms(ROOM_SIZE);
maze.hunt_and_kill();
maze.open_box(6);
maze.make_doors();
valid = maze.repair();
if(i == 9 && DUMP) {
maze.dump(valid ? "VALIDATED" : "FAILED!");
}
door_prob.sample(valid);
} while(!valid);
if(DUMP) door_prob.dump();
mofm.sample(door_prob.mean());
}
if(DUMP) {
fmt::println("FINAL m-of-m");
mofm.dump();
}
REQUIRE(mofm.mean() > 0.20);
}
TEST_CASE("hunt-and-kill scripting", "[mazes]") {
using namespace nlohmann::literals;
auto script = R"(
[
{"action": "hunt_and_kill"},
{"action": "clear"},
{"action": "inner_box", "data": [6, 4]},
{"action": "randomize_rooms", "data": [4]},
{"action": "divide", "data": [3, 3, 10, 10]},
{"action": "inner_donut", "data": [5.5,4.5]},
{"action": "hunt_and_kill"},
{"action": "open_box", "data": [6]},
{"action": "remove_dead_ends"},
{"action": "make_doors"}
]
)"_json;
Map map(33, 33);
auto [maze, valid] = maze::script(map, script);
maze.dump("SCRIPTED");
REQUIRE(valid == true);
}