-
Печенин Данила Михайлович authoredd55b9527
#include <States/GameState/GameBuilder/GameBuilder.h>
#include <random>
#include <queue>
void CommonBuilder::create_context(const float dynamic_objets_ratio) {
std::mt19937 gen(std::random_device{}());
std::vector<std::vector<std::unique_ptr<Room>>::iterator> buf_rooms;
for (auto& row : m_rooms) {
for (auto room = row.begin(); room != row.end(); ++room) {
if (*room == nullptr) continue;
buf_rooms.push_back(room);
}
}
if (buf_rooms.empty()) return;
std::uniform_int_distribution distrib(0 , static_cast<int>(buf_rooms.size()-1));
auto pos = buf_rooms.begin() + distrib(gen);
const sf::Vector2f pacman_pos = (*pos)->get()->get_position();
m_context.pacman.set_initial_location((*pos)->get());
buf_rooms.erase(pos);
if (dynamic_objets_ratio > 1) throw std::invalid_argument("GAME_ENEMY_RATIO should be <= 1");
const auto number_of_dynamic_entities = static_cast<size_t>(static_cast<float>(buf_rooms.size()) * dynamic_objets_ratio);
for (size_t i = 0; i < number_of_dynamic_entities; ++i) {
distrib.param(std::uniform_int_distribution<>::param_type(0, static_cast<int>(buf_rooms.size()) - 1));
pos = buf_rooms.begin() + distrib(gen);
if (float pos_x = (*pos)->get()->get_position().x, pos_y = (*pos)->get()->get_position().y;
std::sqrt((pos_x-pacman_pos.x) * (pos_x-pacman_pos.x) + (pos_y-pacman_pos.y) * (pos_y-pacman_pos.y)) <= m_room_size * 2) {
m_context.static_objects.emplace_back(std::move(std::make_unique<Food>()));
m_context.static_objects.back()->set_initial_location((*pos)->get());
}
else {
m_context.dynamic_objects.emplace_back(std::move(std::make_unique<Enemy>()));
m_context.dynamic_objects.back()->set_initial_location((*pos)->get());
}
buf_rooms.erase(pos);
}
for (const auto& it_room : buf_rooms) {
m_context.static_objects.emplace_back(std::move(std::make_unique<Food>()));
m_context.static_objects.back()->set_initial_location(it_room->get());
}
}
void CommonBuilder::create_state(IStateManager& state_manager, const sf::VideoMode& mode, const std::string& window_title) {
m_game_state = std::make_unique<GameState>(state_manager, mode, window_title);
}
void CommonBuilder::set_all_to_state() {
std::vector<std::unique_ptr<Room>> rooms;
for (auto& row : m_rooms) {
for (auto& room : row) {
if (room == nullptr) continue;
rooms.emplace_back(std::move(room));
}
}
m_game_state->set_maze(Maze(std::move(rooms)));
m_game_state->set_context(std::move(m_context));
}
void SimpleBuilder::create_rooms() {
const auto number_of_rooms_in_row = static_cast<size_t>(m_width / m_room_size),
number_of_rooms_in_col = static_cast<size_t>(m_height / m_room_size);
const sf::Vector2f gap(
(m_width - static_cast<float>(number_of_rooms_in_row) * m_room_size + m_room_size) / 2.f,
(m_height - static_cast<float>(number_of_rooms_in_col) * m_room_size + m_room_size) / 2.f
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
);
for (size_t i = 0; i < number_of_rooms_in_col; ++i) {
std::vector<std::unique_ptr<Room>> room_row;
room_row.reserve(number_of_rooms_in_row);
for (size_t j = 0; j < number_of_rooms_in_row; ++j) {
auto tmp_room = std::make_unique<Room>(m_room_size);
tmp_room->set_color(m_room_color);
tmp_room->set_position(gap + sf::Vector2f{ m_room_size * static_cast<float>(j), m_room_size * static_cast<float>(i) });
room_row.emplace_back(std::move(tmp_room));
}
m_rooms.emplace_back(std::move(room_row));
}
}
void SimpleBuilder::set_rooms_sides() {
if (m_rooms.empty()) return;
if (m_rooms[0].empty()) return;
for (const auto & room : m_rooms[0])
room->set_side(Room::UP, std::make_shared<Wall>(*room));
m_rooms[0][0]->set_side(Room::LEFT, std::make_shared<Wall>(*m_rooms[0][0]));
for (size_t i = 1; i < m_rooms[0].size() - 1; ++i) {
auto tmp_side_ptr = std::make_shared<Pass>(*m_rooms[0][i], *m_rooms[0][i-1]);
m_rooms[0][i]->set_side(Room::LEFT, tmp_side_ptr);
m_rooms[0][i-1]->set_side(Room::RIGHT, tmp_side_ptr);
}
auto tmp_side_ptr = std::make_shared<Pass>(*m_rooms[0][m_rooms[0].size()-1], *m_rooms[0][m_rooms[0].size()-2]);
m_rooms[0][m_rooms[0].size()-1]->set_side(Room::LEFT, tmp_side_ptr);
m_rooms[0][m_rooms[0].size()-2]->set_side(Room::RIGHT, tmp_side_ptr);
m_rooms[0][m_rooms[0].size()-1]->set_side(Room::RIGHT, std::make_shared<Wall>(*m_rooms[0][m_rooms[0].size()-1]));
for (size_t i = 1; i < m_rooms.size(); ++i) {
m_rooms[i][0]->set_side(Room::LEFT, std::make_shared<Wall>(*m_rooms[i][0]));
tmp_side_ptr = std::make_shared<Pass>(*m_rooms[i][0], *m_rooms[i-1][0]);
m_rooms[i][0]->set_side(Room::UP, tmp_side_ptr);
m_rooms[i-1][0]->set_side(Room::DOWN, tmp_side_ptr);
for (size_t j = 1; j < m_rooms[i].size(); ++j) {
tmp_side_ptr = std::make_shared<Pass>(*m_rooms[i][j], *m_rooms[i-1][j]);
m_rooms[i][j]->set_side(Room::UP, tmp_side_ptr);
m_rooms[i-1][j]->set_side(Room::DOWN, tmp_side_ptr);
tmp_side_ptr = std::make_shared<Pass>(*m_rooms[i][j], *m_rooms[i][j-1]);
m_rooms[i][j]->set_side(Room::LEFT, tmp_side_ptr);
m_rooms[i][j-1]->set_side(Room::RIGHT, tmp_side_ptr);
}
m_rooms[i][m_rooms[i].size()-1]->set_side(Room::RIGHT, std::make_shared<Wall>(*m_rooms[i][m_rooms[i].size()-1]));
}
for (const auto & room : m_rooms[m_rooms.size()-1]) {
room->set_side(Room::DOWN, std::make_shared<Wall>(*room));
}
}
void ComplexBuilder::create_rooms() {
const auto number_of_rooms_in_row = static_cast<size_t>(m_width / m_room_size),
number_of_rooms_in_col = static_cast<size_t>(m_height / m_room_size);
const sf::Vector2f gap(
(m_width - static_cast<float>(number_of_rooms_in_row) * m_room_size + m_room_size) / 2.f,
(m_height - static_cast<float>(number_of_rooms_in_col) * m_room_size + m_room_size) / 2.f
);
for (size_t i = 0; i < number_of_rooms_in_col; ++i) {
std::vector<std::unique_ptr<Room>> room_row;
room_row.reserve(number_of_rooms_in_row);
for (size_t j = 0; j < number_of_rooms_in_row; ++j) {
if (i % 2 == 0 && j % 2 == 0) continue;
auto tmp_room = std::make_unique<Room>(m_room_size);
tmp_room->set_color(m_room_color);
tmp_room->set_position(gap + sf::Vector2f{ m_room_size * static_cast<float>(j), m_room_size * static_cast<float>(i) });
room_row.emplace_back(std::move(tmp_room));
}
m_rooms.emplace_back(std::move(room_row));
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
}
}
void ComplexBuilder::set_rooms_sides() {
if (m_rooms.empty()) return;
if (m_rooms[0].empty()) return;
for (size_t i = 0; i < m_rooms.size(); i+=2) {
for (const auto & room : m_rooms[i]) {
room->set_side(Room::LEFT, std::make_shared<Wall>(*room));
room->set_side(Room::RIGHT, std::make_shared<Wall>(*room));
}
}
for (const auto & room : m_rooms[0])
room->set_side(Room::UP, std::make_shared<Wall>(*room));
for (size_t i = 1; i < m_rooms.size() - 1; i+=2) {
m_rooms[i][0]->set_side(Room::LEFT, std::make_shared<Wall>(*m_rooms[i][0]));
m_rooms[i][0]->set_side(Room::UP, std::make_shared<Wall>(*m_rooms[i][0]));
m_rooms[i][0]->set_side(Room::DOWN, std::make_shared<Wall>(*m_rooms[i][0]));
for (size_t j = 1; j < m_rooms[i].size() - 1; ++j) {
if (j % 2 == 0) {
m_rooms[i][j]->set_side(Room::UP, std::make_shared<Wall>(*m_rooms[i][j]));
m_rooms[i][j]->set_side(Room::DOWN, std::make_shared<Wall>(*m_rooms[i][j]));
continue;
}
auto side_ptr_temp = std::make_shared<Pass>(*m_rooms[i][j], *m_rooms[i-1][j-j/2-1]);
m_rooms[i][j]->set_side(Room::UP, side_ptr_temp);
m_rooms[i-1][j-j/2-1]->set_side(Room::DOWN, side_ptr_temp);
side_ptr_temp = std::make_shared<Pass>(*m_rooms[i][j], *m_rooms[i][j-1]);
m_rooms[i][j]->set_side(Room::LEFT, side_ptr_temp);
m_rooms[i][j-1]->set_side(Room::RIGHT, side_ptr_temp);
side_ptr_temp = std::make_shared<Pass>(*m_rooms[i][j], *m_rooms[i][j+1]);
m_rooms[i][j]->set_side(Room::RIGHT, side_ptr_temp);
m_rooms[i][j+1]->set_side(Room::LEFT, side_ptr_temp);
side_ptr_temp = std::make_shared<Pass>(*m_rooms[i][j], *m_rooms[i+1][j-j/2-1]);
m_rooms[i][j]->set_side(Room::DOWN, side_ptr_temp);
m_rooms[i+1][j-j/2-1]->set_side(Room::UP, side_ptr_temp);
}
if (m_rooms[i].size() % 2 == 1) {
m_rooms[i][m_rooms[i].size()-1]->set_side(Room::UP, std::make_shared<Wall>(*m_rooms[i][m_rooms[i].size()-1]));
m_rooms[i][m_rooms[i].size()-1]->set_side(Room::DOWN, std::make_shared<Wall>(*m_rooms[i][m_rooms[i].size()-1]));
}
else {
auto side_ptr_temp = std::make_shared<Pass>(*m_rooms[i][m_rooms[i].size()-1], *m_rooms[i][m_rooms[i].size()-2]);
m_rooms[i][m_rooms[i].size()-1]->set_side(Room::LEFT, side_ptr_temp);
m_rooms[i][m_rooms[i].size()-2]->set_side(Room::RIGHT, side_ptr_temp);
side_ptr_temp = std::make_shared<Pass>(*m_rooms[i][m_rooms[i].size()-1], *m_rooms[i-1][m_rooms[i].size()-1]);
m_rooms[i][m_rooms[i].size()-1]->set_side(Room::UP, side_ptr_temp);
m_rooms[i-1][m_rooms[i].size()-1]->set_side(Room::DOWN, side_ptr_temp);
}
m_rooms[i][m_rooms[i].size()-1]->set_side(Room::RIGHT, std::make_shared<Wall>(*m_rooms[i][m_rooms[i].size()-1]));
}
for (auto& room : m_rooms[m_rooms.size()-1])
room->set_side(Room::DOWN, std::make_shared<Wall>(*room));
if (m_rooms.size() % 2 == 0) {
m_rooms[m_rooms.size()-1][0]->set_side(Room::UP, std::make_shared<Wall>(*m_rooms[m_rooms.size()-1][0]));
m_rooms[m_rooms.size()-1][0]->set_side(Room::LEFT, std::make_shared<Wall>(*m_rooms[m_rooms.size()-1][0]));
for (size_t i = 1; i < m_rooms[m_rooms.size()-1].size() - 1; ++i) {
if (i % 2 == 0) {
m_rooms[m_rooms.size()-1][i]->set_side(Room::UP, std::make_shared<Wall>(*m_rooms[m_rooms.size()-1][i]));
continue;
}
auto side_ptr_temp = std::make_shared<Pass>(*m_rooms[m_rooms.size()-1][i], *m_rooms[m_rooms.size()-2][i-i/2-1]);
m_rooms[m_rooms.size()-1][i]->set_side(Room::UP, side_ptr_temp);
m_rooms[m_rooms.size()-2][i-i/2-1]->set_side(Room::DOWN, side_ptr_temp);
side_ptr_temp = std::make_shared<Pass>(*m_rooms[m_rooms.size()-1][i-1], *m_rooms[m_rooms.size()-1][i]);
m_rooms[m_rooms.size()-1][i]->set_side(Room::LEFT, side_ptr_temp);
m_rooms[m_rooms.size()-1][i-1]->set_side(Room::RIGHT, side_ptr_temp);
side_ptr_temp = std::make_shared<Pass>(*m_rooms[m_rooms.size()-1][i+1], *m_rooms[m_rooms.size()-1][i]);
m_rooms[m_rooms.size()-1][i]->set_side(Room::RIGHT, side_ptr_temp);
m_rooms[m_rooms.size()-1][i+1]->set_side(Room::LEFT, side_ptr_temp);
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
}
if (m_rooms[m_rooms.size()-1].size() % 2 == 1) {
m_rooms[m_rooms.size()-1][m_rooms[m_rooms.size()-1].size()-1]->set_side(Room::UP, std::make_shared<Wall>(*m_rooms[m_rooms.size()-1][m_rooms[m_rooms.size()-1].size()-1]));
}
else {
auto side_ptr_temp = std::make_shared<Pass>(*m_rooms[m_rooms.size()-1][m_rooms[m_rooms.size()-1].size()-1], *m_rooms[m_rooms.size()-2][m_rooms[m_rooms.size()-1].size()-1]);
m_rooms[m_rooms.size()-1][m_rooms[m_rooms.size()-1].size()-1]->set_side(Room::UP, side_ptr_temp);
m_rooms[m_rooms.size()-2][m_rooms[m_rooms.size()-1].size()-1]->set_side(Room::DOWN, side_ptr_temp);
}
m_rooms[m_rooms.size()-1][m_rooms[m_rooms.size()-1].size()-1]->set_side(Room::RIGHT, std::make_shared<Wall>(*m_rooms[m_rooms.size()-1][m_rooms[m_rooms.size()-1].size()-1]));
}
}
ComplexRandomBuilder::ComplexRandomBuilder(const float width, const float height, const float room_size, const sf::Color room_color) :
CommonBuilder(width, height, room_size, room_color),
m_rooms_grid(static_cast<size_t>(height / m_room_size), std::vector(static_cast<size_t>(width / m_room_size), false)),
m_number_of_rooms_in_row(static_cast<size_t>(width / m_room_size)),
m_number_of_rooms_in_col(static_cast<size_t>(height / m_room_size)),
gen(rd()) {}
bool ComplexRandomBuilder::is_valid(const int x, const int y) const {
if (x >= m_number_of_rooms_in_row || y >= m_number_of_rooms_in_col || x < 0 || y < 0) return false;
return true;
}
void ComplexRandomBuilder::collapse_function() {
std::uniform_int_distribution<size_t> row_dist(0, m_number_of_rooms_in_row-1);
std::uniform_int_distribution<size_t> col_dist(0, m_number_of_rooms_in_col-1);
std::normal_distribution prob_dist(0.67f, 0.25f);
size_t start_x = row_dist(gen);
size_t start_y = col_dist(gen);
m_rooms_grid[start_y][start_x] = true;
size_t room_created = 1;
std::queue<std::pair<size_t, size_t>> cells_to_process;
cells_to_process.emplace(start_x, start_y);
while (!cells_to_process.empty()) {
const auto [x, y] = cells_to_process.front();
cells_to_process.pop();
std::vector<std::pair<int, int>> neighbors = {
{x - 1, y}, {x + 1, y}, {x, y - 1}, {x, y + 1}
};
std::shuffle(neighbors.begin(), neighbors.end(), gen);
bool neighbor_created = false;
for (const auto& [neighbor_x, neighbor_y] : neighbors) {
if (is_valid(neighbor_x, neighbor_y) && !m_rooms_grid[neighbor_y][neighbor_x]) {
if (room_created < 20 && !neighbor_created) {
m_rooms_grid[neighbor_y][neighbor_x] = true;
cells_to_process.emplace(neighbor_x, neighbor_y);
neighbor_created = true;
room_created++;
}
else if (prob_dist(gen) < 0.7f) {
m_rooms_grid[neighbor_y][neighbor_x] = true;
cells_to_process.emplace(neighbor_x, neighbor_y);
}
}
}
}
}
void ComplexRandomBuilder::create_rooms() {
collapse_function();
const sf::Vector2f gap(
(m_width - static_cast<float>(m_number_of_rooms_in_row) * m_room_size + m_room_size) / 2.f,
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
(m_height - static_cast<float>(m_number_of_rooms_in_col) * m_room_size + m_room_size) / 2.f
);
m_rooms.clear();
for (size_t i = 0; i < m_number_of_rooms_in_col; ++i) {
std::vector<std::unique_ptr<Room>> room_row;
for (size_t j = 0; j < m_number_of_rooms_in_row; ++j) {
if (m_rooms_grid[i][j]) {
auto tmp_room = std::make_unique<Room>(m_room_size);
tmp_room->set_color(m_room_color);
tmp_room->set_position(gap + sf::Vector2f{
m_room_size * static_cast<float>(j),
m_room_size * static_cast<float>(i)
});
room_row.push_back(std::move(tmp_room));
}
else room_row.push_back({});
}
m_rooms.emplace_back(std::move(room_row));
}
}
void ComplexRandomBuilder::set_rooms_sides() {
for (size_t i = 0; i < m_number_of_rooms_in_col; ++i) {
for (size_t j = 0; j < m_number_of_rooms_in_row; ++j) {
if (!m_rooms_grid[i][j]) continue;
if (static_cast<int>(j) - 1 >= 0 && m_rooms_grid[i][j-1]) {
auto side_ptr_temp = std::make_shared<Pass>(*m_rooms[i][j], *m_rooms[i][j-1]);
m_rooms[i][j]->set_side(Room::LEFT, side_ptr_temp);
m_rooms[i][j-1]->set_side(Room::RIGHT, side_ptr_temp);
}
else
m_rooms[i][j]->set_side(Room::LEFT, std::make_unique<Wall>(*m_rooms[i][j]));
if (static_cast<int>(j) + 1 < m_number_of_rooms_in_row && m_rooms_grid[i][j+1]) {}
else m_rooms[i][j]->set_side(Room::RIGHT, std::make_unique<Wall>(*m_rooms[i][j]));
if (static_cast<int>(i) - 1 >= 0 && m_rooms_grid[i-1][j]) {
auto side_ptr_temp = std::make_shared<Pass>(*m_rooms[i][j], *m_rooms[i-1][j]);
m_rooms[i][j]->set_side(Room::UP, side_ptr_temp);
m_rooms[i-1][j]->set_side(Room::DOWN, side_ptr_temp);
}
else
m_rooms[i][j]->set_side(Room::UP, std::make_unique<Wall>(*m_rooms[i][j]));
if (static_cast<int>(i) + 1 < m_number_of_rooms_in_col && m_rooms_grid[i+1][j]) {}
else m_rooms[i][j]->set_side(Room::DOWN, std::make_unique<Wall>(*m_rooms[i][j]));
}
}
}