Skip to content

Commit

Permalink
Finished updating tests for test_map.cpp.
Browse files Browse the repository at this point in the history
Renamed dijkstra.hpp to searching.hpp and finished tests for generate_item_position().

Added tests for Grid::is_position_within.

Refactored a few tests to move variables inside the assert statements.
  • Loading branch information
JackAshwell11 committed Dec 29, 2023
1 parent ad38e17 commit 091b037
Show file tree
Hide file tree
Showing 14 changed files with 375 additions and 240 deletions.
2 changes: 1 addition & 1 deletion src/hades_extensions/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Define some project-wide options
cmake_minimum_required(VERSION 3.25.2)
cmake_minimum_required(VERSION 3.22.1)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand Down
4 changes: 2 additions & 2 deletions src/hades_extensions/CMakePresets.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"cmakeMinimumRequired": {
"major": 3,
"minor": 25,
"patch": 2
"minor": 22,
"patch": 1
},
"configurePresets": [
{
Expand Down
25 changes: 13 additions & 12 deletions src/hades_extensions/include/generation/map.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

// Local headers
#include "bsp.hpp"
#include "dijkstra.hpp"
#include "searching.hpp"

// ----- STRUCTURES ------------------------------
/// Represents an undirected weighted edge in a graph.
Expand Down Expand Up @@ -42,26 +42,26 @@ struct std::hash<Edge> {
};

// ----- FUNCTIONS ------------------------------
/// Places a tile in the 2D grid using a Dijkstra map.
/// Place a random tile in the 2D grid.
///
/// @param grid - The 2D grid which represents the dungeon.
/// @param random_generator - The random generator used to pick the position.
/// @param item_positions - The positions of all the items in the 2D grid.
/// @param replaceable_tile - The tile to replace in the 2D grid.
/// @param target_tile - The tile to place in the 2D grid.
/// @param count - The number of tiles to place.
/// @throws std::length_error - If the grid is empty.
void place_tiles(const Grid &grid, std::mt19937 &random_generator, std::unordered_set<Position> &item_positions,
TileType target_tile, int count);
[[maybe_unused]] auto place_random_tiles(const Grid &grid, std::mt19937 &random_generator, TileType replaceable_tile,
TileType target_tile, int count = 1) -> std::unordered_set<Position>;

/// Place a random tile in the 2D grid.
/// Places a tile in the 2D grid using the Dijkstra map algorithm.
///
/// @param grid - The 2D grid which represents the dungeon.
/// @param random_generator - The random generator used to pick the position.
/// @param replaceable_tile - The tile to replace in the 2D grid.
/// @param item_positions - The positions of all the items in the 2D grid.
/// @param target_tile - The tile to place in the 2D grid.
/// @param count - The number of tiles to place.
[[maybe_unused]] auto place_tiles(const Grid &grid, std::mt19937 &random_generator, TileType replaceable_tile,
TileType target_tile, int count = 1) -> std::unordered_set<Position>;
/// @throws std::length_error - If the grid is empty.
void place_dijkstra_tiles(const Grid &grid, std::mt19937 &random_generator,
std::unordered_set<Position> &item_positions, TileType target_tile, int count);

/// Create a complete graph from a given list of rooms.
///
Expand All @@ -81,7 +81,7 @@ auto create_connections(const std::unordered_map<Rect, std::vector<Rect>> &compl
///
/// @param grid - The 2D grid which represents the dungeon.
/// @param connections - The connections to pathfind using the A* algorithm.
void create_hallways(Grid &grid, const std::unordered_set<Edge> &connections);
void create_hallways(const Grid &grid, const std::unordered_set<Edge> &connections);

/// Generate the game map for a given game level.
///
Expand All @@ -91,4 +91,5 @@ void create_hallways(Grid &grid, const std::unordered_set<Edge> &connections);
auto create_map(int level, std::optional<unsigned int> seed = std::nullopt)
-> std::pair<std::vector<TileType>, std::tuple<int, int, int>>;

// TODO: Go over documentation for whole of generation/ to check for more @throws
// TODO: Go over generation/ documentation for whole of generation/ to check for more @throws
// TODO: Check if exceptions should have full stops
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@
/// @return A vector of positions mapping out the shortest path from start to end.
auto calculate_astar_path(const Grid &grid, const Position &start, const Position &end) -> std::vector<Position>;

/// Get a random Dijkstra map position for the given grid and minimum distance.
/// Generate a random position in a grid using the Dijkstra map algorithm.
///
/// @param grid - The grid to generate the Dijkstra map position for.
/// @param item_positions - The positions of the items to generate the Dijkstra map position for.
/// @param within - Whether to get a position within the minimum distance or not.
/// @throws std::length_error - If the grid size is less than 0.
/// @return A random Dijkstra map position.
auto generate_dijkstra_map_position(const Grid &grid, const std::unordered_set<Position> &item_positions, bool within) -> Position;
auto generate_item_position(const Grid &grid, const std::unordered_set<Position> &item_positions, bool within)
-> Position;
2 changes: 1 addition & 1 deletion src/hades_extensions/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ add_library(${CPP_LIB} STATIC
${CMAKE_SOURCE_DIR}/src/game_objects/systems/movements.cpp
${CMAKE_SOURCE_DIR}/src/game_objects/systems/upgrade.cpp
${CMAKE_SOURCE_DIR}/src/generation/bsp.cpp
${CMAKE_SOURCE_DIR}/src/generation/dijkstra.cpp
${CMAKE_SOURCE_DIR}/src/generation/map.cpp
${CMAKE_SOURCE_DIR}/src/generation/primitives.cpp
${CMAKE_SOURCE_DIR}/src/generation/searching.cpp
)
target_include_directories(${CPP_LIB} PUBLIC ${CMAKE_SOURCE_DIR}/include)

Expand Down
54 changes: 28 additions & 26 deletions src/hades_extensions/src/generation/map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,23 +43,8 @@ constexpr MapGenerationConstant ITEM_COUNT{5, 1.1, 30};
map_generation_constant.max_value));
}

