unfinished work on random map gen
This commit is contained in:
174
src/map.cc
174
src/map.cc
@ -3,12 +3,12 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
game_map::game_map(RNG &rng, const feature enabled_features):
|
game_map::game_map(RNG *rng, const feature enabled_features):
|
||||||
enabled_features{enabled_features} {
|
enabled_features{enabled_features} {
|
||||||
map.reserve(MAP_HEIGHT * MAP_WIDTH);
|
map.reserve(MAP_HEIGHT * MAP_WIDTH);
|
||||||
|
|
||||||
for (int i = MAP_HEIGHT * MAP_WIDTH; i > 0; --i)
|
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
|
// Note: during generation, walls DO NOT count as being in the rooms
|
||||||
std::vector<std::pair<position, int>> room_dims = gen_room_dims(rng);
|
std::vector<std::pair<position, int>> room_dims = gen_room_dims(rng);
|
||||||
@ -17,14 +17,41 @@ game_map::game_map(RNG &rng, const feature enabled_features):
|
|||||||
std::vector<std::pair<position, position>> room_data = distr_rooms(rng,
|
std::vector<std::pair<position, position>> room_data = distr_rooms(rng,
|
||||||
room_dims);
|
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<std::pair<position, position>> game_map::distr_rooms(RNG &rng,
|
std::vector<std::pair<position, position>> game_map::distr_rooms(RNG *rng,
|
||||||
std::vector<std::pair<position, int>> &room_dims) {
|
std::vector<std::pair<position, int>> &room_dims) {
|
||||||
std::vector<std::pair<position, position>> result{room_dims.size()};
|
std::vector<std::pair<position, position>> result;
|
||||||
|
result.reserve(room_dims.size());
|
||||||
|
|
||||||
int max_layer = room_dims[room_dims.size() - 1].second;
|
int max_layer = room_dims[room_dims.size() - 1].second;
|
||||||
std::vector<int> layer_heights{max_layer + 1};
|
// left, right, height
|
||||||
|
std::vector<std::pair<position, int>> layer_data;
|
||||||
|
layer_data.reserve(max_layer + 1);
|
||||||
|
|
||||||
// distributing rooms horizontally
|
// distributing rooms horizontally
|
||||||
for (int layer = 0; layer <= max_layer; ++layer) {
|
for (int layer = 0; layer <= max_layer; ++layer) {
|
||||||
@ -42,31 +69,128 @@ std::vector<std::pair<position, int>> &room_dims) {
|
|||||||
room_dims[i].first.y);
|
room_dims[i].first.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
layer_heights.push_back(layer_height);
|
layer_data.push_back({{l, r}, layer_height});
|
||||||
|
|
||||||
// distribute the current layer
|
// distribute the current layer
|
||||||
if (l == r) {
|
if (l == r) {
|
||||||
result.push_back({room_dims[l].first,
|
result.push_back({{
|
||||||
{rng.rand_under(ACTUAL_MAP_WIDTH - room_dims[l].first.x + 1), 0}});
|
0, rng->rand_under(ACTUAL_MAP_WIDTH -
|
||||||
|
room_dims[l].first.x + 1)
|
||||||
|
},
|
||||||
|
room_dims[l].first});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int left = room_dims[l].first.x;
|
int left = 0;
|
||||||
int right = ACTUAL_MAP_WIDTH;
|
int right = ACTUAL_MAP_WIDTH;
|
||||||
|
|
||||||
// every time, distribute the last one first
|
// 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;
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void game_map::jitter(RNG *rng,
|
||||||
|
std::vector<std::pair<position, position>> &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<position, position> &room1,
|
||||||
|
std::pair<position, position> &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<position, position> &room1,
|
||||||
|
std::pair<position, position> &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,
|
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} {
|
enabled_features{enabled_features} {
|
||||||
int map_size = MAP_HEIGHT * MAP_WIDTH;
|
int map_size = MAP_HEIGHT * MAP_WIDTH;
|
||||||
map.reserve(map_size);
|
map.reserve(map_size);
|
||||||
@ -82,12 +206,13 @@ game_map::game_map(const std::string &map_data,
|
|||||||
empty_spots.push_back(remap_index(i));
|
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) {
|
if (enabled_features | FEATURE_REVISIT) {
|
||||||
up_stairs = rng.get_rand_in_vector(
|
auto tmp = remove_from_list(empty_spots, down_stairs);
|
||||||
remove_from_list(empty_spots, {down_stairs}));
|
up_stairs = rng->get_rand_in_vector(tmp);
|
||||||
|
|
||||||
map[remap_position(up_stairs)] = '<';
|
map[remap_position(up_stairs)] = '<';
|
||||||
map[remap_position(down_stairs)] = '>';
|
map[remap_position(down_stairs)] = '>';
|
||||||
} else {
|
} else {
|
||||||
@ -147,9 +272,11 @@ const std::vector<position_list>game_map::get_room_list() const {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::pair<position, int>> game_map::gen_room_dims(RNG &rng) {
|
std::vector<std::pair<position, int>> game_map::gen_room_dims(RNG *rng) {
|
||||||
position_list room_dim_list{MAX_ROOM_CNT};
|
position_list room_dim_list;
|
||||||
std::vector<std::pair<position, int>> result{MAX_ROOM_CNT};
|
room_dim_list.reserve(MAX_ROOM_CNT);
|
||||||
|
std::vector<std::pair<position, int>> result;
|
||||||
|
result.reserve(MAX_ROOM_CNT);
|
||||||
|
|
||||||
for (int i = 0; i < MAX_ROOM_CNT; ++i)
|
for (int i = 0; i < MAX_ROOM_CNT; ++i)
|
||||||
room_dim_list.push_back(random_size(MIN_ROOM_WIDTH, MIN_ROOM_HEIGHT,
|
room_dim_list.push_back(random_size(MIN_ROOM_WIDTH, MIN_ROOM_HEIGHT,
|
||||||
@ -171,6 +298,7 @@ std::vector<std::pair<position, int>> game_map::gen_room_dims(RNG &rng) {
|
|||||||
curr_left + MIN_ROOM_SPACING +
|
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});
|
result.push_back({room_dim_list[i], curr_layer_cnt});
|
||||||
|
curr_left += MIN_ROOM_SPACING + room_dim_list[i].x;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,8 +316,10 @@ std::vector<std::pair<position, int>> game_map::gen_room_dims(RNG &rng) {
|
|||||||
if (curr_top + MIN_ROOM_SPACING +
|
if (curr_top + MIN_ROOM_SPACING +
|
||||||
room_dim_list[i].y + HEIGHT_RESERVED <= ACTUAL_MAP_HEIGHT &&
|
room_dim_list[i].y + HEIGHT_RESERVED <= ACTUAL_MAP_HEIGHT &&
|
||||||
curr_left + MIN_ROOM_SPACING +
|
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});
|
result.push_back({room_dim_list[i], curr_layer_cnt});
|
||||||
|
curr_left += MIN_ROOM_SPACING + room_dim_list[i].x;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result.shrink_to_fit();
|
result.shrink_to_fit();
|
||||||
@ -199,7 +329,7 @@ std::vector<std::pair<position, int>> game_map::gen_room_dims(RNG &rng) {
|
|||||||
|
|
||||||
position random_size(int min_width, int min_height,
|
position random_size(int min_width, int min_height,
|
||||||
int max_width, int max_height,
|
int max_width, int max_height,
|
||||||
RNG &rng) {
|
RNG *rng) {
|
||||||
return {rng.rand_between(min_width, max_width + 1),
|
return {rng->rand_between(min_width, max_width + 1),
|
||||||
rng.rand_between(min_height, max_height + 1)};
|
rng->rand_between(min_height, max_height + 1)};
|
||||||
}
|
}
|
||||||
|
22
src/map.h
22
src/map.h
@ -14,12 +14,12 @@ private:
|
|||||||
static const int MIN_ROOM_WIDTH = 3;
|
static const int MIN_ROOM_WIDTH = 3;
|
||||||
static const int MIN_ROOM_HEIGHT = 3;
|
static const int MIN_ROOM_HEIGHT = 3;
|
||||||
static const int MAX_ROOM_WIDTH = 20;
|
static const int MAX_ROOM_WIDTH = 20;
|
||||||
static const int MAX_ROOM_HEIGHT = 13;
|
static const int MAX_ROOM_HEIGHT = 5;
|
||||||
// setup safezones
|
// setup safezones
|
||||||
static const int ACTUAL_MAP_WIDTH = MAP_WIDTH - 4;
|
static const int ACTUAL_MAP_WIDTH = MAP_WIDTH - 4;
|
||||||
static const int ACTUAL_MAP_HEIGHT = MAP_HEIGHT - 4;
|
static const int ACTUAL_MAP_HEIGHT = MAP_HEIGHT - 4;
|
||||||
static const int MAP_PADDING = 1;
|
static const int MAP_PADDING = 2;
|
||||||
static const int MIN_ROOM_SPACING = 4;
|
static const int MIN_ROOM_SPACING = 3;
|
||||||
static const int WIDTH_RESERVED = 8;
|
static const int WIDTH_RESERVED = 8;
|
||||||
static const int HEIGHT_RESERVED = 4;
|
static const int HEIGHT_RESERVED = 4;
|
||||||
|
|
||||||
@ -32,9 +32,9 @@ private:
|
|||||||
int room_cnt;
|
int room_cnt;
|
||||||
public:
|
public:
|
||||||
// randomly generate a map
|
// 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
|
// 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 feature enabled_features);
|
||||||
|
|
||||||
const position_list get_available_positions() const;
|
const position_list get_available_positions() const;
|
||||||
@ -60,12 +60,18 @@ private:
|
|||||||
|
|
||||||
position random_size(int min_width, int min_height,
|
position random_size(int min_width, int min_height,
|
||||||
int max_width, int max_height,
|
int max_width, int max_height,
|
||||||
RNG &rng);
|
RNG *rng);
|
||||||
|
|
||||||
std::vector<std::pair<position, int>> gen_room_dims(RNG &rng);
|
std::vector<std::pair<position, int>> gen_room_dims(RNG *rng);
|
||||||
std::vector<std::pair<position, position>> distr_rooms(RNG &rng,
|
std::vector<std::pair<position, position>> distr_rooms(RNG *rng,
|
||||||
std::vector<std::pair<position, int>>
|
std::vector<std::pair<position, int>>
|
||||||
&room_dims);
|
&room_dims);
|
||||||
|
|
||||||
|
bool overlap_x(std::pair<position, position> &room1,
|
||||||
|
std::pair<position, position> &room2);
|
||||||
|
bool overlap_y(std::pair<position, position> &room1,
|
||||||
|
std::pair<position, position> &room2);
|
||||||
|
void jitter(RNG *rng, std::vector<std::pair<position, position>> &rooms);
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::string default_map =
|
const std::string default_map =
|
||||||
|
@ -64,3 +64,17 @@ std::vector<position> remove_from_list(const std::vector<position>
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<position> remove_from_list(const std::vector<position>
|
||||||
|
&sorted_positions,
|
||||||
|
position &excluded) {
|
||||||
|
|
||||||
|
std::vector<position> result{sorted_positions.size() - 1};
|
||||||
|
|
||||||
|
for (auto src : sorted_positions) {
|
||||||
|
if (src != excluded)
|
||||||
|
result.push_back(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
@ -24,5 +24,7 @@ std::size_t find(const std::vector<position> &sorted_list,
|
|||||||
std::vector<position> remove_from_list(const std::vector<position>
|
std::vector<position> remove_from_list(const std::vector<position>
|
||||||
&sorted_positions,
|
&sorted_positions,
|
||||||
std::vector<position> excluded);
|
std::vector<position> excluded);
|
||||||
|
std::vector<position> remove_from_list(const std::vector<position>
|
||||||
|
&sorted_positions,
|
||||||
|
position &excluded);
|
||||||
#endif
|
#endif
|
||||||
|
@ -35,9 +35,3 @@ int RNG::get_curr_rand_num() const {
|
|||||||
bool RNG::trial(fraction &psuccess) {
|
bool RNG::trial(fraction &psuccess) {
|
||||||
return (rand() % psuccess.denominator) < psuccess.numerator;
|
return (rand() % psuccess.denominator) < psuccess.numerator;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T> T &RNG::get_rand_in_vector(const std::vector<T> &vec) {
|
|
||||||
curr_rand_num = rand();
|
|
||||||
|
|
||||||
return vec[curr_rand_num % vec.size()];
|
|
||||||
}
|
|
||||||
|
@ -28,7 +28,11 @@ public:
|
|||||||
|
|
||||||
bool trial(fraction &psuccess);
|
bool trial(fraction &psuccess);
|
||||||
|
|
||||||
template<class T> T &get_rand_in_vector(const std::vector<T> &vec);
|
template<class T> T &get_rand_in_vector(std::vector<T> &vec) {
|
||||||
|
curr_rand_num = rand();
|
||||||
|
|
||||||
|
return vec[curr_rand_num % vec.size()];
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user