1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
#include "RLE_reader.hpp"
#include <ctre.hpp>
#include <cctype>
#include <string>
#include <vector>
#include "engine/data/bounds.hpp"
#include "engine/data/vector2.hpp"
#include "errors/RLE_reader.hpp"
#include "util/algorithm_impl.hpp"
#include "util/io_impl.hpp"
#include "util/string_impl.hpp"
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;
}
|