void place_tiles(const Grid &grid, std::mt19937 &random_generator, std::unordered_set<Position> &item_positions,
const TileType target_tile, const int count) {
// Place each tile using the Dijkstra map
for (int _ = 0; _ < count; _++) {
// Determine if we should select a position within or outside the minimum distance
const bool within_min_distance{std::uniform_real_distribution<>{0, 1}(random_generator) <
WITHIN_MIN_DISTANCE_CHANCE};

// Generate the Dijkstra map for the grid and place the tile in a random position
const Position possible_tile{generate_dijkstra_map_position(grid, item_positions, within_min_distance)};
grid.set_value(possible_tile, target_tile);
item_positions.emplace(possible_tile);
}
}

auto place_tiles(const Grid &grid, std::mt19937 &random_generator, const TileType replaceable_tile,
const TileType target_tile, const int count) -> std::unordered_set<Position> {
auto place_random_tiles(const Grid &grid, std::mt19937 &random_generator, const TileType replaceable_tile,
const TileType target_tile, const int count) -> std::unordered_set<Position> {
// Get all the positions that match the replaceable tile
std::vector<Position> replaceable_tiles;
for (int y = 0; y < grid.height; y++) {
Expand All @@ -70,6 +55,11 @@ auto place_tiles(const Grid &grid, std::mt19937 &random_generator, const TileTyp
}
}

// Check if there are enough replaceable tiles to place the target tile
if (static_cast<int>(replaceable_tiles.size()) < count) {
throw std::length_error("Not enough replaceable tiles to place the target tiles.");
}

// Create a collection to store the item positions then place each tile
std::unordered_set<Position> item_positions;
for (int _ = 0; _ < count; _++) {
Expand All @@ -84,6 +74,21 @@ auto place_tiles(const Grid &grid, std::mt19937 &random_generator, const TileTyp
return item_positions;
}

void place_dijkstra_tiles(const Grid &grid, std::mt19937 &random_generator,
std::unordered_set<Position> &item_positions, const TileType target_tile, const int count) {
// Place each tile using the Dijkstra map
for (int _ = 0; _ < count; _++) {
// Determine if we should select a position within or outside the minimum distance
const bool within_min_distance{std::uniform_real_distribution<>{0, 1}(random_generator) <
WITHIN_MIN_DISTANCE_CHANCE};

// Generate the Dijkstra map for the grid and place the tile in a random position
const Position possible_tile{generate_item_position(grid, item_positions, within_min_distance)};
grid.set_value(possible_tile, target_tile);
item_positions.emplace(possible_tile);
}
}

auto create_complete_graph(const std::vector<Rect> &rooms) -> std::unordered_map<Rect, std::vector<Rect>> {
// Check if the rooms vector is empty
if (rooms.empty()) {
Expand Down Expand Up @@ -140,7 +145,7 @@ auto create_connections(const std::unordered_map<Rect, std::vector<Rect>> &compl
return mst;
}

void create_hallways(Grid &grid, const std::unordered_set<Edge> &connections) {
void create_hallways(const Grid &grid, const std::unordered_set<Edge> &connections) {
// Use the A* algorithm to connect each pair of rooms avoiding the obstacles
std::vector<std::vector<Position>> path_positions(connections.size());
std::transform(std::execution::par, connections.begin(), connections.end(), path_positions.begin(),
Expand All @@ -157,8 +162,6 @@ void create_hallways(Grid &grid, const std::unordered_set<Edge> &connections) {
}
}

#include <iostream>

auto create_map(const int level, std::optional<unsigned int> seed)
-> std::pair<std::vector<TileType>, std::tuple<int, int, int>> {
// Check that the level number is valid
Expand All @@ -180,21 +183,20 @@ auto create_map(const int level, std::optional<unsigned int> seed)
Grid grid{grid_width, grid_height};
Leaf bsp{{{0, 0}, {grid_width - 1, grid_height - 1}}};

// Split the bsp, create the rooms, and create the hallways between the rooms
// Split the bsp and create the rooms
std::vector<Rect> rooms;
split(bsp, random_generator);
create_room(bsp, grid, random_generator, rooms);

// Place random obstacles in the grid then create hallways between the rooms
place_tiles(grid, random_generator, TileType::Empty, TileType::Obstacle, generate_value(OBSTACLE_COUNT, level));
place_random_tiles(grid, random_generator, TileType::Empty, TileType::Obstacle,
generate_value(OBSTACLE_COUNT, level));
create_hallways(grid, create_connections(create_complete_graph(rooms)));

// Place the player as well as the item tiles in the grid
auto item_positions{place_tiles(grid, random_generator, TileType::Floor, TileType::Player)};
place_tiles(grid, random_generator, item_positions, TileType::Potion, generate_value(ITEM_COUNT, level));
auto item_positions{place_random_tiles(grid, random_generator, TileType::Floor, TileType::Player)};
place_dijkstra_tiles(grid, random_generator, item_positions, TileType::Potion, generate_value(ITEM_COUNT, level));

// Return the grid and a LevelConstants object
return std::make_pair(*grid.grid, std::make_tuple(level, grid_width, grid_height));
}

// TODO: Optimise/simplify this whole file and maybe combine place_tiles with a boolean
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Related header
#include "generation/dijkstra.hpp"
#include "generation/searching.hpp"

// Std headers
#include <array>
Expand Down Expand Up @@ -90,10 +90,8 @@ auto calculate_astar_path(const Grid &grid, const Position &start, const Positio
return result;
}

// TODO: Optimise this and try to combine/simplify them

auto generate_dijkstra_map_position(const Grid &grid, const std::unordered_set<Position> &item_positions,
const bool within) -> Position {
auto generate_item_position(const Grid &grid, const std::unordered_set<Position> &item_positions, const bool within)
-> Position {
// Check if the grid size is not zero
if (grid.width == 0 || grid.height == 0) {
throw std::length_error("Grid size must be bigger than 0.");
Expand Down Expand Up @@ -143,7 +141,7 @@ auto generate_dijkstra_map_position(const Grid &grid, const std::unordered_set<P
if (within && !within_positions.empty()) {
return *within_positions.begin();
}
if (!outside_positions.empty()) {
if (!within && !outside_positions.empty()) {
return *outside_positions.begin();
}
return {-1, -1};
Expand Down
3 changes: 3 additions & 0 deletions src/hades_extensions/tests/.clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,6 @@ Checks: "
-readability-magic-numbers,
"
WarningsAsErrors: "*"
CheckOptions:
- key: readability-identifier-length.IgnoredLoopCounterNames
value: "^[ijkxy_]$"
5 changes: 2 additions & 3 deletions src/hades_extensions/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@ add_executable(${TEST_MODULE}
${CMAKE_SOURCE_DIR}/tests/game_objects/systems/test_movements.cpp
${CMAKE_SOURCE_DIR}/tests/game_objects/systems/test_upgrade.cpp
${CMAKE_SOURCE_DIR}/tests/generation/test_bsp.cpp
${CMAKE_SOURCE_DIR}/tests/generation/t.cpp
#${CMAKE_SOURCE_DIR}/tests/generation/test_dijkstra.cpp
#${CMAKE_SOURCE_DIR}/tests/generation/test_map.cpp
${CMAKE_SOURCE_DIR}/tests/generation/test_map.cpp
${CMAKE_SOURCE_DIR}/tests/generation/test_primitives.cpp
${CMAKE_SOURCE_DIR}/tests/generation/test_searching.cpp
)
target_include_directories(${TEST_MODULE} PUBLIC ${CMAKE_SOURCE_DIR}/tests)
target_link_libraries(
Expand Down
60 changes: 20 additions & 40 deletions src/hades_extensions/tests/generation/test_bsp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,8 @@ TEST_F(BspFixture, TestBspSplitVertical) {
split(leaf, random_generator);

// Make sure the children are correct
const Rect left_container{{0, 0}, {7, 10}};
const Rect right_container{{9, 0}, {15, 10}};
ASSERT_EQ(*leaf.left->container, left_container);
ASSERT_EQ(*leaf.right->container, right_container);
ASSERT_EQ(*leaf.left->container, Rect({0, 0}, {7, 10}));
ASSERT_EQ(*leaf.right->container, Rect({9, 0}, {15, 10}));
}

/// Test that the split function correctly splits a leaf horizontally.
Expand All @@ -39,10 +37,8 @@ TEST_F(BspFixture, TestBspSplitHorizontal) {
split(leaf, random_generator);

// Make sure the children are correct
const Rect left_container{{0, 0}, {10, 7}};
const Rect right_container{{0, 9}, {10, 15}};
ASSERT_EQ(*leaf.left->container, left_container);
ASSERT_EQ(*leaf.right->container, right_container);
ASSERT_EQ(*leaf.left->container, Rect({0, 0}, {10, 7}));
ASSERT_EQ(*leaf.right->container, Rect({0, 9}, {10, 15}));
}

/// Test that the split function correctly splits a leaf in a random direction.
Expand All @@ -52,10 +48,8 @@ TEST_F(BspFixture, TestBspSplitRandom) {
split(leaf, random_generator);

// Make sure the children are correct
const Rect left_container{{0, 0}, {7, 15}};
const Rect right_container{{9, 0}, {15, 15}};
ASSERT_EQ(*leaf.left->container, left_container);
ASSERT_EQ(*leaf.right->container, right_container);
ASSERT_EQ(*leaf.left->container, Rect({0, 0}, {7, 15}));
ASSERT_EQ(*leaf.right->container, Rect({9, 0}, {15, 15}));
}

/// Test that the split function correctly splits a leaf multiple times.
Expand All @@ -65,18 +59,12 @@ TEST_F(BspFixture, TestBspSplitMultiple) {
split(leaf, random_generator);

// Make sure the children are correct
const Rect left_container{{0, 0}, {10, 20}};
const Rect left_left_container{{0, 0}, {10, 11}};
const Rect left_right_container{{0, 13}, {10, 20}};
const Rect right_container{{12, 0}, {20, 20}};
const Rect right_left_container{{12, 0}, {20, 10}};
const Rect right_right_container{{12, 12}, {20, 20}};
ASSERT_EQ(*leaf.left->container, left_container);
ASSERT_EQ(*leaf.left->left->container, left_left_container);
ASSERT_EQ(*leaf.left->right->container, left_right_container);
ASSERT_EQ(*leaf.right->container, right_container);
ASSERT_EQ(*leaf.right->left->container, right_left_container);
ASSERT_EQ(*leaf.right->right->container, right_right_container);
ASSERT_EQ(*leaf.left->container, Rect({0, 0}, {10, 20}));
ASSERT_EQ(*leaf.left->left->container, Rect({0, 0}, {10, 11}));
ASSERT_EQ(*leaf.left->right->container, Rect({0, 13}, {10, 20}));
ASSERT_EQ(*leaf.right->container, Rect({12, 0}, {20, 20}));
ASSERT_EQ(*leaf.right->left->container, Rect({12, 0}, {20, 10}));
ASSERT_EQ(*leaf.right->right->container, Rect({12, 12}, {20, 20}));
}

/// Test that the split function returns if the leaf is already split.
Expand All @@ -88,10 +76,8 @@ TEST_F(BspFixture, TestBspSplitExistingChildren) {
split(leaf, random_generator);

// Make sure the children haven't changed
const Rect left_container{{0, 0}, {0, 0}};
const Rect right_container{{0, 0}, {0, 0}};
ASSERT_EQ(*leaf.left->container, left_container);
ASSERT_EQ(*leaf.right->container, right_container);
ASSERT_EQ(*leaf.left->container, Rect({0, 0}, {0, 0}));
ASSERT_EQ(*leaf.right->container, Rect({0, 0}, {0, 0}));
}

/// Test that the split function overwrites the children if only one child exists.
Expand All @@ -102,10 +88,8 @@ TEST_F(BspFixture, TestBspSplitSingleChild) {
split(leaf, random_generator);

// Make sure the children are correct
const Rect left_container{{0, 0}, {7, 15}};
const Rect right_container{{9, 0}, {15, 15}};
ASSERT_EQ(*leaf.left->container, left_container);
ASSERT_EQ(*leaf.right->container, right_container);
ASSERT_EQ(*leaf.left->container, Rect({0, 0}, {7, 15}));
ASSERT_EQ(*leaf.right->container, Rect({9, 0}, {15, 15}));
}

/// Test that the split function returns if the leaf is too small to split.
Expand All @@ -124,8 +108,7 @@ TEST_F(BspFixture, TestBspCreateRoomSingleLeaf) {
create_room(leaf, grid, random_generator, rooms);

// Make sure the room is correct
const Rect room{{4, 4}, {13, 14}};
ASSERT_EQ(*leaf.room, room);
ASSERT_EQ(*leaf.room, Rect({4, 4}, {13, 14}));
ASSERT_EQ(rooms.size(), 1);
}

Expand All @@ -139,10 +122,8 @@ TEST_F(BspFixture, TestBspCreateRoomChildLeafs) {
create_room(leaf, grid, random_generator, rooms);

// Make sure the room is correct
const Rect left_room{{2, 0}, {6, 6}};
const Rect right_room{{9, 4}, {14, 10}};
ASSERT_EQ(*leaf.left->room, left_room);
ASSERT_EQ(*leaf.right->room, right_room);
ASSERT_EQ(*leaf.left->room, Rect({2, 0}, {6, 6}));
ASSERT_EQ(*leaf.right->room, Rect({9, 4}, {14, 10}));
ASSERT_EQ(rooms.size(), 2);
}

Expand All @@ -155,8 +136,7 @@ TEST_F(BspFixture, TestBspCreateRoomExistingRoom) {
create_room(leaf, grid, random_generator, rooms);

// Make sure the room is correct
const Rect room{{4, 4}, {13, 14}};
ASSERT_EQ(*leaf.room, room);
ASSERT_EQ(*leaf.room, Rect({4, 4}, {13, 14}));
ASSERT_EQ(rooms.size(), 1);
}

Expand Down
Loading

0 comments on commit 091b037

Please sign in to comment.