More tests converted to fuc2.
This commit is contained in:
parent
b8b42d5681
commit
903cf00661
10 changed files with 671 additions and 556 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <fuc2/testing.hpp>
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "gui/event_router.hpp"
|
#include "gui/event_router.hpp"
|
||||||
|
|
@ -7,51 +7,61 @@ using namespace fmt;
|
||||||
using namespace gui;
|
using namespace gui;
|
||||||
using enum gui::routing::Event;
|
using enum gui::routing::Event;
|
||||||
using enum gui::routing::State;
|
using enum gui::routing::State;
|
||||||
|
using namespace fuc2;
|
||||||
|
|
||||||
using EventScript = std::vector<routing::Event>;
|
namespace event_router_tests {
|
||||||
|
using EventScript = std::vector<routing::Event>;
|
||||||
|
|
||||||
void run_script(routing::Router& router, routing::State expected, EventScript script) {
|
void run_script(routing::Router& router, routing::State expected, EventScript script) {
|
||||||
for(auto ev : script) {
|
for(auto ev : script) {
|
||||||
router.event(ev);
|
router.event(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK(router.in_state(expected));
|
||||||
}
|
}
|
||||||
|
|
||||||
REQUIRE(router.in_state(expected));
|
void test_basic_router_operations_test() {
|
||||||
}
|
routing::Router router;
|
||||||
|
|
||||||
TEST_CASE("basic router operations test", "[event_router]") {
|
// start goes to idle
|
||||||
routing::Router router;
|
run_script(router, IDLE, {
|
||||||
|
STARTED
|
||||||
// start goes to idle
|
});
|
||||||
run_script(router, IDLE, {
|
|
||||||
STARTED
|
// simulate drag and drop
|
||||||
});
|
run_script(router, IDLE, {
|
||||||
|
MOUSE_DOWN,
|
||||||
// simulate drag and drop
|
MOUSE_MOVE,
|
||||||
run_script(router, IDLE, {
|
MOUSE_UP,
|
||||||
MOUSE_DOWN,
|
KEY_PRESS
|
||||||
MOUSE_MOVE,
|
});
|
||||||
MOUSE_UP,
|
|
||||||
KEY_PRESS
|
// moving the mouse outside dnd
|
||||||
});
|
run_script(router, IDLE, {
|
||||||
|
MOUSE_MOVE,
|
||||||
// moving the mouse outside dnd
|
KEY_PRESS,
|
||||||
run_script(router, IDLE, {
|
MOUSE_MOVE
|
||||||
MOUSE_MOVE,
|
});
|
||||||
KEY_PRESS,
|
|
||||||
MOUSE_MOVE
|
// regular mouse click
|
||||||
});
|
run_script(router, IDLE, {
|
||||||
|
MOUSE_DOWN,
|
||||||
// regular mouse click
|
MOUSE_UP
|
||||||
run_script(router, IDLE, {
|
});
|
||||||
MOUSE_DOWN,
|
|
||||||
MOUSE_UP
|
// possible bad key press in a move?
|
||||||
});
|
run_script(router, IDLE, {
|
||||||
|
MOUSE_DOWN,
|
||||||
// possible bad key press in a move?
|
MOUSE_MOVE,
|
||||||
run_script(router, IDLE, {
|
KEY_PRESS,
|
||||||
MOUSE_DOWN,
|
MOUSE_UP,
|
||||||
MOUSE_MOVE,
|
});
|
||||||
KEY_PRESS,
|
}
|
||||||
MOUSE_UP,
|
|
||||||
});
|
fuc2::Set TESTS{
|
||||||
|
.name="event_router",
|
||||||
|
.tests={
|
||||||
|
TEST(test_basic_router_operations_test),
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
119
tests/fsm.cpp
119
tests/fsm.cpp
|
|
@ -1,67 +1,78 @@
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <fuc2/testing.hpp>
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "algos/simplefsm.hpp"
|
#include "algos/simplefsm.hpp"
|
||||||
|
|
||||||
using namespace fmt;
|
using namespace fmt;
|
||||||
using std::string;
|
using std::string;
|
||||||
|
using namespace fuc2;
|
||||||
|
|
||||||
enum class MyState {
|
namespace fsm_tests {
|
||||||
START, RUNNING, END
|
enum class MyState {
|
||||||
};
|
START, RUNNING, END
|
||||||
|
};
|
||||||
|
|
||||||
enum class MyEvent {
|
enum class MyEvent {
|
||||||
STARTED, PUSH, QUIT
|
STARTED, PUSH, QUIT
|
||||||
};
|
};
|
||||||
|
|
||||||
class MyFSM : public DeadSimpleFSM<MyState, MyEvent> {
|
class MyFSM : public DeadSimpleFSM<MyState, MyEvent> {
|
||||||
public:
|
public:
|
||||||
void event(MyEvent ev, string data="") {
|
void event(MyEvent ev, string data="") {
|
||||||
switch($state) {
|
switch($state) {
|
||||||
FSM_STATE(MyState, START, ev);
|
FSM_STATE(MyState, START, ev);
|
||||||
FSM_STATE(MyState, RUNNING, ev, data);
|
FSM_STATE(MyState, RUNNING, ev, data);
|
||||||
FSM_STATE(MyState, END, ev);
|
FSM_STATE(MyState, END, ev);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void START(MyEvent ev) {
|
||||||
|
println("<<< START {}", (int)ev);
|
||||||
|
state(MyState::RUNNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RUNNING(MyEvent ev, string &data) {
|
||||||
|
if(ev == MyEvent::QUIT) {
|
||||||
|
println("<<< QUITTING {}", data);
|
||||||
|
state(MyState::END);
|
||||||
|
} else {
|
||||||
|
println("<<< RUN: {}", data);
|
||||||
|
state(MyState::RUNNING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void END(MyEvent ev) {
|
||||||
|
println("<<< STOP {}", (int)ev);
|
||||||
|
state(MyState::END);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void test_confirm_fsm_works_with_optional_data() {
|
||||||
|
MyFSM fsm;
|
||||||
|
|
||||||
|
CHECK(fsm.in_state(MyState::START));
|
||||||
|
|
||||||
|
fsm.event(MyEvent::STARTED);
|
||||||
|
CHECK(fsm.in_state(MyState::RUNNING));
|
||||||
|
|
||||||
|
fsm.event(MyEvent::PUSH);
|
||||||
|
CHECK(fsm.in_state(MyState::RUNNING));
|
||||||
|
|
||||||
|
fsm.event(MyEvent::PUSH);
|
||||||
|
CHECK(fsm.in_state(MyState::RUNNING));
|
||||||
|
|
||||||
|
fsm.event(MyEvent::PUSH);
|
||||||
|
CHECK(fsm.in_state(MyState::RUNNING));
|
||||||
|
|
||||||
|
fsm.event(MyEvent::QUIT, "DONE!");
|
||||||
|
CHECK(fsm.in_state(MyState::END));
|
||||||
}
|
}
|
||||||
|
|
||||||
void START(MyEvent ev) {
|
|
||||||
println("<<< START {}", (int)ev);
|
|
||||||
state(MyState::RUNNING);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RUNNING(MyEvent ev, string &data) {
|
fuc2::Set TESTS{
|
||||||
if(ev == MyEvent::QUIT) {
|
.name="fsm",
|
||||||
println("<<< QUITTING {}", data);
|
.tests={
|
||||||
state(MyState::END);
|
TEST(test_confirm_fsm_works_with_optional_data),
|
||||||
} else {
|
}
|
||||||
println("<<< RUN: {}", data);
|
};
|
||||||
state(MyState::RUNNING);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void END(MyEvent ev) {
|
|
||||||
println("<<< STOP {}", (int)ev);
|
|
||||||
state(MyState::END);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_CASE("confirm fsm works with optional data", "[utils]") {
|
|
||||||
MyFSM fsm;
|
|
||||||
|
|
||||||
REQUIRE(fsm.in_state(MyState::START));
|
|
||||||
|
|
||||||
fsm.event(MyEvent::STARTED);
|
|
||||||
REQUIRE(fsm.in_state(MyState::RUNNING));
|
|
||||||
|
|
||||||
fsm.event(MyEvent::PUSH);
|
|
||||||
REQUIRE(fsm.in_state(MyState::RUNNING));
|
|
||||||
|
|
||||||
fsm.event(MyEvent::PUSH);
|
|
||||||
REQUIRE(fsm.in_state(MyState::RUNNING));
|
|
||||||
|
|
||||||
fsm.event(MyEvent::PUSH);
|
|
||||||
REQUIRE(fsm.in_state(MyState::RUNNING));
|
|
||||||
|
|
||||||
fsm.event(MyEvent::QUIT, "DONE!");
|
|
||||||
REQUIRE(fsm.in_state(MyState::END));
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,52 +1,63 @@
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <fuc2/testing.hpp>
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "game/inventory.hpp"
|
#include "game/inventory.hpp"
|
||||||
|
|
||||||
using namespace fmt;
|
using namespace fmt;
|
||||||
|
using namespace fuc2;
|
||||||
|
|
||||||
TEST_CASE("base test", "[inventory]") {
|
namespace inventory_tests {
|
||||||
return;
|
void test_base_test() {
|
||||||
inventory::Model inv;
|
return;
|
||||||
DinkyECS::Entity test_ent = 1;
|
inventory::Model inv;
|
||||||
|
DinkyECS::Entity test_ent = 1;
|
||||||
|
|
||||||
bool good = inv.add("hand_l", test_ent);
|
bool good = inv.add("hand_l", test_ent);
|
||||||
inv.invariant();
|
inv.invariant();
|
||||||
REQUIRE(good);
|
CHECK(good);
|
||||||
|
|
||||||
auto& slot = inv.get(test_ent);
|
auto& slot = inv.get(test_ent);
|
||||||
REQUIRE(slot == "hand_l");
|
CHECK(slot == "hand_l");
|
||||||
|
|
||||||
// confirm that we get false when trying to do it again
|
// confirm that we get false when trying to do it again
|
||||||
// BUG: this dies
|
// BUG: this dies
|
||||||
good = inv.add("hand_l", test_ent);
|
good = inv.add("hand_l", test_ent);
|
||||||
REQUIRE(!good);
|
CHECK(!good);
|
||||||
|
|
||||||
auto ent = inv.get(slot);
|
auto ent = inv.get(slot);
|
||||||
REQUIRE(ent == test_ent);
|
CHECK(ent == test_ent);
|
||||||
|
|
||||||
REQUIRE(inv.has(ent));
|
CHECK(inv.has(ent));
|
||||||
REQUIRE(inv.has(slot));
|
CHECK(inv.has(slot));
|
||||||
|
|
||||||
// test base remove
|
// test base remove
|
||||||
inv.remove(ent);
|
inv.remove(ent);
|
||||||
REQUIRE(!inv.has(slot));
|
CHECK(!inv.has(slot));
|
||||||
REQUIRE(!inv.has(ent));
|
CHECK(!inv.has(ent));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("test swapping items", "[inventory]") {
|
void test_test_swapping_items() {
|
||||||
inventory::Model inv;
|
inventory::Model inv;
|
||||||
DinkyECS::Entity hand_l_ent = 10;
|
DinkyECS::Entity hand_l_ent = 10;
|
||||||
DinkyECS::Entity hand_r_ent = 20;
|
DinkyECS::Entity hand_r_ent = 20;
|
||||||
|
|
||||||
inv.add("hand_l", hand_l_ent);
|
inv.add("hand_l", hand_l_ent);
|
||||||
inv.add("hand_r", hand_r_ent);
|
inv.add("hand_r", hand_r_ent);
|
||||||
REQUIRE(inv.count() == 2);
|
CHECK(inv.count() == 2);
|
||||||
|
|
||||||
inv.swap(hand_l_ent, hand_r_ent);
|
inv.swap(hand_l_ent, hand_r_ent);
|
||||||
|
|
||||||
REQUIRE(inv.get("hand_l") == hand_r_ent);
|
CHECK(inv.get("hand_l") == hand_r_ent);
|
||||||
REQUIRE(inv.get("hand_r") == hand_l_ent);
|
CHECK(inv.get("hand_r") == hand_l_ent);
|
||||||
|
|
||||||
REQUIRE(inv.count() == 2);
|
CHECK(inv.count() == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
fuc2::Set TESTS{
|
||||||
|
.name="inventory",
|
||||||
|
.tests={
|
||||||
|
TEST(test_base_test),
|
||||||
|
TEST(test_test_swapping_items),
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <fuc2/testing.hpp>
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
@ -8,35 +8,47 @@
|
||||||
#include "algos/point.hpp"
|
#include "algos/point.hpp"
|
||||||
|
|
||||||
using namespace lighting;
|
using namespace lighting;
|
||||||
|
using namespace fuc2;
|
||||||
|
|
||||||
TEST_CASE("lighting a map works", "[lighting]") {
|
namespace lighting_tests {
|
||||||
GameDB::init();
|
|
||||||
auto& level = GameDB::current_level();
|
|
||||||
auto& map = *level.map;
|
|
||||||
|
|
||||||
Point light1, light2;
|
void test_lighting_a_map_works() {
|
||||||
|
GameDB::init();
|
||||||
|
auto& level = GameDB::current_level();
|
||||||
|
auto& map = *level.map;
|
||||||
|
|
||||||
REQUIRE(map.place_entity(0, light1));
|
Point light1, light2;
|
||||||
REQUIRE(map.place_entity(0, light1));
|
|
||||||
|
|
||||||
LightSource source1{6, 1.0};
|
CHECK(map.place_entity(0, light1));
|
||||||
LightSource source2{4,3};
|
CHECK(map.place_entity(0, light1));
|
||||||
|
|
||||||
LightRender lr(map.walls());
|
LightSource source1{6, 1.0};
|
||||||
|
LightSource source2{4,3};
|
||||||
|
|
||||||
lr.reset_light();
|
LightRender lr(map.walls());
|
||||||
|
|
||||||
lr.set_light_target(light1);
|
lr.reset_light();
|
||||||
lr.set_light_target(light2);
|
|
||||||
|
|
||||||
lr.path_light(map.walls());
|
lr.set_light_target(light1);
|
||||||
|
lr.set_light_target(light2);
|
||||||
|
|
||||||
lr.render_light(source1, light1);
|
lr.path_light(map.walls());
|
||||||
lr.render_light(source2, light2);
|
|
||||||
|
|
||||||
lr.clear_light_target(light1);
|
lr.render_light(source1, light1);
|
||||||
lr.clear_light_target(light2);
|
lr.render_light(source2, light2);
|
||||||
|
|
||||||
Matrix &lighting = lr.lighting();
|
lr.clear_light_target(light1);
|
||||||
(void)lighting;
|
lr.clear_light_target(light2);
|
||||||
|
|
||||||
|
Matrix &lighting = lr.lighting();
|
||||||
|
(void)lighting;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fuc2::Set TESTS{
|
||||||
|
.name="lighting",
|
||||||
|
.tests={
|
||||||
|
TEST(test_lighting_a_map_works),
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <fuc2/testing.hpp>
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "game/components.hpp"
|
#include "game/components.hpp"
|
||||||
|
|
@ -6,16 +6,26 @@
|
||||||
|
|
||||||
using namespace fmt;
|
using namespace fmt;
|
||||||
using namespace components;
|
using namespace components;
|
||||||
|
using namespace fuc2;
|
||||||
|
|
||||||
TEST_CASE("test the loot ui", "[loot]") {
|
namespace loot_tests {
|
||||||
auto items = settings::get("assets/items.json");
|
void test_test_the_loot_ui() {
|
||||||
DinkyECS::World world;
|
auto items = settings::get("assets/items.json");
|
||||||
auto torch = world.entity();
|
DinkyECS::World world;
|
||||||
auto& data = items["TORCH_BAD"];
|
auto torch = world.entity();
|
||||||
|
auto& data = items["TORCH_BAD"];
|
||||||
|
|
||||||
components::init();
|
components::init();
|
||||||
components::configure_entity(world, torch, data["components"]);
|
components::configure_entity(world, torch, data["components"]);
|
||||||
|
|
||||||
auto& torch_sprite = world.get<Sprite>(torch);
|
auto& torch_sprite = world.get<Sprite>(torch);
|
||||||
REQUIRE(torch_sprite.name == "torch_horizontal_floor");
|
CHECK(torch_sprite.name == "torch_horizontal_floor");
|
||||||
|
}
|
||||||
|
|
||||||
|
fuc2::Set TESTS{
|
||||||
|
.name="loot",
|
||||||
|
.tests={
|
||||||
|
TEST(test_test_the_loot_ui),
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,13 @@ TEST_SET(component_tests);
|
||||||
TEST_SET(config_tests);
|
TEST_SET(config_tests);
|
||||||
TEST_SET(dbc_tests);
|
TEST_SET(dbc_tests);
|
||||||
TEST_SET(dinkyecs_tests);
|
TEST_SET(dinkyecs_tests);
|
||||||
|
TEST_SET(event_router_tests);
|
||||||
|
TEST_SET(inventory_tests);
|
||||||
|
TEST_SET(lighting_tests);
|
||||||
|
TEST_SET(loot_tests);
|
||||||
|
TEST_SET(map_tests);
|
||||||
|
TEST_SET(matrix_tests);
|
||||||
|
TEST_SET(mazes_tests);
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
run(ai_tests::TESTS);
|
run(ai_tests::TESTS);
|
||||||
|
|
@ -22,4 +29,11 @@ int main(int argc, char* argv[]) {
|
||||||
run(config_tests::TESTS);
|
run(config_tests::TESTS);
|
||||||
run(dbc_tests::TESTS);
|
run(dbc_tests::TESTS);
|
||||||
run(dinkyecs_tests::TESTS);
|
run(dinkyecs_tests::TESTS);
|
||||||
|
run(event_router_tests::TESTS);
|
||||||
|
run(inventory_tests::TESTS);
|
||||||
|
run(lighting_tests::TESTS);
|
||||||
|
run(loot_tests::TESTS);
|
||||||
|
run(map_tests::TESTS);
|
||||||
|
run(matrix_tests::TESTS);
|
||||||
|
run(mazes_tests::TESTS);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
108
tests/map.cpp
108
tests/map.cpp
|
|
@ -1,4 +1,4 @@
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <fuc2/testing.hpp>
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
@ -12,74 +12,86 @@
|
||||||
using namespace fmt;
|
using namespace fmt;
|
||||||
using namespace nlohmann;
|
using namespace nlohmann;
|
||||||
using std::string;
|
using std::string;
|
||||||
|
using namespace fuc2;
|
||||||
|
|
||||||
json load_test_data(const string &fname) {
|
namespace map_tests {
|
||||||
std::ifstream infile(fname);
|
json load_test_data(const string &fname) {
|
||||||
return json::parse(infile);
|
std::ifstream infile(fname);
|
||||||
}
|
return json::parse(infile);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("camera control", "[map]") {
|
void test_camera_control() {
|
||||||
GameDB::init();
|
GameDB::init();
|
||||||
|
|
||||||
auto& level = GameDB::current_level();
|
auto& level = GameDB::current_level();
|
||||||
auto& map = *level.map;
|
auto& map = *level.map;
|
||||||
|
|
||||||
Point center = map.center_camera({10,10}, 5, 5);
|
Point center = map.center_camera({10,10}, 5, 5);
|
||||||
|
|
||||||
// map.dump(center.x, center.y);
|
// map.dump(center.x, center.y);
|
||||||
REQUIRE(center.x == 8);
|
CHECK(center.x == 8);
|
||||||
REQUIRE(center.y == 8);
|
CHECK(center.y == 8);
|
||||||
|
|
||||||
Point translation = map.map_to_camera({10,10}, center);
|
Point translation = map.map_to_camera({10,10}, center);
|
||||||
|
|
||||||
REQUIRE(translation.x == 2);
|
CHECK(translation.x == 2);
|
||||||
REQUIRE(translation.y == 2);
|
CHECK(translation.y == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("map placement test", "[map-fail]") {
|
void test_map_placement_test() {
|
||||||
GameDB::init();
|
GameDB::init();
|
||||||
|
|
||||||
for(int i = 0; i < 10; i++) {
|
for(int i = 0; i < 10; i++) {
|
||||||
auto& level = GameDB::create_level();
|
auto& level = GameDB::create_level();
|
||||||
|
|
||||||
for(size_t rnum = 0; rnum < level.map->room_count(); rnum++) {
|
for(size_t rnum = 0; rnum < level.map->room_count(); rnum++) {
|
||||||
Point pos;
|
Point pos;
|
||||||
|
|
||||||
REQUIRE(level.map->place_entity(rnum, pos));
|
CHECK(level.map->place_entity(rnum, pos));
|
||||||
|
|
||||||
REQUIRE(!level.map->iswall(pos.x, pos.y));
|
CHECK(!level.map->iswall(pos.x, pos.y));
|
||||||
REQUIRE(level.map->inmap(pos.x, pos.y));
|
CHECK(level.map->inmap(pos.x, pos.y));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("map image test", "[map]") {
|
void test_map_image_test() {
|
||||||
GameDB::init();
|
GameDB::init();
|
||||||
|
|
||||||
auto& level = GameDB::current_level();
|
auto& level = GameDB::current_level();
|
||||||
Matrix map_tiles = matrix::make(7,7);
|
Matrix map_tiles = matrix::make(7,7);
|
||||||
EntityGrid entity_map;
|
EntityGrid entity_map;
|
||||||
|
|
||||||
auto render = std::make_shared<sf::RenderTexture>();
|
auto render = std::make_shared<sf::RenderTexture>();
|
||||||
sf::Sprite sprite{render->getTexture()};
|
sf::Sprite sprite{render->getTexture()};
|
||||||
auto player = level.world->get_the<components::Player>();
|
auto player = level.world->get_the<components::Player>();
|
||||||
auto& player_pos = level.world->get<components::Position>(player.entity);
|
auto& player_pos = level.world->get<components::Position>(player.entity);
|
||||||
auto player_display = level.world->get<components::Tile>(player.entity).display;
|
auto player_display = level.world->get<components::Tile>(player.entity).display;
|
||||||
|
|
||||||
for(matrix::each_row it{level.map->walls()}; it.next();) {
|
for(matrix::each_row it{level.map->walls()}; it.next();) {
|
||||||
player_pos.location.x = it.x;
|
player_pos.location.x = it.x;
|
||||||
player_pos.location.y = it.y;
|
player_pos.location.y = it.y;
|
||||||
System::draw_map(map_tiles, entity_map);
|
System::draw_map(map_tiles, entity_map);
|
||||||
System::render_map(map_tiles, entity_map, *render, 2, player_display);
|
System::render_map(map_tiles, entity_map, *render, 2, player_display);
|
||||||
|
|
||||||
// randomly test about 80% of them
|
// randomly test about 80% of them
|
||||||
if(Random::uniform(0, 100) < 20) break;
|
if(Random::uniform(0, 100) < 20) break;
|
||||||
|
|
||||||
#ifdef TEST_RENDER
|
#ifdef TEST_RENDER
|
||||||
// confirm we get two different maps
|
// confirm we get two different maps
|
||||||
auto out_img = render->getTexture().copyToImage();
|
auto out_img = render->getTexture().copyToImage();
|
||||||
bool worked = out_img.saveToFile(fmt::format("tmp/map_render{}{}.png", it.x, it.y));
|
bool worked = out_img.saveToFile(fmt::format("tmp/map_render{}{}.png", it.x, it.y));
|
||||||
REQUIRE(worked);
|
CHECK(worked);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fuc2::Set TESTS{
|
||||||
|
.name="map",
|
||||||
|
.tests={
|
||||||
|
TEST(test_camera_control),
|
||||||
|
TEST(test_map_placement_test),
|
||||||
|
TEST(test_map_image_test),
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
434
tests/matrix.cpp
434
tests/matrix.cpp
|
|
@ -1,4 +1,4 @@
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <fuc2/testing.hpp>
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "game/config.hpp"
|
#include "game/config.hpp"
|
||||||
|
|
@ -13,265 +13,283 @@
|
||||||
|
|
||||||
using namespace nlohmann;
|
using namespace nlohmann;
|
||||||
using namespace fmt;
|
using namespace fmt;
|
||||||
|
using namespace fuc2;
|
||||||
using std::string, std::shared_ptr;
|
using std::string, std::shared_ptr;
|
||||||
using matrix::Matrix;
|
using matrix::Matrix;
|
||||||
|
|
||||||
std::shared_ptr<Map> make_map() {
|
namespace matrix_tests {
|
||||||
GameDB::init();
|
std::shared_ptr<Map> make_map() {
|
||||||
return GameDB::current_level().map;
|
GameDB::init();
|
||||||
}
|
return GameDB::current_level().map;
|
||||||
|
|
||||||
// BUG: create a test that randomizes a map then does matrix ops on it
|
|
||||||
|
|
||||||
inline void random_matrix(Matrix &out) {
|
|
||||||
for(size_t y = 0; y < out.size(); y++) {
|
|
||||||
for(size_t x = 0; x < out[0].size(); x++) {
|
|
||||||
out[y][x] = Random::uniform<int>(-10,10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("thrash matrix iterators", "[matrix]") {
|
|
||||||
for(int count = 0; count < 5; count++) {
|
|
||||||
size_t width = Random::uniform<size_t>(1, 100);
|
|
||||||
size_t height = Random::uniform<size_t>(1, 100);
|
|
||||||
|
|
||||||
Matrix test(height, matrix::Row(width));
|
|
||||||
random_matrix(test);
|
|
||||||
|
|
||||||
// first make a randomized matrix
|
|
||||||
matrix::each_cell cells{test};
|
|
||||||
cells.next(); // kick off the other iterator
|
|
||||||
|
|
||||||
for(matrix::each_row it{test};
|
|
||||||
it.next(); cells.next())
|
|
||||||
{
|
|
||||||
REQUIRE(test[cells.y][cells.x] == test[it.y][it.x]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("thrash box distance iterators", "[matrix]") {
|
|
||||||
size_t width = Random::uniform<size_t>(10, 21);
|
|
||||||
size_t height = Random::uniform<size_t>(10, 25);
|
|
||||||
|
|
||||||
Matrix result(height, matrix::Row(width));
|
|
||||||
matrix::assign(result, 0);
|
|
||||||
|
|
||||||
size_t size = Random::uniform<int>(4, 10);
|
|
||||||
|
|
||||||
Point target{width/2, height/2};
|
|
||||||
matrix::box box{result, target.x, target.y, size};
|
|
||||||
while(box.next()) {
|
|
||||||
result[box.y][box.x] = box.distance();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// matrix::dump(format("MAP {}x{} @ {},{}; BOX {}x{}; size: {}",
|
// BUG: create a test that randomizes a map then does matrix ops on it
|
||||||
// matrix::width(result), matrix::height(result),
|
|
||||||
// target.x, target.y, box.right - box.left, box.bottom - box.top, size),
|
|
||||||
// result, target.x, target.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("thrash box iterators", "[matrix]") {
|
inline void random_matrix(Matrix &out) {
|
||||||
for(int count = 0; count < 5; count++) {
|
for(size_t y = 0; y < out.size(); y++) {
|
||||||
size_t width = Random::uniform<size_t>(1, 25);
|
for(size_t x = 0; x < out[0].size(); x++) {
|
||||||
size_t height = Random::uniform<size_t>(1, 33);
|
out[y][x] = Random::uniform<int>(-10,10);
|
||||||
|
|
||||||
Matrix test(height, matrix::Row(width));
|
|
||||||
random_matrix(test);
|
|
||||||
|
|
||||||
// this will be greater than the random_matrix cells
|
|
||||||
int test_i = Random::uniform<size_t>(20,30);
|
|
||||||
|
|
||||||
// go through every cell
|
|
||||||
for(matrix::each_cell target{test}; target.next();) {
|
|
||||||
PointList result;
|
|
||||||
// make a random size box
|
|
||||||
size_t size = Random::uniform<int>(1, 33);
|
|
||||||
matrix::box box{test, target.x, target.y, size};
|
|
||||||
|
|
||||||
while(box.next()) {
|
|
||||||
test[box.y][box.x] = test_i;
|
|
||||||
result.push_back({box.x, box.y});
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto point : result) {
|
|
||||||
REQUIRE(test[point.y][point.x] == test_i);
|
|
||||||
test[point.y][point.x] = 10; // kind of reset it for another try
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("thrash compass iterators", "[matrix]") {
|
void test_thrash_matrix_iterators() {
|
||||||
for(int count = 0; count < 5; count++) {
|
for(int count = 0; count < 5; count++) {
|
||||||
size_t width = Random::uniform<size_t>(1, 25);
|
size_t width = Random::uniform<size_t>(1, 100);
|
||||||
size_t height = Random::uniform<size_t>(1, 33);
|
size_t height = Random::uniform<size_t>(1, 100);
|
||||||
|
|
||||||
Matrix test(height, matrix::Row(width));
|
Matrix test(height, matrix::Row(width));
|
||||||
random_matrix(test);
|
random_matrix(test);
|
||||||
|
|
||||||
// this will be greater than the random_matrix cells
|
// first make a randomized matrix
|
||||||
int test_i = Random::uniform<size_t>(20,30);
|
matrix::each_cell cells{test};
|
||||||
|
cells.next(); // kick off the other iterator
|
||||||
|
|
||||||
// go through every cell
|
for(matrix::each_row it{test};
|
||||||
for(matrix::each_cell target{test}; target.next();) {
|
it.next(); cells.next())
|
||||||
PointList result;
|
{
|
||||||
// make a random size box
|
CHECK(test[cells.y][cells.x] == test[it.y][it.x]);
|
||||||
matrix::compass compass{test, target.x, target.y};
|
|
||||||
|
|
||||||
while(compass.next()) {
|
|
||||||
test[compass.y][compass.x] = test_i;
|
|
||||||
result.push_back({compass.x, compass.y});
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto point : result) {
|
|
||||||
REQUIRE(test[point.y][point.x] == test_i);
|
|
||||||
test[point.y][point.x] = 10; // kind of reset it for another try
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("prototype line algorithm", "[matrix]") {
|
void test_thrash_box_distance_iterators() {
|
||||||
size_t width = Random::uniform<size_t>(10, 12);
|
size_t width = Random::uniform<size_t>(10, 21);
|
||||||
size_t height = Random::uniform<size_t>(10, 15);
|
size_t height = Random::uniform<size_t>(10, 25);
|
||||||
Map map(width,height);
|
|
||||||
// create a target for the paths
|
|
||||||
Point start{.x=map.width() / 2, .y=map.height()/2};
|
|
||||||
|
|
||||||
for(matrix::box box{map.walls(), start.x, start.y, 3};
|
Matrix result(height, matrix::Row(width));
|
||||||
box.next();)
|
matrix::assign(result, 0);
|
||||||
{
|
|
||||||
Matrix result = map.walls();
|
|
||||||
result[start.y][start.x] = 1;
|
|
||||||
Point end{.x=box.x, .y=box.y};
|
|
||||||
|
|
||||||
for(matrix::line it{start, end}; it.next();)
|
size_t size = Random::uniform<int>(4, 10);
|
||||||
{
|
|
||||||
REQUIRE(map.inmap(it.x, it.y));
|
Point target{width/2, height/2};
|
||||||
result[it.y][it.x] = 15;
|
matrix::box box{result, target.x, target.y, size};
|
||||||
|
while(box.next()) {
|
||||||
|
result[box.y][box.x] = box.distance();
|
||||||
}
|
}
|
||||||
|
|
||||||
result[start.y][start.x] = 15;
|
// matrix::dump(format("MAP {}x{} @ {},{}; BOX {}x{}; size: {}",
|
||||||
|
// matrix::width(result), matrix::height(result),
|
||||||
|
// target.x, target.y, box.right - box.left, box.bottom - box.top, size),
|
||||||
|
// result, target.x, target.y);
|
||||||
|
}
|
||||||
|
|
||||||
// matrix::dump("RESULT AFTER LINE", result, end.x, end.y);
|
void test_thrash_box_iterators() {
|
||||||
|
for(int count = 0; count < 5; count++) {
|
||||||
|
size_t width = Random::uniform<size_t>(1, 25);
|
||||||
|
size_t height = Random::uniform<size_t>(1, 33);
|
||||||
|
|
||||||
bool f_found = false;
|
Matrix test(height, matrix::Row(width));
|
||||||
for(matrix::each_cell it{result}; it.next();) {
|
random_matrix(test);
|
||||||
if(result[it.y][it.x] == 15) {
|
|
||||||
f_found = true;
|
// this will be greater than the random_matrix cells
|
||||||
break;
|
int test_i = Random::uniform<size_t>(20,30);
|
||||||
|
|
||||||
|
// go through every cell
|
||||||
|
for(matrix::each_cell target{test}; target.next();) {
|
||||||
|
PointList result;
|
||||||
|
// make a random size box
|
||||||
|
size_t size = Random::uniform<int>(1, 33);
|
||||||
|
matrix::box box{test, target.x, target.y, size};
|
||||||
|
|
||||||
|
while(box.next()) {
|
||||||
|
test[box.y][box.x] = test_i;
|
||||||
|
result.push_back({box.x, box.y});
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto point : result) {
|
||||||
|
CHECK(test[point.y][point.x] == test_i);
|
||||||
|
test[point.y][point.x] = 10; // kind of reset it for another try
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
REQUIRE(f_found);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("prototype circle algorithm", "[matrix]") {
|
void test_thrash_compass_iterators() {
|
||||||
for(int count = 0; count < 5; count++) {
|
for(int count = 0; count < 5; count++) {
|
||||||
size_t width = Random::uniform<size_t>(10, 13);
|
size_t width = Random::uniform<size_t>(1, 25);
|
||||||
|
size_t height = Random::uniform<size_t>(1, 33);
|
||||||
|
|
||||||
|
Matrix test(height, matrix::Row(width));
|
||||||
|
random_matrix(test);
|
||||||
|
|
||||||
|
// this will be greater than the random_matrix cells
|
||||||
|
int test_i = Random::uniform<size_t>(20,30);
|
||||||
|
|
||||||
|
// go through every cell
|
||||||
|
for(matrix::each_cell target{test}; target.next();) {
|
||||||
|
PointList result;
|
||||||
|
// make a random size box
|
||||||
|
matrix::compass compass{test, target.x, target.y};
|
||||||
|
|
||||||
|
while(compass.next()) {
|
||||||
|
test[compass.y][compass.x] = test_i;
|
||||||
|
result.push_back({compass.x, compass.y});
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto point : result) {
|
||||||
|
CHECK(test[point.y][point.x] == test_i);
|
||||||
|
test[point.y][point.x] = 10; // kind of reset it for another try
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_prototype_line_algorithm() {
|
||||||
|
size_t width = Random::uniform<size_t>(10, 12);
|
||||||
size_t height = Random::uniform<size_t>(10, 15);
|
size_t height = Random::uniform<size_t>(10, 15);
|
||||||
int pos_mod = Random::uniform<int>(-3,3);
|
|
||||||
Map map(width,height);
|
Map map(width,height);
|
||||||
|
|
||||||
// create a target for the paths
|
// create a target for the paths
|
||||||
Point start{.x=map.width() / 2 + pos_mod, .y=map.height()/2 + pos_mod};
|
Point start{.x=map.width() / 2, .y=map.height()/2};
|
||||||
|
|
||||||
for(float radius = 1.0f; radius < 4.0f; radius += 0.1f) {
|
for(matrix::box box{map.walls(), start.x, start.y, 3};
|
||||||
// use an empty map
|
box.next();)
|
||||||
|
{
|
||||||
Matrix result = map.walls();
|
Matrix result = map.walls();
|
||||||
|
result[start.y][start.x] = 1;
|
||||||
|
Point end{.x=box.x, .y=box.y};
|
||||||
|
|
||||||
for(matrix::circle it{result, start, radius}; it.next();) {
|
for(matrix::line it{start, end}; it.next();)
|
||||||
for(int x = it.left; x < it.right; x++) {
|
{
|
||||||
// println("top={}, bottom={}, center.y={}, dy={}, left={}, right={}, x={}, y={}", it.top, it.bottom, it.center.y, it.dy, it.left, it.right, x, it.y);
|
CHECK(map.inmap(it.x, it.y));
|
||||||
// println("RESULT {},{}", matrix::width(result), matrix::height(result));
|
result[it.y][it.x] = 15;
|
||||||
REQUIRE(it.y >= 0);
|
}
|
||||||
REQUIRE(x >= 0);
|
|
||||||
REQUIRE(it.y < int(matrix::height(result)));
|
result[start.y][start.x] = 15;
|
||||||
REQUIRE(x < int(matrix::width(result)));
|
|
||||||
result[it.y][x] += 1;
|
// matrix::dump("RESULT AFTER LINE", result, end.x, end.y);
|
||||||
|
|
||||||
|
bool f_found = false;
|
||||||
|
for(matrix::each_cell it{result}; it.next();) {
|
||||||
|
if(result[it.y][it.x] == 15) {
|
||||||
|
f_found = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// matrix::dump(format("RESULT AFTER CIRCLE radius {}", radius), result, start.x, start.y);
|
CHECK(f_found);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("viewport iterator", "[matrix]") {
|
void test_prototype_circle_algorithm() {
|
||||||
components::init();
|
for(int count = 0; count < 5; count++) {
|
||||||
textures::init();
|
size_t width = Random::uniform<size_t>(10, 13);
|
||||||
GameDB::init();
|
size_t height = Random::uniform<size_t>(10, 15);
|
||||||
size_t width = Random::uniform<size_t>(20, 22);
|
int pos_mod = Random::uniform<int>(-3,3);
|
||||||
size_t height = Random::uniform<size_t>(21, 25);
|
Map map(width,height);
|
||||||
shared_ptr<Map> map = make_map();
|
|
||||||
|
|
||||||
size_t view_width = width/2;
|
// create a target for the paths
|
||||||
size_t view_height = height/2;
|
Point start{.x=map.width() / 2 + pos_mod, .y=map.height()/2 + pos_mod};
|
||||||
Point player;
|
|
||||||
REQUIRE(map->place_entity(1, player));
|
|
||||||
Point start = map->center_camera(player, view_width, view_height);
|
|
||||||
|
|
||||||
size_t end_x = std::min(view_width, map->width() - start.x);
|
for(float radius = 1.0f; radius < 4.0f; radius += 0.1f) {
|
||||||
size_t end_y = std::min(view_height, map->height() - start.y);
|
// use an empty map
|
||||||
|
Matrix result = map.walls();
|
||||||
|
|
||||||
matrix::viewport it{map->walls(), start, int(view_width), int(view_height)};
|
for(matrix::circle it{result, start, radius}; it.next();) {
|
||||||
|
for(int x = it.left; x < it.right; x++) {
|
||||||
|
// println("top={}, bottom={}, center.y={}, dy={}, left={}, right={}, x={}, y={}", it.top, it.bottom, it.center.y, it.dy, it.left, it.right, x, it.y);
|
||||||
|
// println("RESULT {},{}", matrix::width(result), matrix::height(result));
|
||||||
|
CHECK(it.y >= 0);
|
||||||
|
CHECK(x >= 0);
|
||||||
|
CHECK(it.y < int(matrix::height(result)));
|
||||||
|
CHECK(x < int(matrix::width(result)));
|
||||||
|
result[it.y][x] += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for(size_t y = 0; y < end_y; ++y) {
|
// matrix::dump(format("RESULT AFTER CIRCLE radius {}", radius), result, start.x, start.y);
|
||||||
for(size_t x = 0; x < end_x && it.next(); ++x) {
|
|
||||||
// still working on this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("random rectangle", "[matrix]") {
|
|
||||||
components::init();
|
|
||||||
for(int i = 0; i < 5; i++) {
|
|
||||||
shared_ptr<Map> map = make_map();
|
|
||||||
map->invert_space();
|
|
||||||
auto wall_copy = map->walls();
|
|
||||||
|
|
||||||
for(size_t rnum = 0; rnum < map->room_count(); rnum++) {
|
|
||||||
Room &room = map->room(rnum);
|
|
||||||
Point pos;
|
|
||||||
|
|
||||||
for(matrix::rando_rect it{map->walls(), room.x, room.y, room.width, room.height}; it.next();)
|
|
||||||
{
|
|
||||||
REQUIRE(size_t(it.x) >= room.x);
|
|
||||||
REQUIRE(size_t(it.y) >= room.y);
|
|
||||||
REQUIRE(size_t(it.x) <= room.x + room.width);
|
|
||||||
REQUIRE(size_t(it.y) <= room.y + room.height);
|
|
||||||
|
|
||||||
wall_copy[it.y][it.x] = wall_copy[it.y][it.x] + 5;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// matrix::dump("WALLS FILLED", wall_copy);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("standard rectangle", "[matrix]") {
|
void test_viewport_iterator() {
|
||||||
components::init();
|
components::init();
|
||||||
for(int i = 0; i < 5; i++) {
|
textures::init();
|
||||||
|
GameDB::init();
|
||||||
|
size_t width = Random::uniform<size_t>(20, 22);
|
||||||
|
size_t height = Random::uniform<size_t>(21, 25);
|
||||||
shared_ptr<Map> map = make_map();
|
shared_ptr<Map> map = make_map();
|
||||||
auto wall_copy = map->walls();
|
|
||||||
|
|
||||||
for(size_t rnum = 0; rnum < map->room_count(); rnum++) {
|
size_t view_width = width/2;
|
||||||
Room &room = map->room(rnum);
|
size_t view_height = height/2;
|
||||||
Point pos;
|
Point player;
|
||||||
|
CHECK(map->place_entity(1, player));
|
||||||
|
Point start = map->center_camera(player, view_width, view_height);
|
||||||
|
|
||||||
for(matrix::rectangle it{map->walls(), room.x, room.y, room.width, room.height}; it.next();)
|
size_t end_x = std::min(view_width, map->width() - start.x);
|
||||||
{
|
size_t end_y = std::min(view_height, map->height() - start.y);
|
||||||
REQUIRE(size_t(it.x) >= room.x);
|
|
||||||
REQUIRE(size_t(it.y) >= room.y);
|
|
||||||
REQUIRE(size_t(it.x) <= room.x + room.width);
|
|
||||||
REQUIRE(size_t(it.y) <= room.y + room.height);
|
|
||||||
|
|
||||||
wall_copy[it.y][it.x] = wall_copy[it.y][it.x] + 5;
|
matrix::viewport it{map->walls(), start, int(view_width), int(view_height)};
|
||||||
|
|
||||||
|
for(size_t y = 0; y < end_y; ++y) {
|
||||||
|
for(size_t x = 0; x < end_x && it.next(); ++x) {
|
||||||
|
// still working on this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// matrix::dump("WALLS FILLED", wall_copy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_random_rectangle() {
|
||||||
|
components::init();
|
||||||
|
for(int i = 0; i < 5; i++) {
|
||||||
|
shared_ptr<Map> map = make_map();
|
||||||
|
map->invert_space();
|
||||||
|
auto wall_copy = map->walls();
|
||||||
|
|
||||||
|
for(size_t rnum = 0; rnum < map->room_count(); rnum++) {
|
||||||
|
Room &room = map->room(rnum);
|
||||||
|
Point pos;
|
||||||
|
|
||||||
|
for(matrix::rando_rect it{map->walls(), room.x, room.y, room.width, room.height}; it.next();)
|
||||||
|
{
|
||||||
|
CHECK(size_t(it.x) >= room.x);
|
||||||
|
CHECK(size_t(it.y) >= room.y);
|
||||||
|
CHECK(size_t(it.x) <= room.x + room.width);
|
||||||
|
CHECK(size_t(it.y) <= room.y + room.height);
|
||||||
|
|
||||||
|
wall_copy[it.y][it.x] = wall_copy[it.y][it.x] + 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// matrix::dump("WALLS FILLED", wall_copy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_standard_rectangle() {
|
||||||
|
components::init();
|
||||||
|
for(int i = 0; i < 5; i++) {
|
||||||
|
shared_ptr<Map> map = make_map();
|
||||||
|
auto wall_copy = map->walls();
|
||||||
|
|
||||||
|
for(size_t rnum = 0; rnum < map->room_count(); rnum++) {
|
||||||
|
Room &room = map->room(rnum);
|
||||||
|
Point pos;
|
||||||
|
|
||||||
|
for(matrix::rectangle it{map->walls(), room.x, room.y, room.width, room.height}; it.next();)
|
||||||
|
{
|
||||||
|
CHECK(size_t(it.x) >= room.x);
|
||||||
|
CHECK(size_t(it.y) >= room.y);
|
||||||
|
CHECK(size_t(it.x) <= room.x + room.width);
|
||||||
|
CHECK(size_t(it.y) <= room.y + room.height);
|
||||||
|
|
||||||
|
wall_copy[it.y][it.x] = wall_copy[it.y][it.x] + 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// matrix::dump("WALLS FILLED", wall_copy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fuc2::Set TESTS{
|
||||||
|
.name="matrix",
|
||||||
|
.tests={
|
||||||
|
TEST(test_thrash_matrix_iterators),
|
||||||
|
TEST(test_thrash_box_distance_iterators),
|
||||||
|
TEST(test_thrash_box_iterators),
|
||||||
|
TEST(test_thrash_compass_iterators),
|
||||||
|
TEST(test_prototype_line_algorithm),
|
||||||
|
TEST(test_prototype_circle_algorithm),
|
||||||
|
TEST(test_viewport_iterator),
|
||||||
|
TEST(test_random_rectangle),
|
||||||
|
TEST(test_standard_rectangle),
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
265
tests/mazes.cpp
265
tests/mazes.cpp
|
|
@ -1,4 +1,4 @@
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <fuc2/testing.hpp>
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "algos/matrix.hpp"
|
#include "algos/matrix.hpp"
|
||||||
|
|
@ -11,150 +11,152 @@
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using matrix::Matrix;
|
using matrix::Matrix;
|
||||||
|
using namespace fuc2;
|
||||||
|
|
||||||
TEST_CASE("hunt-and-kill", "[mazes]") {
|
namespace mazes_tests {
|
||||||
Map map(21, 21);
|
void test_hunt_and_kill() {
|
||||||
maze::Builder maze(map);
|
Map map(21, 21);
|
||||||
|
|
||||||
maze.hunt_and_kill();
|
|
||||||
REQUIRE(maze.repair() == true);
|
|
||||||
|
|
||||||
if(DUMP) maze.dump("BASIC MAZE");
|
|
||||||
|
|
||||||
maze.randomize_rooms(ROOM_SIZE);
|
|
||||||
maze.hunt_and_kill();
|
|
||||||
maze.place_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::Builder maze(map);
|
||||||
|
|
||||||
maze.hunt_and_kill();
|
maze.hunt_and_kill();
|
||||||
maze.clear();
|
CHECK(maze.repair() == true);
|
||||||
maze.inner_box(6, 4);
|
|
||||||
|
if(DUMP) maze.dump("BASIC MAZE");
|
||||||
|
|
||||||
maze.randomize_rooms(ROOM_SIZE);
|
maze.randomize_rooms(ROOM_SIZE);
|
||||||
|
|
||||||
maze.hunt_and_kill();
|
|
||||||
maze.open_box(6);
|
|
||||||
maze.place_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.hunt_and_kill();
|
||||||
maze.place_doors();
|
maze.place_doors();
|
||||||
auto valid = maze.repair();
|
CHECK(maze.repair() == true);
|
||||||
|
|
||||||
if(i == 41 && DUMP && valid) {
|
if(DUMP) maze.dump("ROOM MAZE");
|
||||||
maze.dump("COMBINED");
|
|
||||||
}
|
CHECK(map.$dead_ends.size() > 0);
|
||||||
|
CHECK(map.$rooms.size() > 0);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("hunt-and-kill validator", "[mazes]") {
|
void test_hunt_and_kill_box() {
|
||||||
bool valid = true;
|
for(int i = 25; i < 65; i += 2) {
|
||||||
Stats mofm;
|
Map map(i, i);
|
||||||
|
|
||||||
for(int i = 0; i < 10; i++) {
|
|
||||||
Stats door_prob;
|
|
||||||
|
|
||||||
do {
|
|
||||||
Map map(33, 33);
|
|
||||||
maze::Builder maze(map);
|
maze::Builder maze(map);
|
||||||
|
|
||||||
maze.hunt_and_kill();
|
maze.hunt_and_kill();
|
||||||
maze.clear();
|
maze.clear();
|
||||||
maze.inner_box(6, 4);
|
maze.inner_box(6, 4);
|
||||||
maze.randomize_rooms(ROOM_SIZE);
|
maze.randomize_rooms(ROOM_SIZE);
|
||||||
|
|
||||||
maze.hunt_and_kill();
|
maze.hunt_and_kill();
|
||||||
maze.open_box(6);
|
maze.open_box(6);
|
||||||
maze.place_doors();
|
maze.place_doors();
|
||||||
valid = maze.repair();
|
auto valid = maze.repair();
|
||||||
|
|
||||||
if(i == 9 && DUMP) {
|
if(i == 41 && DUMP) {
|
||||||
maze.dump(valid ? "VALIDATED" : "FAILED!");
|
maze.dump(valid ? "INNER BOX" : "FAILED BOX");
|
||||||
}
|
}
|
||||||
door_prob.sample(valid);
|
}
|
||||||
} while(!valid);
|
|
||||||
|
|
||||||
if(DUMP) door_prob.dump();
|
|
||||||
mofm.sample(door_prob.mean());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(DUMP) {
|
void test_hunt_and_kill_ring() {
|
||||||
fmt::println("FINAL m-of-m");
|
Map map(21, 21);
|
||||||
mofm.dump();
|
maze::Builder maze(map);
|
||||||
|
|
||||||
|
maze.inner_donut(5.5, 3.5);
|
||||||
|
maze.hunt_and_kill();
|
||||||
|
CHECK(maze.repair() == true);
|
||||||
|
|
||||||
|
if(DUMP) maze.dump("INNER RING");
|
||||||
|
|
||||||
|
CHECK(maze.$rooms.size() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
REQUIRE(mofm.mean() > 0.20);
|
void test_hunt_and_kill_fissure() {
|
||||||
}
|
Map map(21, 21);
|
||||||
|
maze::Builder maze(map);
|
||||||
|
|
||||||
|
maze.divide({3,3}, {19,18});
|
||||||
|
maze.hunt_and_kill();
|
||||||
|
CHECK(maze.repair() == true);
|
||||||
|
|
||||||
|
if(DUMP) maze.dump("FISSURE MAZE");
|
||||||
|
|
||||||
|
CHECK(maze.$rooms.size() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_hunt_and_kill_no_dead_ends() {
|
||||||
|
Map map(21, 21);
|
||||||
|
maze::Builder maze(map);
|
||||||
|
|
||||||
|
maze.hunt_and_kill();
|
||||||
|
maze.remove_dead_ends();
|
||||||
|
CHECK(maze.repair() == true);
|
||||||
|
|
||||||
|
if(DUMP) maze.dump("NO DEAD ENDS");
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_hunt_and_kill_too_much() {
|
||||||
|
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.place_doors();
|
||||||
|
auto valid = maze.repair();
|
||||||
|
|
||||||
|
if(i == 41 && DUMP && valid) {
|
||||||
|
maze.dump("COMBINED");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_hunt_and_kill_validator() {
|
||||||
|
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.place_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();
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK(mofm.mean() > 0.20);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST_CASE("hunt-and-kill scripting", "[mazes]") {
|
void test_hunt_and_kill_scripting() {
|
||||||
using namespace nlohmann::literals;
|
using namespace nlohmann::literals;
|
||||||
|
|
||||||
// go up by 2 to keep odd
|
// go up by 2 to keep odd
|
||||||
for(int i = 0; i < 20; i+=2) {
|
for(int i = 0; i < 20; i+=2) {
|
||||||
auto script = R"(
|
auto script = R"(
|
||||||
[
|
[
|
||||||
{"action": "hunt_and_kill"},
|
{"action": "hunt_and_kill"},
|
||||||
{"action": "clear"},
|
{"action": "clear"},
|
||||||
|
|
@ -169,14 +171,29 @@ TEST_CASE("hunt-and-kill scripting", "[mazes]") {
|
||||||
]
|
]
|
||||||
)"_json;
|
)"_json;
|
||||||
|
|
||||||
Map map(23+i, 23+i);
|
Map map(23+i, 23+i);
|
||||||
auto [maze, valid] = maze::script(map, script);
|
auto [maze, valid] = maze::script(map, script);
|
||||||
|
|
||||||
if(valid) {
|
if(valid) {
|
||||||
REQUIRE(maze.validate() == true);
|
CHECK(maze.validate() == true);
|
||||||
REQUIRE(map.INVARIANT() == true);
|
CHECK(map.INVARIANT() == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(DUMP) maze.dump(valid ? "SCRIPTED" : "SCRIPTED FAIL!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(DUMP) maze.dump(valid ? "SCRIPTED" : "SCRIPTED FAIL!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fuc2::Set TESTS{
|
||||||
|
.name="mazes",
|
||||||
|
.tests={
|
||||||
|
TEST(test_hunt_and_kill_scripting),
|
||||||
|
TEST(test_hunt_and_kill_validator),
|
||||||
|
TEST(test_hunt_and_kill_too_much),
|
||||||
|
TEST(test_hunt_and_kill_no_dead_ends),
|
||||||
|
TEST(test_hunt_and_kill_fissure),
|
||||||
|
TEST(test_hunt_and_kill_ring),
|
||||||
|
TEST(test_hunt_and_kill_box),
|
||||||
|
TEST(test_hunt_and_kill),
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,4 @@
|
||||||
tests = files(
|
tests = files(
|
||||||
'event_router.cpp',
|
|
||||||
'fsm.cpp',
|
|
||||||
'inventory.cpp',
|
|
||||||
'lighting.cpp',
|
|
||||||
'loot.cpp',
|
|
||||||
'map.cpp',
|
|
||||||
'matrix.cpp',
|
|
||||||
'mazes.cpp',
|
|
||||||
'palette.cpp',
|
'palette.cpp',
|
||||||
'pathing.cpp',
|
'pathing.cpp',
|
||||||
'rituals.cpp',
|
'rituals.cpp',
|
||||||
|
|
@ -19,6 +11,14 @@ tests = files(
|
||||||
)
|
)
|
||||||
|
|
||||||
fuc2_tests = files(
|
fuc2_tests = files(
|
||||||
|
'mazes.cpp',
|
||||||
|
'matrix.cpp',
|
||||||
|
'map.cpp',
|
||||||
|
'loot.cpp',
|
||||||
|
'lighting.cpp',
|
||||||
|
'inventory.cpp',
|
||||||
|
'fsm.cpp',
|
||||||
|
'event_router.cpp',
|
||||||
'dinkyecs.cpp',
|
'dinkyecs.cpp',
|
||||||
'dbc.cpp',
|
'dbc.cpp',
|
||||||
'ai.cpp',
|
'ai.cpp',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue