aboutsummaryrefslogtreecommitdiff
path: root/src/game
diff options
context:
space:
mode:
Diffstat (limited to 'src/game')
-rw-r--r--src/game/RLE_reader.cpp133
-rw-r--r--src/game/RLE_reader.hpp24
-rw-r--r--src/game/game.cpp77
-rw-r--r--src/game/game.hpp5
4 files changed, 230 insertions, 9 deletions
diff --git a/src/game/RLE_reader.cpp b/src/game/RLE_reader.cpp
new file mode 100644
index 0000000..f971966
--- /dev/null
+++ b/src/game/RLE_reader.cpp
@@ -0,0 +1,133 @@
+#include "RLE_reader.hpp"
+
+#include "engine/data/bounds.hpp"
+#include "engine/data/vector2.hpp"
+#include "errors/RLE_reader.hpp"
+#include "util/algorithm.hpp"
+#include "util/io.hpp"
+#include "util/string.hpp"
+
+#include <ctre.hpp>
+
+#include <cctype>
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include <iostream>
+
+RLEReader::RLEReader(const IMatrixFactory<MatrixElement> &matrix_factory) noexcept
+ : _matrix_factory(matrix_factory)
+{
+}
+
+auto RLEReader::read_RLE_file(const std::filesystem::path &path) const
+ -> std::unique_ptr<IMatrix<MatrixElement>>
+{
+ auto content_lines = read_file_lines<std::vector<std::string>>(path);
+
+ if (content_lines.empty())
+ {
+ throw InvalidRLEFileError(path, "File is empty");
+ }
+
+ if (content_lines.back().empty())
+ {
+ content_lines.pop_back();
+ }
+
+ const auto header_line_iter = container_find(
+ content_lines,
+ [](const std::string &line)
+ {
+ return ctre::starts_with<"x = \\d+, y = \\d+">(line);
+ // return ctre::match<"x = \\d+, y = \\d+(, rule = [a-zA-Z0-9/]+)?">(line);
+ });
+
+ if (header_line_iter == content_lines.end())
+ {
+ throw InvalidRLEFileError(path, "No header line");
+ }
+
+ const auto &header_line = *header_line_iter;
+
+ const auto header_parts = split_string<std::vector<std::string>>(header_line, ',');
+
+ const auto &header_x_part = header_parts[0];
+ const auto &header_y_part = header_parts[1].substr(1);
+
+ const auto pattern_width =
+ static_cast<Bounds::Value>(std::stoul(header_x_part.substr(4)));
+
+ const auto pattern_height =
+ static_cast<Bounds::Value>(std::stoul(header_y_part.substr(4)));
+
+ const auto pattern_size = Bounds({.width = pattern_width, .height = pattern_height});
+
+ auto pattern_matrix = _matrix_factory(pattern_size);
+
+ auto pattern_pos = Vector2({.x = 0, .y = 0});
+
+ const auto first_pattern_line_iter = header_line_iter + 1;
+
+ for (auto pattern_line_iter = first_pattern_line_iter;
+ pattern_line_iter != content_lines.end();
+ ++pattern_line_iter)
+ {
+ if (!ctre::match<"[bo$0-9!]+">(*pattern_line_iter))
+ {
+ throw InvalidRLEFileError(path, "Invalid pattern line");
+ }
+ }
+
+ auto pattern = std::string();
+
+ for (auto pattern_line_iter = first_pattern_line_iter;
+ pattern_line_iter != content_lines.end();
+ ++pattern_line_iter)
+ {
+ pattern.append(*pattern_line_iter);
+ }
+
+ auto run_count_str = std::string();
+
+ for (const auto &character : pattern)
+ {
+ if (static_cast<bool>(isdigit(character)))
+ {
+ run_count_str += character;
+ continue;
+ }
+
+ if (character == '!')
+ {
+ break;
+ }
+
+ const auto run_count = run_count_str.empty() ? 1 : std::stoi(run_count_str);
+
+ run_count_str.clear();
+
+ if (character == '$')
+ {
+ pattern_pos.set_x(0);
+ pattern_pos += Vector2({.x = 0, .y = run_count});
+ continue;
+ }
+
+ for (auto run_index = 0; run_index < run_count; run_index++)
+ {
+ if (pattern_size.validate_coords(pattern_pos) != CoordsValidation::VALID)
+ {
+ throw InvalidRLEFileError(path, "Pattern goes out of bounds");
+ }
+
+ pattern_matrix->set(pattern_pos, character == 'o' ? 'x' : ' ');
+
+ pattern_pos += Vector2::right();
+ }
+ }
+
+ return pattern_matrix;
+}
+
diff --git a/src/game/RLE_reader.hpp b/src/game/RLE_reader.hpp
new file mode 100644
index 0000000..797575e
--- /dev/null
+++ b/src/game/RLE_reader.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "interfaces/RLE_reader.hpp"
+#include "interfaces/matrix.hpp"
+
+#include <yacppdic/auto_wirable.hpp>
+
+#include <filesystem>
+#include <memory>
+
+class RLEReader
+ : public IRLEReader,
+ public yacppdic::
+ AutoWirable<IRLEReader, RLEReader, IMatrixFactory<IRLEReader::MatrixElement>>
+{
+public:
+ explicit RLEReader(const IMatrixFactory<MatrixElement> &matrix_factory) noexcept;
+
+ [[nodiscard]] auto read_RLE_file(const std::filesystem::path &path) const
+ -> std::unique_ptr<IMatrix<MatrixElement>> override;
+
+private:
+ IMatrixFactory<MatrixElement> _matrix_factory;
+};
diff --git a/src/game/game.cpp b/src/game/game.cpp
index 73ab7f5..8d15b86 100644
--- a/src/game/game.cpp
+++ b/src/game/game.cpp
@@ -3,7 +3,10 @@
#include "engine/data/bounds.hpp"
#include "engine/escape.hpp"
#include "engine/keycodes.hpp"
+#include "errors/RLE_reader.hpp"
+#include "errors/io.hpp"
#include "util/algorithm.hpp"
+#include "util/fs.hpp"
#include "util/string.hpp"
#include <fmt/color.h>
@@ -21,7 +24,8 @@ Game::Game(
std::shared_ptr<IGenerationTracker> generation_tracker,
std::shared_ptr<IStatusManager> status_manager,
std::shared_ptr<IUserInputObserver> user_input_observer,
- std::shared_ptr<ICellHelper> cell_helper) noexcept
+ std::shared_ptr<ICellHelper> cell_helper,
+ std::shared_ptr<IRLEReader> rle_reader) noexcept
: _statusline_factory(std::move(statusline_factory)),
_scene(std::move(scene)),
_cursor_controller(std::move(cursor_controller)),
@@ -29,6 +33,7 @@ Game::Game(
_status_manager(std::move(status_manager)),
_user_input_observer(std::move(user_input_observer)),
_cell_helper(std::move(cell_helper)),
+ _rle_reader(std::move(rle_reader)),
_current_mode(Mode::NORMAL),
_minimum_cursor_pos_y(0)
{
@@ -89,18 +94,74 @@ void Game::on_start() noexcept
scene_size.get_width(),
scene_size.get_height()));
- _commands["ping"] = CommandInfo(
- {.option_cnt = 0,
- .function = [this](CommandInfo::Options /*options*/)
+ _commands["open"] = CommandInfo(
+ {.option_cnt = 1U,
+ .function = [this](CommandInfo::Options options)
{
- _erase_entire_line();
+ const auto rle_file_path =
+ expand_path_home(std::filesystem::path(options[0]));
- const auto position = _cursor_controller->where();
+ std::unique_ptr<IMatrix<char>> rle_matrix;
- _cursor_controller->move_to(Vector2({.x = 0, .y = position.get_y()}));
+ try
+ {
+ rle_matrix = _rle_reader->read_RLE_file(rle_file_path);
+ }
+ catch (const InvalidRLEFileError &error)
+ {
+ _show_command_error(fmt::format("Error: {}", error.what()));
+ return;
+ }
+ catch (const IOError &error)
+ {
+ _show_command_error(fmt::format("Error: {}", error.what()));
+ return;
+ }
+
+ if (rle_matrix == nullptr)
+ {
+ _show_command_error(fmt::format(
+ "A unknown error occurred while reading RLE file with path '{}'",
+ rle_file_path.string()));
+ return;
+ }
+
+ _return_to_normal_mode();
+
+ const auto previous_pos = _cursor_controller->where();
+
+ auto scene_matrix = _scene->get_matrix();
+
+ for (auto row : *rle_matrix)
+ {
+ for (auto &col : row)
+ {
+ const auto col_pos = _cursor_controller->where();
+
+ std::cout.put(col);
+
+ _cursor_controller->move_to(col_pos);
+
+ scene_matrix->set(col_pos, col);
+
+ if (!container_has(_living_cell_positions, col_pos))
+ {
+ _living_cell_positions.push_back(col_pos);
+ }
+
+ _cursor_controller->move(Vector2::right(), 1U);
+ }
+
+ fmt::print("\n");
+ const auto current_pos = _cursor_controller->where();
+
+ _cursor_controller->move_to(
+ Vector2({.x = previous_pos.get_x(), .y = current_pos.get_y() - 1}));
+ }
- std::cout << "pong!";
std::cout.flush();
+
+ _cursor_controller->move_to(previous_pos);
}});
}
diff --git a/src/game/game.hpp b/src/game/game.hpp
index 4d83fe5..abee6ec 100644
--- a/src/game/game.hpp
+++ b/src/game/game.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include "interfaces/RLE_reader.hpp"
#include "interfaces/cell_helper.hpp"
#include "interfaces/cursor.hpp"
#include "interfaces/game.hpp"
@@ -59,7 +60,8 @@ public:
std::shared_ptr<IGenerationTracker> generation_tracker,
std::shared_ptr<IStatusManager> status_manager,
std::shared_ptr<IUserInputObserver> user_input_observer,
- std::shared_ptr<ICellHelper> cell_helper) noexcept;
+ std::shared_ptr<ICellHelper> cell_helper,
+ std::shared_ptr<IRLEReader> rle_reader) noexcept;
void on_start() noexcept override;
@@ -76,6 +78,7 @@ private:
std::shared_ptr<IStatusManager> _status_manager;
std::shared_ptr<IUserInputObserver> _user_input_observer;
std::shared_ptr<ICellHelper> _cell_helper;
+ std::shared_ptr<IRLEReader> _rle_reader;
Mode _current_mode;