276 lines
6.8 KiB
C++
276 lines
6.8 KiB
C++
#include <fuc2/testing.hpp>
|
|
#include <fmt/core.h>
|
|
#include <string>
|
|
#include "algos/spatialmap.hpp"
|
|
#include "algos/dinkyecs.hpp"
|
|
#include "algos/rand.hpp"
|
|
#include <limits>
|
|
#include <fmt/core.h>
|
|
|
|
using DinkyECS::Entity;
|
|
using namespace fmt;
|
|
using namespace fuc2;
|
|
|
|
namespace spatialmap_tests {
|
|
void test_SpatialMap_insert() {
|
|
DinkyECS::World world;
|
|
SpatialMap map;
|
|
|
|
auto player = world.entity();
|
|
auto item = world.entity();
|
|
auto potion = world.entity();
|
|
auto enemy = world.entity();
|
|
Point at{10,10};
|
|
Point enemy_at{11,11};
|
|
|
|
map.insert(at, item, false);
|
|
map.insert(at, potion, false);
|
|
CHECK(!map.occupied(at));
|
|
|
|
map.insert(at, player, true);
|
|
CHECK(map.occupied_by(at) == player);
|
|
|
|
BLOWS_UP([&]() {
|
|
map.insert(at, enemy, true);
|
|
});
|
|
|
|
map.insert(enemy_at, enemy, true);
|
|
CHECK(map.occupied_by(enemy_at) == enemy);
|
|
CHECK(map.occupied(enemy_at));
|
|
}
|
|
|
|
void test_SpatialMap_remove() {
|
|
DinkyECS::World world;
|
|
SpatialMap map;
|
|
|
|
auto player = world.entity();
|
|
auto item = world.entity();
|
|
Point at{120, 120};
|
|
|
|
// confirm that things can be in any order
|
|
map.insert(at, player, true);
|
|
map.insert(at, item, false);
|
|
CHECK(map.occupied(at));
|
|
CHECK(map.occupied_by(at) == player);
|
|
|
|
auto data = map.remove(at, player);
|
|
CHECK(!map.occupied(at));
|
|
CHECK(data.entity == player);
|
|
CHECK(data.collision == true);
|
|
|
|
BLOWS_UP([&]() {
|
|
map.remove(at, player);
|
|
});
|
|
}
|
|
|
|
|
|
void test_SpatialMap_move() {
|
|
DinkyECS::World world;
|
|
SpatialMap map;
|
|
|
|
auto player = world.entity();
|
|
auto item = world.entity();
|
|
Point at{10, 320};
|
|
map.insert(at, player, true);
|
|
map.insert(at, item, false);
|
|
CHECK(map.occupied(at));
|
|
|
|
auto enemy = world.entity();
|
|
auto potion = world.entity();
|
|
Point enemy_at{11, 320};
|
|
map.insert(enemy_at, enemy, true);
|
|
map.insert(enemy_at, potion, false);
|
|
CHECK(map.occupied(enemy_at));
|
|
CHECK(map.occupied_by(enemy_at) == enemy);
|
|
|
|
Point target{at.x + 1, at.y};
|
|
|
|
// try bad move with a slot that's empty
|
|
BLOWS_UP([&]() {
|
|
map.move({0,0}, target, player);
|
|
});
|
|
|
|
// try move into an occupied spot also fails
|
|
BLOWS_UP([&]() {
|
|
map.move(at, target, player);
|
|
});
|
|
|
|
// now move to a new spot, need to add them back
|
|
map.insert(at, player, true);
|
|
target.x++; // just move farther
|
|
map.move(at, target, player);
|
|
|
|
CHECK(map.occupied(target));
|
|
CHECK(map.occupied_by(target) == player);
|
|
auto data = map.remove(target, player);
|
|
CHECK(data.entity == player);
|
|
CHECK(data.collision == true);
|
|
}
|
|
|
|
|
|
void test_SpatialMap_occupied() {
|
|
DinkyECS::World world;
|
|
SpatialMap map;
|
|
|
|
auto player = world.entity();
|
|
auto item = world.entity();
|
|
|
|
Point at{1000, 20};
|
|
// first test empty locations
|
|
CHECK(!map.something_there(at));
|
|
CHECK(!map.occupied(at));
|
|
|
|
// then when there's something without collision
|
|
map.insert(at, item, false);
|
|
CHECK(map.something_there(at));
|
|
CHECK(!map.occupied(at));
|
|
|
|
// finally with collision and an item there
|
|
map.insert(at, player, true);
|
|
CHECK(map.something_there(at));
|
|
CHECK(map.occupied(at));
|
|
CHECK(map.occupied_by(at) == player);
|
|
|
|
// then remove the item and still have collision
|
|
|
|
map.remove(at, item);
|
|
CHECK(map.something_there(at));
|
|
CHECK(map.occupied(at));
|
|
CHECK(map.occupied_by(at) == player);
|
|
|
|
// remove player and back to no collision
|
|
map.remove(at, player);
|
|
CHECK(!map.something_there(at));
|
|
CHECK(!map.occupied(at));
|
|
|
|
// last thing, put just the player in at a new spot
|
|
Point target{at.x+1, at.y+10};
|
|
map.insert(target, player, true);
|
|
CHECK(map.something_there(target));
|
|
CHECK(map.occupied(target));
|
|
CHECK(map.occupied_by(target) == player);
|
|
}
|
|
|
|
|
|
void test_SpatialMap_get() {
|
|
DinkyECS::World world;
|
|
SpatialMap map;
|
|
|
|
auto player = world.entity();
|
|
auto item = world.entity();
|
|
Point at{101, 31};
|
|
|
|
// finally with collision and an item there
|
|
map.insert(at, player, true);
|
|
CHECK(map.occupied(at));
|
|
CHECK(map.occupied_by(at) == player);
|
|
|
|
auto entity = map.get(at);
|
|
CHECK(player == entity);
|
|
|
|
// This probably doesn't work so need to
|
|
// rethink how get works.
|
|
map.insert(at, item, false);
|
|
entity = map.get(at);
|
|
CHECK(entity == item);
|
|
}
|
|
|
|
void test_SpatialMap_find() {
|
|
DinkyECS::World world;
|
|
SpatialMap map;
|
|
Point at{101, 31};
|
|
DinkyECS::Entity should_collide = DinkyECS::NONE;
|
|
|
|
for(int i = 0; i < 10; i++) {
|
|
auto ent = world.entity();
|
|
map.insert(at, ent, i == 8);
|
|
|
|
if(i == 8) {
|
|
should_collide = ent;
|
|
}
|
|
}
|
|
|
|
auto collision = map.find(at, [&](auto data) -> bool {
|
|
return data.collision;
|
|
});
|
|
|
|
CHECK(collision == should_collide);
|
|
|
|
auto no_collide = map.find(at, [&](auto data) -> bool {
|
|
return !data.collision;
|
|
});
|
|
|
|
CHECK(no_collide != should_collide);
|
|
}
|
|
|
|
void test_SpatialMap_neighbors() {
|
|
DinkyECS::World world;
|
|
SpatialMap map;
|
|
|
|
auto player = world.entity();
|
|
auto enemy1 = world.entity();
|
|
auto enemy2 = world.entity();
|
|
//auto item1 = world.entity();
|
|
//auto item2 = world.entity();
|
|
Point at{101, 31};
|
|
|
|
map.insert(at, player, true);
|
|
map.insert({at.x+1, at.y}, enemy1, true);
|
|
map.insert({at.x-1, at.y+1}, enemy2, true);
|
|
|
|
auto result = map.neighbors(at, true);
|
|
CHECK(result.found);
|
|
CHECK(result.nearby.size() == 2);
|
|
|
|
bool maybe = result.nearby[0] == enemy1 || result.nearby[1] == enemy1;
|
|
CHECK(maybe);
|
|
|
|
maybe = result.nearby[0] == enemy2 || result.nearby[1] == enemy2;
|
|
CHECK(maybe);
|
|
|
|
result = map.neighbors(at, false);
|
|
CHECK(result.found);
|
|
CHECK(result.nearby.size() == 1);
|
|
CHECK(result.nearby[0] == enemy1);
|
|
}
|
|
|
|
void test_SpatialMap_distance_sorted() {
|
|
DinkyECS::World world;
|
|
SpatialMap map;
|
|
|
|
auto player = world.entity();
|
|
auto enemy1 = world.entity();
|
|
auto item = world.entity();
|
|
|
|
map.insert({1,1}, player, true);
|
|
map.insert({4,4}, enemy1, true);
|
|
map.insert({3, 3}, item, false);
|
|
|
|
SortedEntities result;
|
|
map.distance_sorted(result, {1, 1}, 100);
|
|
CHECK(result.size() == 3);
|
|
CHECK(result[0].entity == enemy1);
|
|
CHECK(result[1].entity == item);
|
|
CHECK(result[2].entity == player);
|
|
|
|
int prev_dist = std::numeric_limits<int>::max();
|
|
for(auto rec : result) {
|
|
CHECK(rec.dist_square < prev_dist);
|
|
prev_dist = rec.dist_square;
|
|
}
|
|
}
|
|
|
|
fuc2::Set TESTS{
|
|
.name="spatialmap",
|
|
.tests={
|
|
TEST(test_SpatialMap_distance_sorted),
|
|
TEST(test_SpatialMap_neighbors),
|
|
TEST(test_SpatialMap_find),
|
|
TEST(test_SpatialMap_get),
|
|
TEST(test_SpatialMap_occupied),
|
|
TEST(test_SpatialMap_move),
|
|
TEST(test_SpatialMap_remove),
|
|
TEST(test_SpatialMap_insert),
|
|
}
|
|
};
|
|
}
|