diff options
Diffstat (limited to 'Source/PuzzleSerializer.cpp')
-rw-r--r-- | Source/PuzzleSerializer.cpp | 98 |
1 files changed, 70 insertions, 28 deletions
diff --git a/Source/PuzzleSerializer.cpp b/Source/PuzzleSerializer.cpp index 5c91b56..132ebb7 100644 --- a/Source/PuzzleSerializer.cpp +++ b/Source/PuzzleSerializer.cpp | |||
@@ -14,12 +14,12 @@ Puzzle PuzzleSerializer::ReadPuzzle(int id) { | |||
14 | if (height == 0) height = width; | 14 | if (height == 0) height = width; |
15 | if (width < 0 || height < 0) return Puzzle(); // @Error: Grid size should be always positive? Looks like the starting panels break this rule, though. | 15 | if (width < 0 || height < 0) return Puzzle(); // @Error: Grid size should be always positive? Looks like the starting panels break this rule, though. |
16 | 16 | ||
17 | int numIntersections = _memory->ReadEntityData<int>(id, NUM_DOTS, 1)[0]; | 17 | _numIntersections = _memory->ReadEntityData<int>(id, NUM_DOTS, 1)[0]; |
18 | _intersectionFlags = _memory->ReadArray<int>(id, DOT_FLAGS, numIntersections); | 18 | _intersectionFlags = _memory->ReadArray<int>(id, DOT_FLAGS, _numIntersections); |
19 | int numConnections = _memory->ReadEntityData<int>(id, NUM_CONNECTIONS, 1)[0]; | 19 | int numConnections = _memory->ReadEntityData<int>(id, NUM_CONNECTIONS, 1)[0]; |
20 | _connectionsA = _memory->ReadArray<int>(id, DOT_CONNECTION_A, numConnections); | 20 | _connectionsA = _memory->ReadArray<int>(id, DOT_CONNECTION_A, numConnections); |
21 | _connectionsB = _memory->ReadArray<int>(id, DOT_CONNECTION_B, numConnections); | 21 | _connectionsB = _memory->ReadArray<int>(id, DOT_CONNECTION_B, numConnections); |
22 | _intersectionLocations = _memory->ReadArray<float>(id, DOT_POSITIONS, numIntersections*2); | 22 | _intersectionLocations = _memory->ReadArray<float>(id, DOT_POSITIONS, _numIntersections*2); |
23 | 23 | ||
24 | Puzzle p; | 24 | Puzzle p; |
25 | p.NewGrid(width, height); | 25 | p.NewGrid(width, height); |
@@ -27,6 +27,7 @@ Puzzle PuzzleSerializer::ReadPuzzle(int id) { | |||
27 | ReadExtras(p); | 27 | ReadExtras(p); |
28 | ReadDecorations(p, id); | 28 | ReadDecorations(p, id); |
29 | ReadSequence(p, id); | 29 | ReadSequence(p, id); |
30 | ReadSymmetry(p, id); | ||
30 | return p; | 31 | return p; |
31 | } | 32 | } |
32 | 33 | ||
@@ -80,7 +81,7 @@ void PuzzleSerializer::ReadIntersections(Puzzle& p) { | |||
80 | } | 81 | } |
81 | } | 82 | } |
82 | 83 | ||
83 | for (int j=0; j<_intersectionFlags.size(); j++) { | 84 | for (int j=0; j<_numIntersections; j++) { |
84 | if (_intersectionFlags[_connectionsA[j]] & Flags::IS_ENDPOINT) break; | 85 | if (_intersectionFlags[_connectionsA[j]] & Flags::IS_ENDPOINT) break; |
85 | if (_intersectionFlags[_connectionsB[j]] & Flags::IS_ENDPOINT) break; | 86 | if (_intersectionFlags[_connectionsB[j]] & Flags::IS_ENDPOINT) break; |
86 | float x1 = _intersectionLocations[2*_connectionsA[j]]; | 87 | float x1 = _intersectionLocations[2*_connectionsA[j]]; |
@@ -100,7 +101,7 @@ void PuzzleSerializer::ReadIntersections(Puzzle& p) { | |||
100 | void PuzzleSerializer::ReadExtras(Puzzle& p) { | 101 | void PuzzleSerializer::ReadExtras(Puzzle& p) { |
101 | // This iterates bottom-top, left-right | 102 | // This iterates bottom-top, left-right |
102 | int i = 0; | 103 | int i = 0; |
103 | for (; i < _intersectionFlags.size(); i++) { | 104 | for (; i < _numIntersections; i++) { |
104 | int flags = _intersectionFlags[i]; | 105 | int flags = _intersectionFlags[i]; |
105 | auto [x, y] = loc_to_xy(p, i); | 106 | auto [x, y] = loc_to_xy(p, i); |
106 | if (y < 0) break; // This is the expected exit point | 107 | if (y < 0) break; // This is the expected exit point |
@@ -114,7 +115,7 @@ void PuzzleSerializer::ReadExtras(Puzzle& p) { | |||
114 | } | 115 | } |
115 | 116 | ||
116 | // Iterate the remaining intersections (endpoints, dots, gaps) | 117 | // Iterate the remaining intersections (endpoints, dots, gaps) |
117 | for (; i < _intersectionFlags.size(); i++) { | 118 | for (; i < _numIntersections; i++) { |
118 | int location = FindConnection(i); | 119 | int location = FindConnection(i); |
119 | if (location == -1) continue; // @Error: Unable to find connection point | 120 | if (location == -1) continue; // @Error: Unable to find connection point |
120 | // (x1, y1) location of this intersection | 121 | // (x1, y1) location of this intersection |
@@ -177,8 +178,23 @@ void PuzzleSerializer::ReadSequence(Puzzle& p, int id) { | |||
177 | std::vector<int> sequence = _memory->ReadArray<int>(id, SEQUENCE, sequenceLength); | 178 | std::vector<int> sequence = _memory->ReadArray<int>(id, SEQUENCE, sequenceLength); |
178 | 179 | ||
179 | for (int location : sequence) { | 180 | for (int location : sequence) { |
180 | auto [x, y] = loc_to_xy(p, location); | 181 | p.sequence.emplace_back(loc_to_xy(p, location)); |
181 | p.sequence.emplace_back(Pos{x, y}); | 182 | } |
183 | } | ||
184 | |||
185 | void PuzzleSerializer::ReadSymmetry(Puzzle& p, int id) { | ||
186 | int hasSymmetry = _memory->ReadEntityData<int>(id, REFLECTION_DATA, 1)[0]; | ||
187 | if (hasSymmetry == 0) return; // Array is null, no puzzle symmetry | ||
188 | |||
189 | std::vector<int> reflectionData = _memory->ReadArray<int>(id, REFLECTION_DATA, _numIntersections); | ||
190 | Pos p1 = loc_to_xy(p, reflectionData[0]); | ||
191 | Pos p2 = loc_to_xy(p, reflectionData[reflectionData[0]]); | ||
192 | if (p1.x != p2.x) { | ||
193 | p.symmetry = Puzzle::Symmetry::Y; | ||
194 | } else if (p1.y != p2.y) { | ||
195 | p.symmetry = Puzzle::Symmetry::X; | ||
196 | } else { | ||
197 | p.symmetry = Puzzle::Symmetry::XY; | ||
182 | } | 198 | } |
183 | } | 199 | } |
184 | 200 | ||
@@ -188,9 +204,6 @@ void PuzzleSerializer::WriteIntersections(const Puzzle& p) { | |||
188 | // Grided intersections | 204 | // Grided intersections |
189 | for (int y=p.height-1; y>=0; y-=2) { | 205 | for (int y=p.height-1; y>=0; y-=2) { |
190 | for (int x=0; x<p.width; x+=2) { | 206 | for (int x=0; x<p.width; x+=2) { |
191 | auto [xPos, yPos] = xy_to_pos(p, x, y); | ||
192 | _intersectionLocations.push_back(xPos); | ||
193 | _intersectionLocations.push_back(yPos); | ||
194 | int flags = 0; | 207 | int flags = 0; |
195 | if (p.grid[x][y].start) { | 208 | if (p.grid[x][y].start) { |
196 | flags |= Flags::IS_STARTPOINT; | 209 | flags |= Flags::IS_STARTPOINT; |
@@ -240,7 +253,8 @@ void PuzzleSerializer::WriteIntersections(const Puzzle& p) { | |||
240 | if (numConnections == 0) flags |= HAS_NO_CONN; | 253 | if (numConnections == 0) flags |= HAS_NO_CONN; |
241 | if (numConnections == 1) flags |= HAS_ONE_CONN; | 254 | if (numConnections == 1) flags |= HAS_ONE_CONN; |
242 | 255 | ||
243 | _intersectionFlags.push_back(flags); | 256 | auto [xPos, yPos] = xy_to_pos(p, x, y); |
257 | AddIntersection(x, y, xPos, yPos, flags); | ||
244 | } | 258 | } |
245 | } | 259 | } |
246 | } | 260 | } |
@@ -267,10 +281,7 @@ void PuzzleSerializer::WriteEndpoints(const Puzzle& p) { | |||
267 | yPos -= .05f; | 281 | yPos -= .05f; |
268 | break; | 282 | break; |
269 | } | 283 | } |
270 | _endpointLocations.emplace_back(x, y, static_cast<int>(_intersectionFlags.size())); | 284 | AddIntersection(x, y, xPos, yPos, Flags::IS_ENDPOINT); |
271 | _intersectionLocations.push_back(xPos); | ||
272 | _intersectionLocations.push_back(yPos); | ||
273 | _intersectionFlags.push_back(Flags::IS_ENDPOINT); | ||
274 | } | 285 | } |
275 | } | 286 | } |
276 | } | 287 | } |
@@ -300,11 +311,6 @@ void PuzzleSerializer::WriteDots(const Puzzle& p) { | |||
300 | _connectionsA.push_back(other_connection); | 311 | _connectionsA.push_back(other_connection); |
301 | _connectionsB.push_back(static_cast<int>(_intersectionFlags.size())); | 312 | _connectionsB.push_back(static_cast<int>(_intersectionFlags.size())); |
302 | 313 | ||
303 | // Add this dot to the end | ||
304 | auto [xPos, yPos] = xy_to_pos(p, x, y); | ||
305 | _intersectionLocations.push_back(xPos); | ||
306 | _intersectionLocations.push_back(yPos); | ||
307 | |||
308 | int flags = Flags::HAS_DOT; | 314 | int flags = Flags::HAS_DOT; |
309 | switch (p.grid[x][y].dot) { | 315 | switch (p.grid[x][y].dot) { |
310 | case Cell::Dot::BLACK: | 316 | case Cell::Dot::BLACK: |
@@ -319,7 +325,9 @@ void PuzzleSerializer::WriteDots(const Puzzle& p) { | |||
319 | flags |= DOT_IS_INVISIBLE; | 325 | flags |= DOT_IS_INVISIBLE; |
320 | break; | 326 | break; |
321 | } | 327 | } |
322 | _intersectionFlags.push_back(flags); | 328 | |
329 | auto [xPos, yPos] = xy_to_pos(p, x, y); | ||
330 | AddIntersection(x, y, xPos, yPos, flags); | ||
323 | } | 331 | } |
324 | } | 332 | } |
325 | } | 333 | } |
@@ -409,17 +417,36 @@ void PuzzleSerializer::WriteSequence(const Puzzle& p, int id) { | |||
409 | } | 417 | } |
410 | 418 | ||
411 | Pos endpoint = p.sequence[p.sequence.size() - 1]; | 419 | Pos endpoint = p.sequence[p.sequence.size() - 1]; |
412 | for (auto [x, y, location] : _endpointLocations) { | 420 | int location = extra_xy_to_loc(endpoint); |
413 | if (x == endpoint.x && y == endpoint.y) { | ||
414 | sequence.emplace_back(location); | ||
415 | break; | ||
416 | } | ||
417 | } | ||
418 | 421 | ||
419 | _memory->WriteEntityData<int>(id, SEQUENCE_LEN, {static_cast<int>(sequence.size())}); | 422 | _memory->WriteEntityData<int>(id, SEQUENCE_LEN, {static_cast<int>(sequence.size())}); |
420 | _memory->WriteNewArray<int>(id, SEQUENCE, sequence); | 423 | _memory->WriteNewArray<int>(id, SEQUENCE, sequence); |
421 | } | 424 | } |
422 | 425 | ||
426 | void PuzzleSerializer::WriteSymmetry(const Puzzle& p, int id) { | ||
427 | if (p.symmetry == Puzzle::Symmetry::NONE) { | ||
428 | _memory->WriteEntityData<int>(id, REFLECTION_DATA, {0}); | ||
429 | return; | ||
430 | } | ||
431 | |||
432 | // TODO: This. Probably 3 different sections for the different types? | ||
433 | // The idea is simple, though, just write symmetry data for all endpoints. | ||
434 | // Handle the default grid... then just separate iterators for dots/gaps/endpoints? Gross, but might work. | ||
435 | // I think this might put constraints on how I build the dots/gaps, actually. Let me see. | ||
436 | /* | ||
437 | Pos p1 = loc_to_xy(p, reflectionData[0]); | ||
438 | Pos p2 = loc_to_xy(p, reflectionData[reflectionData[0]]); | ||
439 | if (p1.x != p2.x) { | ||
440 | p.symmetry = Puzzle::Symmetry::Y; | ||
441 | } else if (p1.y != p2.y) { | ||
442 | p.symmetry = Puzzle::Symmetry::X; | ||
443 | } else { | ||
444 | p.symmetry = Puzzle::Symmetry::XY; | ||
445 | } | ||
446 | |||
447 | */ | ||
448 | } | ||
449 | |||
423 | std::tuple<int, int> PuzzleSerializer::loc_to_xy(const Puzzle& p, int location) const { | 450 | std::tuple<int, int> PuzzleSerializer::loc_to_xy(const Puzzle& p, int location) const { |
424 | int height2 = (p.height - 1) / 2; | 451 | int height2 = (p.height - 1) / 2; |
425 | int width2 = (p.width + 1) / 2; | 452 | int width2 = (p.width + 1) / 2; |
@@ -437,6 +464,14 @@ int PuzzleSerializer::xy_to_loc(const Puzzle& p, int x, int y) const { | |||
437 | return rowsFromBottom * width2 + x/2; | 464 | return rowsFromBottom * width2 + x/2; |
438 | } | 465 | } |
439 | 466 | ||
467 | int PuzzleSerializer::extra_xy_to_loc(Pos pos) const { | ||
468 | for (auto [x, y, location] : _extraLocations) { | ||
469 | if (pos.x == x && pos.y == y) return location; | ||
470 | } | ||
471 | |||
472 | return -1; // @Error | ||
473 | } | ||
474 | |||
440 | std::tuple<int, int> PuzzleSerializer::dloc_to_xy(const Puzzle& p, int location) const { | 475 | std::tuple<int, int> PuzzleSerializer::dloc_to_xy(const Puzzle& p, int location) const { |
441 | int height2 = (p.height - 3) / 2; | 476 | int height2 = (p.height - 3) / 2; |
442 | int width2 = (p.width - 1) / 2; | 477 | int width2 = (p.width - 1) / 2; |
@@ -476,3 +511,10 @@ int PuzzleSerializer::FindConnection(int location) const { | |||
476 | } | 511 | } |
477 | return -1; | 512 | return -1; |
478 | } | 513 | } |
514 | |||
515 | void PuzzleSerializer::AddIntersection(int x, int y, float xPos, float yPos, int flags) { | ||
516 | _extraLocations.emplace_back(x, y, static_cast<int>(_intersectionFlags.size())); | ||
517 | _intersectionLocations.push_back(xPos); | ||
518 | _intersectionLocations.push_back(yPos); | ||
519 | _intersectionFlags.push_back(flags); | ||
520 | } | ||