levelz-cpp 0.2.0
Loading...
Searching...
No Matches
levelz.hpp
1#pragma once
2
3#include <string>
4#include <vector>
5#include <fstream>
6#include <sstream>
7#include <cstdio>
8#include <unordered_map>
9#include <algorithm>
10#include <regex>
11
12#include "levelz/coordinate.hpp"
13#include "levelz/block.hpp"
14#include "levelz/level.hpp"
15#include "levelz/matrix.hpp"
16
17using namespace LevelZ;
18
19// Internal
20
21namespace LevelZ {
22
26 const std::string HEADER_END = "---";
27
31 const std::string END = "end";
32
33}
34
35namespace {
36
37 static std::vector<std::string> splitString(const std::string& str, const std::string& delimiter) {
38 std::string str0 = str;
39
40 std::vector<std::string> parts;
41 size_t pos = 0;
42 std::string token;
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());
47 }
48 parts.push_back(str0);
49 return parts;
50 }
51
52 static std::vector<std::vector<std::string>> split(const std::vector<std::string>& file) {
53 int index = 0;
54 for (int i = 0; i < file.size(); i++) {
55 if (file[i] == LevelZ::HEADER_END) {
56 index = i;
57 break;
58 }
59 }
60
61 std::vector<std::string> header(file.begin(), file.begin() + index);
62 std::vector<std::string> body(file.begin() + index + 1, file.end());
63
64 return {header, body};
65 }
66
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;
70
71 size_t last = str.find_last_not_of(' ');
72 return str.substr(first, (last - first + 1));
73 }
74
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;
77
78 for (const std::string& header : headers) {
79 if (header[0] != '@') throw (header);
80
81 int i = header.find(' ');
82 std::string key = trim(header.substr(1, i));
83 std::string value = trim(header.substr(i));
84
85 map[key] = value;
86 }
87
88 return map;
89 }
90
91 static std::vector<Coordinate2D> read2DPoints(const std::string& input) {
92 std::vector<Coordinate2D> points;
93
94 const std::vector<std::string> split = splitString(input, "*");
95
96 for (std::string s0 : split) {
97 if (s0.empty()) continue;
98
99 if (s0.rfind('(', 0) == 0 && s0.rfind(']') == s0.size() - 1) {
101 points.push_back(c);
102 } else
103 points.push_back(Coordinate2D::from_string(s0));
104 }
105
106 return points;
107 }
108
109 static std::vector<Coordinate3D> read3DPoints(const std::string& input) {
110 std::vector<Coordinate3D> points;
111
112 const std::regex matrix("[\\[\\]()]");
113 const std::vector<std::string> split = splitString(input, "*");
114
115 for (std::string s0 : split) {
116 if (s0.empty()) continue;
117
118 if (s0.rfind('(', 0) == 0 && s0.rfind(']') == s0.size() - 1) {
120 points.push_back(c);
121 } else
122 points.push_back(Coordinate3D::from_string(s0));
123 }
124
125 return points;
126 }
127
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());
131
132 size_t pos = input.find('<');
133 if (pos == std::string::npos)
134 return Block(input);
135
136 std::string name = input.substr(0, pos);
137 std::string data = input.substr(pos + 1);
138
139 std::unordered_map<std::string, std::string> properties;
140 size_t cpos = 0;
141 std::string s0, s1;
142 while ((cpos = data.find(',')) != std::string::npos) {
143 s0 = data.substr(0, cpos);
144 data.erase(0, cpos + 1);
145
146 if ((cpos = s0.find('=')) != std::string::npos) {
147 s1 = s0.substr(0, cpos);
148 s0.erase(0, cpos + 1);
149 properties[s1] = s0;
150 }
151 }
152
153 return Block(name, properties);
154 }
155
156 static std::pair<Block, std::vector<Coordinate2D>> read2DLine(std::string& line) {
157 line.erase(std::remove(line.begin(), line.end(), ' '), line.end());
158
159 size_t pos = line.find(':');
160 std::string block = line.substr(0, pos);
161 std::string points = line.substr(pos + 1);
162
163 return {readBlock(block), read2DPoints(points)};
164 }
165
166 static std::pair<Block, std::vector<Coordinate3D>> read3DLine(std::string& line) {
167 line.erase(std::remove(line.begin(), line.end(), ' '));
168
169 size_t pos = line.find(':');
170 std::string block = line.substr(0, pos);
171 std::string points = line.substr(pos + 1);
172
173 return {readBlock(block), read3DPoints(points)};
174 }
175
176}
177
178// Implementation
179
180namespace LevelZ {
181
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]);
190
191 bool is2D = headers.at("type") == "2";
192
193 if (headers.find("spawn") == headers.end())
194 headers["spawn"] = is2D ? "[0, 0]" : "[0, 0, 0]";
195
196 if (is2D && headers.find("scroll") == headers.end())
197 headers["scroll"] = "none";
198
199 std::vector<LevelObject> blocks;
200 for (std::string& line : parts[1]) {
201 if (line[0] == '#') continue;
202 if (line == END) break;
203
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);
207
208 if (is2D) {
209 std::pair<Block, std::vector<Coordinate2D>> pair = read2DLine(line0);
210 for (Coordinate2D& point : pair.second)
211 blocks.push_back(LevelObject(pair.first, point));
212 } else {
213 std::pair<Block, std::vector<Coordinate3D>> pair = read3DLine(line0);
214 for (Coordinate3D& point : pair.second)
215 blocks.push_back(LevelObject(pair.first, point));
216 }
217 }
218
219 if (is2D)
220 return Level2D(headers, blocks);
221 else
222 return Level3D(headers, blocks);
223 }
224
230 Level parseContents(const std::string& string) {
231 std::vector<std::string> lines;
232 std::istringstream stream(string);
233
234 while (stream.good()) {
235 std::string line;
236 std::getline(stream, line);
237 lines.push_back(line);
238 }
239
240 return parseLines(lines);
241 }
242
248 Level parseFile(const std::string& file) {
249 std::vector<std::string> lines;
250 std::fstream stream(file);
251
252 std::string line;
253 while (std::getline(stream, line)) {
254 lines.push_back(line);
255 }
256
257 return parseLines(lines);
258 }
259
260}
Definition block.hpp:11
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
Definition level.hpp:90
Definition level.hpp:155
Definition block.hpp:113
Definition level.hpp:14