From f5daea0b18ee907e63352c54fedccc1efce5feb2 Mon Sep 17 00:00:00 2001 From: Peisong Xiao Date: Fri, 12 Jul 2024 17:10:16 -0400 Subject: [PATCH] unfinished work on random map gen --- src/map.cc | 174 ++++++++++++++++++++++++++++++++++++++++++------ src/map.h | 22 +++--- src/position.cc | 14 ++++ src/position.h | 4 +- src/rng.cc | 6 -- src/rng.h | 6 +- 6 files changed, 188 insertions(+), 38 deletions(-) diff --git a/src/map.cc b/src/map.cc index 12af10c..6d531f8 100644 --- a/src/map.cc +++ b/src/map.cc @@ -3,12 +3,12 @@ #include #include -game_map::game_map(RNG &rng, const feature enabled_features): +game_map::game_map(RNG *rng, const feature enabled_features): enabled_features{enabled_features} { map.reserve(MAP_HEIGHT * MAP_WIDTH); for (int i = MAP_HEIGHT * MAP_WIDTH; i > 0; --i) - map.push_back(-1); + map.push_back(' '); // Note: during generation, walls DO NOT count as being in the rooms std::vector> room_dims = gen_room_dims(rng); @@ -17,14 +17,41 @@ game_map::game_map(RNG &rng, const feature enabled_features): std::vector> room_data = distr_rooms(rng, room_dims); + for (size_t r = 0; r < room_data.size(); ++r) { + for (int x = 0; x < room_data[r].first.x; ++x) + for (int y = 0; y < room_data[r].first.y; ++y) + map[remap_position({room_data[r].second.x + x, + room_data[r].second.y + y})] = r; + + for (int x = 0; x < room_data[r].first.x; ++x) { + map[remap_position({room_data[r].second.x + x, + room_data[r].second.y - 1})] = '-'; + map[remap_position({room_data[r].second.x + x, + room_data[r].second.y + + room_data[r].first.y + 1})] = '-'; + } + + for (int y = -1; y <= room_data[r].first.y; ++y) { + map[remap_position({room_data[r].second.x - 1, + room_data[r].second.y + y})] = '|'; + map[remap_position({room_data[r].second.x + + room_data[r].first.x + 1, + room_data[r].second.y + y})] = '|'; + } + } + + map.shrink_to_fit(); } -std::vector> game_map::distr_rooms(RNG &rng, +std::vector> game_map::distr_rooms(RNG *rng, std::vector> &room_dims) { - std::vector> result{room_dims.size()}; + std::vector> result; + result.reserve(room_dims.size()); int max_layer = room_dims[room_dims.size() - 1].second; - std::vector layer_heights{max_layer + 1}; + // left, right, height + std::vector> layer_data; + layer_data.reserve(max_layer + 1); // distributing rooms horizontally for (int layer = 0; layer <= max_layer; ++layer) { @@ -42,31 +69,128 @@ std::vector> &room_dims) { room_dims[i].first.y); } - layer_heights.push_back(layer_height); + layer_data.push_back({{l, r}, layer_height}); // distribute the current layer if (l == r) { - result.push_back({room_dims[l].first, - {rng.rand_under(ACTUAL_MAP_WIDTH - room_dims[l].first.x + 1), 0}}); + result.push_back({{ + 0, rng->rand_under(ACTUAL_MAP_WIDTH - + room_dims[l].first.x + 1) + }, + room_dims[l].first}); continue; } - int left = room_dims[l].first.x; + int left = 0; int right = ACTUAL_MAP_WIDTH; // every time, distribute the last one first - for (int i = l + 1; i < r; ++i) + for (int i = l; i < r; ++i) left += MIN_ROOM_SPACING + room_dims[i].first.x; - for (int i = r; i > l; --i) { + for (int i = r; i >= l; --i) { + int offset = rng->rand_between(left, right - room_dims[i].first.x + 1); + result.push_back({{0, offset}, room_dims[i].first}); + + right = offset - MIN_ROOM_SPACING; + + if (i != l) + left -= MIN_ROOM_SPACING + room_dims[i - 1].first.x; } } + // distributing rooms vertically + int top = 0; + int bottom = ACTUAL_MAP_HEIGHT; + + for (int i = 0; i < max_layer; ++i) + top += MIN_ROOM_SPACING + layer_data[i].second; + + for (int i = max_layer; i >= 0; --i) { + int offset = rng->rand_between(top, bottom - layer_data[i].second + 1); + + for (int j = layer_data[i].first.x; j <= layer_data[i].first.y; ++j) + result[j].second.y = offset; + + bottom = offset - MIN_ROOM_SPACING; + + if (i != 0) + top -= MIN_ROOM_SPACING + layer_data[i - 1].second; + } + + // jitter + //jitter(rng, result); + + //add padding + for (auto room : result) + room.first += {MAP_PADDING, MAP_PADDING}; + return result; } +void game_map::jitter(RNG *rng, + std::vector> &rooms) { + for (auto target = rooms.rbegin(); target != rooms.rend(); ++target) { + int t = -INF; + int b = INF; + int l = -INF; + int r = INF; + + for (auto i : rooms) + if (i != *target) { + if (overlap_x(*target, i)) { + if (target->second.y > i.second.y) + t = std::max(t, + i.second.y + i.first.y + + MIN_ROOM_SPACING); + else + b = std::min(b, + i.second.y + - MIN_ROOM_SPACING); + } + + if (overlap_y(*target, i)) { + if (target->second.x > i.second.x) + l = std::max(l, + i.second.x + i.first.x + + MIN_ROOM_SPACING); + else + r = std::min(r, + i.second.x + - MIN_ROOM_SPACING); + } + } + + target->second.x = rng->rand_between(l, r - target->first.x + 1); + target->second.y = rng->rand_between(t, b - target->first.y + 1); + } +} + +bool game_map::overlap_x(std::pair &room1, + std::pair &room2) { + return (room1.second.x >= room2.second.x && + room1.second.x - 1 <= room2.second.x + room2.first.x + 1) || + (room2.second.x >= room1.second.x && + room2.second.x - 1 <= room1.second.x + room1.first.x + 1); +} + +bool game_map::overlap_y(std::pair &room1, + std::pair &room2) { + return (room1.second.y >= room2.second.y && + room1.second.y - 1 <= room2.second.y + room2.first.y + 1) || + (room2.second.y >= room1.second.y && + room2.second.y - 1 <= room1.second.y + room1.first.y + 1); +} + +position game_map::random_size(int min_width, int min_height, + int max_width, int max_height, + RNG *rng) { + return {rng->rand_between(min_width, max_width + 1), + rng->rand_between(min_height, max_height + 1)}; +} + game_map::game_map(const std::string &map_data, - RNG &rng, const feature enabled_features): + RNG *rng, const feature enabled_features): enabled_features{enabled_features} { int map_size = MAP_HEIGHT * MAP_WIDTH; map.reserve(map_size); @@ -82,12 +206,13 @@ game_map::game_map(const std::string &map_data, empty_spots.push_back(remap_index(i)); } - down_stairs = rng.get_rand_in_vector(empty_spots); + down_stairs = rng->get_rand_in_vector(empty_spots); if (enabled_features | FEATURE_REVISIT) { - up_stairs = rng.get_rand_in_vector( - remove_from_list(empty_spots, {down_stairs})); + auto tmp = remove_from_list(empty_spots, down_stairs); + up_stairs = rng->get_rand_in_vector(tmp); + map[remap_position(up_stairs)] = '<'; map[remap_position(down_stairs)] = '>'; } else { @@ -147,9 +272,11 @@ const std::vectorgame_map::get_room_list() const { return result; } -std::vector> game_map::gen_room_dims(RNG &rng) { - position_list room_dim_list{MAX_ROOM_CNT}; - std::vector> result{MAX_ROOM_CNT}; +std::vector> game_map::gen_room_dims(RNG *rng) { + position_list room_dim_list; + room_dim_list.reserve(MAX_ROOM_CNT); + std::vector> result; + result.reserve(MAX_ROOM_CNT); for (int i = 0; i < MAX_ROOM_CNT; ++i) room_dim_list.push_back(random_size(MIN_ROOM_WIDTH, MIN_ROOM_HEIGHT, @@ -171,6 +298,7 @@ std::vector> game_map::gen_room_dims(RNG &rng) { curr_left + MIN_ROOM_SPACING + room_dim_list[i].x + WIDTH_RESERVED <= ACTUAL_MAP_WIDTH) { result.push_back({room_dim_list[i], curr_layer_cnt}); + curr_left += MIN_ROOM_SPACING + room_dim_list[i].x; continue; } @@ -188,8 +316,10 @@ std::vector> game_map::gen_room_dims(RNG &rng) { if (curr_top + MIN_ROOM_SPACING + room_dim_list[i].y + HEIGHT_RESERVED <= ACTUAL_MAP_HEIGHT && curr_left + MIN_ROOM_SPACING + - room_dim_list[i].x + WIDTH_RESERVED <= ACTUAL_MAP_WIDTH) + room_dim_list[i].x + WIDTH_RESERVED <= ACTUAL_MAP_WIDTH) { result.push_back({room_dim_list[i], curr_layer_cnt}); + curr_left += MIN_ROOM_SPACING + room_dim_list[i].x; + } } result.shrink_to_fit(); @@ -199,7 +329,7 @@ std::vector> game_map::gen_room_dims(RNG &rng) { position random_size(int min_width, int min_height, int max_width, int max_height, - RNG &rng) { - return {rng.rand_between(min_width, max_width + 1), - rng.rand_between(min_height, max_height + 1)}; + RNG *rng) { + return {rng->rand_between(min_width, max_width + 1), + rng->rand_between(min_height, max_height + 1)}; } diff --git a/src/map.h b/src/map.h index 101de03..a349833 100644 --- a/src/map.h +++ b/src/map.h @@ -14,12 +14,12 @@ private: static const int MIN_ROOM_WIDTH = 3; static const int MIN_ROOM_HEIGHT = 3; static const int MAX_ROOM_WIDTH = 20; - static const int MAX_ROOM_HEIGHT = 13; + static const int MAX_ROOM_HEIGHT = 5; // setup safezones static const int ACTUAL_MAP_WIDTH = MAP_WIDTH - 4; static const int ACTUAL_MAP_HEIGHT = MAP_HEIGHT - 4; - static const int MAP_PADDING = 1; - static const int MIN_ROOM_SPACING = 4; + static const int MAP_PADDING = 2; + static const int MIN_ROOM_SPACING = 3; static const int WIDTH_RESERVED = 8; static const int HEIGHT_RESERVED = 4; @@ -32,9 +32,9 @@ private: int room_cnt; public: // randomly generate a map - game_map(RNG &rng, const feature enabled_features); + game_map(RNG *rng, const feature enabled_features); // read map from a string - game_map(const std::string &map_data, RNG &rng, + game_map(const std::string &map_data, RNG *rng, const feature enabled_features); const position_list get_available_positions() const; @@ -60,12 +60,18 @@ private: position random_size(int min_width, int min_height, int max_width, int max_height, - RNG &rng); + RNG *rng); - std::vector> gen_room_dims(RNG &rng); - std::vector> distr_rooms(RNG &rng, + std::vector> gen_room_dims(RNG *rng); + std::vector> distr_rooms(RNG *rng, std::vector> &room_dims); + + bool overlap_x(std::pair &room1, + std::pair &room2); + bool overlap_y(std::pair &room1, + std::pair &room2); + void jitter(RNG *rng, std::vector> &rooms); }; const std::string default_map = diff --git a/src/position.cc b/src/position.cc index 478b57d..b30636d 100644 --- a/src/position.cc +++ b/src/position.cc @@ -64,3 +64,17 @@ std::vector remove_from_list(const std::vector return result; } + +std::vector remove_from_list(const std::vector + &sorted_positions, + position &excluded) { + + std::vector result{sorted_positions.size() - 1}; + + for (auto src : sorted_positions) { + if (src != excluded) + result.push_back(src); + } + + return result; +} diff --git a/src/position.h b/src/position.h index 214b8f9..b7a6d55 100644 --- a/src/position.h +++ b/src/position.h @@ -24,5 +24,7 @@ std::size_t find(const std::vector &sorted_list, std::vector remove_from_list(const std::vector &sorted_positions, std::vector excluded); - +std::vector remove_from_list(const std::vector + &sorted_positions, + position &excluded); #endif diff --git a/src/rng.cc b/src/rng.cc index 2cd54bb..54aafa1 100644 --- a/src/rng.cc +++ b/src/rng.cc @@ -35,9 +35,3 @@ int RNG::get_curr_rand_num() const { bool RNG::trial(fraction &psuccess) { return (rand() % psuccess.denominator) < psuccess.numerator; } - -template T &RNG::get_rand_in_vector(const std::vector &vec) { - curr_rand_num = rand(); - - return vec[curr_rand_num % vec.size()]; -} diff --git a/src/rng.h b/src/rng.h index 037d6bb..896b8a7 100644 --- a/src/rng.h +++ b/src/rng.h @@ -28,7 +28,11 @@ public: bool trial(fraction &psuccess); - template T &get_rand_in_vector(const std::vector &vec); + template T &get_rand_in_vector(std::vector &vec) { + curr_rand_num = rand(); + + return vec[curr_rand_num % vec.size()]; + } }; #endif