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