diff options
author | HampusM <hampus@hampusmat.com> | 2022-06-12 13:44:58 +0200 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2022-06-13 17:57:01 +0200 |
commit | 927e065f9829045247be7c0b3296408b6f577c1f (patch) | |
tree | 7da3d9cd5aa4070414a8708a582f6c3ab3e1e708 /src/game/RLE_reader.cpp | |
parent | eb66598c326862fd9dfc1899be4eac93f81a8023 (diff) |
feat: add reading RLE files
Diffstat (limited to 'src/game/RLE_reader.cpp')
-rw-r--r-- | src/game/RLE_reader.cpp | 133 |
1 files changed, 133 insertions, 0 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; +} + |