From 927e065f9829045247be7c0b3296408b6f577c1f Mon Sep 17 00:00:00 2001 From: HampusM Date: Sun, 12 Jun 2022 13:44:58 +0200 Subject: feat: add reading RLE files --- src/game/RLE_reader.cpp | 133 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 src/game/RLE_reader.cpp (limited to 'src/game/RLE_reader.cpp') 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 + +#include +#include +#include +#include + +#include + +RLEReader::RLEReader(const IMatrixFactory &matrix_factory) noexcept + : _matrix_factory(matrix_factory) +{ +} + +auto RLEReader::read_RLE_file(const std::filesystem::path &path) const + -> std::unique_ptr> +{ + auto content_lines = read_file_lines>(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>(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(std::stoul(header_x_part.substr(4))); + + const auto pattern_height = + static_cast(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(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; +} + -- cgit v1.2.3-18-g5258