#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; }