#include "game.hpp" #include #include #include #include Game::Game( std::shared_ptr scene, std::shared_ptr cursor_controller, std::shared_ptr generation_tracker, std::shared_ptr status_manager, std::shared_ptr user_input_observer) noexcept : _scene(std::move(scene)), _cursor_controller(std::move(cursor_controller)), _generation_tracker(std::move(generation_tracker)), _status_manager(std::move(status_manager)), _user_input_observer(std::move(user_input_observer)), _gen_update_speed_millis(1000) { } void Game::on_start() noexcept { _status_manager->initialize(); _status_manager->set_section_title(StatusLineSection::A, ""); _status_manager->set_section_title(StatusLineSection::B, "X: "); _status_manager->set_section_title(StatusLineSection::C, "Y: "); _status_manager->set_section_title(StatusLineSection::D, "Paused: "); _status_manager->set_section_title(StatusLineSection::E, "Generation: "); _status_manager->set_section_title(StatusLineSection::F, "Time since last frame: "); const auto scene_size = _scene->size(); const auto center_position = Vector2( {.x = static_cast(scene_size.get_width()) / 2, .y = static_cast(scene_size.get_height()) / 2}); _cursor_controller->move_to(center_position); _status_manager->set_section_body( StatusLineSection::B, fmt::format("{}", center_position.get_x())); _status_manager->set_section_body( StatusLineSection::C, fmt::format("{}", center_position.get_y())); _status_manager->set_section_body( StatusLineSection::D, _generation_tracker->get_is_paused() ? "yes" : "no"); _status_manager->set_section_body(StatusLineSection::E, "0"); _status_manager->set_section_body(StatusLineSection::F, "0"); _last_update_time = std::chrono::system_clock::now(); } void Game::on_update() noexcept { const auto pressed_key = _user_input_observer->get_currently_pressed_key(); auto cursor_has_moved = false; switch (pressed_key) { case 'h': _move_cursor(Vector2::left()); cursor_has_moved = true; break; case 'j': _move_cursor(Vector2::down()); cursor_has_moved = true; break; case 'k': _move_cursor(Vector2::up()); cursor_has_moved = true; break; case 'l': _move_cursor(Vector2::right()); cursor_has_moved = true; break; case 'q': std::exit(EXIT_SUCCESS); case 'i': _insert_cell(_cursor_controller->where(), 'x'); break; case 'p': { auto onoff = !_generation_tracker->get_is_paused(); _generation_tracker->set_is_paused(onoff); _status_manager->set_section_body(StatusLineSection::D, onoff ? "yes" : "no"); break; } default: break; } if (cursor_has_moved) { const auto current_pos = _cursor_controller->where(); _status_manager->set_section_body( StatusLineSection::B, fmt::format("{}", current_pos.get_x())); _status_manager->set_section_body( StatusLineSection::C, fmt::format("{}", current_pos.get_y())); } const auto time_now = std::chrono::system_clock::now(); const auto time_since_last_update = time_now - _last_update_time; _status_manager->set_section_body( StatusLineSection::F, fmt::format("{} nanoseconds", time_since_last_update.count())); const auto time_since_last_gen_update = std::chrono::duration_cast( time_now - _last_gen_update_time); if (!_generation_tracker->get_is_paused() && time_since_last_gen_update.count() > _gen_update_speed_millis) { const auto new_current_gen = _generation_tracker->get_current_generation() + 1U; _generation_tracker->set_current_generation(new_current_gen); _status_manager->set_section_body( StatusLineSection::E, fmt::format("{}", new_current_gen)); _last_gen_update_time = time_now; } _last_update_time = time_now; } void Game::on_exit() const noexcept { for (auto row : *_scene->get_matrix()) { for (auto &col : row) { fmt::print("{}", col); } fmt::print("\n"); } std::cout.flush(); } void Game::_move_cursor(const Vector2 &direction) noexcept { const auto new_position = _cursor_controller->where().to_direction(direction, 1); const auto scene_size = _scene->size(); if (scene_size.validate_coords(new_position) != CoordsValidation::VALID) { return; } _cursor_controller->move_to(new_position); } void Game::_insert_cell(const Vector2 &position, char cell) noexcept { std::cout.put(cell); std::cout.flush(); _cursor_controller->move_to(position); auto matrix = _scene->get_matrix(); const auto pos_offset = Vector2({.x = 0U, .y = 1U}); matrix->set(position - pos_offset, cell); }