+
+
+
+
+
+
+
8#include <unordered_map>
+
+
+
+
12#include "levelz/coordinate.hpp"
+
13#include "levelz/block.hpp"
+
14#include "levelz/level.hpp"
+
15#include "levelz/matrix.hpp"
+
+
17using namespace LevelZ;
+
+
+
+
+
+
26 const std::string HEADER_END =
"---";
+
+
31 const std::string END =
"end";
+
+
+
+
+
+
37 static std::vector<std::string> splitString(
const std::string& str,
const std::string& delimiter) {
+
38 std::string str0 = str;
+
+
40 std::vector<std::string> parts;
+
+
+
43 while ((pos = str0.find(delimiter)) != std::string::npos) {
+
44 token = str0.substr(0, pos);
+
45 parts.push_back(token);
+
46 str0.erase(0, pos + delimiter.length());
+
+
48 parts.push_back(str0);
+
+
+
+
52 static std::vector<std::vector<std::string>> split(
const std::vector<std::string>& file) {
+
+
54 for (
int i = 0; i < file.size(); i++) {
+
55 if (file[i] == LevelZ::HEADER_END) {
+
+
+
+
+
+
61 std::vector<std::string> header(file.begin(), file.begin() + index);
+
62 std::vector<std::string> body(file.begin() + index + 1, file.end());
+
+
64 return {header, body};
+
+
+
67 static std::string trim(
const std::string& str) {
+
68 size_t first = str.find_first_not_of(
' ');
+
69 if (std::string::npos == first)
return str;
+
+
71 size_t last = str.find_last_not_of(
' ');
+
72 return str.substr(first, (last - first + 1));
+
+
+
75 static std::unordered_map<std::string, std::string> readHeaders(
const std::vector<std::string>& headers) {
+
76 std::unordered_map<std::string, std::string> map;
+
+
78 for (
const std::string& header : headers) {
+
79 if (header[0] !=
'@')
throw (header);
+
+
81 int i = header.find(
' ');
+
82 std::string key = trim(header.substr(1, i));
+
83 std::string value = trim(header.substr(i));
+
+
+
+
+
+
+
+
91 static std::vector<Coordinate2D> read2DPoints(
const std::string& input) {
+
92 std::vector<Coordinate2D> points;
+
+
94 const std::vector<std::string> split = splitString(input,
"*");
+
+
96 for (std::string s0 : split) {
+
97 if (s0.empty())
continue;
+
+
99 if (s0.rfind(
'(', 0) == 0 && s0.rfind(
']') == s0.size() - 1) {
+
+
+
+
+
+
+
+
+
+
109 static std::vector<Coordinate3D> read3DPoints(
const std::string& input) {
+
110 std::vector<Coordinate3D> points;
+
+
112 const std::regex matrix(
"[\\[\\]()]");
+
113 const std::vector<std::string> split = splitString(input,
"*");
+
+
115 for (std::string s0 : split) {
+
116 if (s0.empty())
continue;
+
+
118 if (s0.rfind(
'(', 0) == 0 && s0.rfind(
']') == s0.size() - 1) {
+
+
+
+
+
+
+
+
+
+
128 static Block readBlock(std::string& input) {
+
129 input.erase(std::remove(input.begin(), input.end(),
' '), input.end());
+
130 input.erase(std::remove(input.begin(), input.end(),
'>'), input.end());
+
+
132 size_t pos = input.find(
'<');
+
133 if (pos == std::string::npos)
+
+
+
136 std::string name = input.substr(0, pos);
+
137 std::string data = input.substr(pos + 1);
+
+
139 std::unordered_map<std::string, std::string> properties;
+
+
+
142 while ((cpos = data.find(
',')) != std::string::npos) {
+
143 s0 = data.substr(0, cpos);
+
144 data.erase(0, cpos + 1);
+
+
146 if ((cpos = s0.find(
'=')) != std::string::npos) {
+
147 s1 = s0.substr(0, cpos);
+
148 s0.erase(0, cpos + 1);
+
+
+
+
+
153 return Block(name, properties);
+
+
+
156 static std::pair<Block, std::vector<Coordinate2D>> read2DLine(std::string& line) {
+
157 line.erase(std::remove(line.begin(), line.end(),
' '), line.end());
+
+
159 size_t pos = line.find(
':');
+
160 std::string block = line.substr(0, pos);
+
161 std::string points = line.substr(pos + 1);
+
+
163 return {readBlock(block), read2DPoints(points)};
+
+
+
166 static std::pair<Block, std::vector<Coordinate3D>> read3DLine(std::string& line) {
+
167 line.erase(std::remove(line.begin(), line.end(),
' '));
+
+
169 size_t pos = line.find(
':');
+
170 std::string block = line.substr(0, pos);
+
171 std::string points = line.substr(pos + 1);
+
+
173 return {readBlock(block), read3DPoints(points)};
+
+
+
+
+
+
+
+
+
187 Level parseLines(
const std::vector<std::string>& lines) {
+
188 std::vector<std::vector<std::string>> parts = split(lines);
+
189 std::unordered_map<std::string, std::string> headers = readHeaders(parts[0]);
+
+
191 bool is2D = headers.at(
"type") ==
"2";
+
+
193 if (headers.find(
"spawn") == headers.end())
+
194 headers[
"spawn"] = is2D ?
"[0, 0]" :
"[0, 0, 0]";
+
+
196 if (is2D && headers.find(
"scroll") == headers.end())
+
197 headers[
"scroll"] =
"none";
+
+
199 std::vector<LevelObject> blocks;
+
200 for (std::string& line : parts[1]) {
+
201 if (line[0] ==
'#')
continue;
+
202 if (line == END)
break;
+
+
204 int ci = line.find(
'#');
+
205 std::string line0 = ci == std::string::npos ? line : line.substr(0, ci);
+
206 line0.erase(line0.find_last_not_of(
" \n\r\t") + 1);
+
+
+
209 std::pair<Block, std::vector<Coordinate2D>> pair = read2DLine(line0);
+
+
+
+
213 std::pair<Block, std::vector<Coordinate3D>> pair = read3DLine(line0);
+
+
+
+
+
+
+
220 return Level2D(headers, blocks);
+
+
222 return Level3D(headers, blocks);
+
+
+
230 Level parseContents(
const std::string&
string) {
+
231 std::vector<std::string> lines;
+
232 std::istringstream stream(
string);
+
+
234 while (stream.good()) {
+
+
236 std::getline(stream, line);
+
237 lines.push_back(line);
+
+
+
240 return parseLines(lines);
+
+
+
248 Level parseFile(
const std::string& file) {
+
249 std::vector<std::string> lines;
+
250 std::fstream stream(file);
+
+
+
253 while (std::getline(stream, line)) {
+
254 lines.push_back(line);
+
+
+
257 return parseLines(lines);
+
+
+
+
+
Definition coordinate.hpp:28
+
static Coordinate2D from_string(const std::string &str)
Definition coordinate.hpp:167
+
Definition coordinate.hpp:177
+
static Coordinate3D from_string(const std::string &str)
Definition coordinate.hpp:323
+
static LevelZ::CoordinateMatrix2D from_string(const std::string &str)
Definition matrix.hpp:123
+
static LevelZ::CoordinateMatrix3D from_string(const std::string &str)
Definition matrix.hpp:270
+
+
+
+
+