From 6f0a34bfb761d965bd961dc1f880b84e35f9959f Mon Sep 17 00:00:00 2001 From: jbzdarkid Date: Wed, 20 Nov 2019 10:05:59 -0800 Subject: Understanding symmetry, but nothing else. --- Source/Memory.h | 4 +- Source/Puzzle.h | 9 ++++- Source/PuzzleSerializer.cpp | 98 ++++++++++++++++++++++++++++++++------------- Source/PuzzleSerializer.h | 8 +++- Source/Randomizer2.cpp | 21 ++++++---- Source/Randomizer2.h | 1 + Source/Randomizer2Core.cpp | 2 +- Source/Solver.cpp | 6 +-- Source/Validator.cpp | 4 +- 9 files changed, 107 insertions(+), 46 deletions(-) (limited to 'Source') diff --git a/Source/Memory.h b/Source/Memory.h index 5332cc3..b7edb28 100644 --- a/Source/Memory.h +++ b/Source/Memory.h @@ -5,8 +5,8 @@ #include #include -// #define GLOBALS 0x5B28C0 -#define GLOBALS 0x62D0A0 +#define GLOBALS 0x5B28C0 +// #define GLOBALS 0x62D0A0 #define HEARTBEAT 0x401 enum class ProcStatus { diff --git a/Source/Puzzle.h b/Source/Puzzle.h index 1e00ef4..ac604f1 100644 --- a/Source/Puzzle.h +++ b/Source/Puzzle.h @@ -61,7 +61,12 @@ struct Cell { }; struct Negation {}; -struct Pos {int x; int y;}; +struct Pos { + Pos(int x_, int y_) : x(x_), y(y_) {} + Pos(const std::tuple& xy) : x(std::get<0>(xy)), y(std::get<1>(xy)) {} + int x; + int y; +}; class Puzzle { public: @@ -70,7 +75,7 @@ public: bool hasDecorations = false; enum class Symmetry {NONE, X, Y, XY}; - Symmetry sym = Symmetry::NONE; + Symmetry symmetry = Symmetry::NONE; bool pillar = false; bool valid = false; 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) { if (height == 0) height = width; if (width < 0 || height < 0) return Puzzle(); // @Error: Grid size should be always positive? Looks like the starting panels break this rule, though. - int numIntersections = _memory->ReadEntityData(id, NUM_DOTS, 1)[0]; - _intersectionFlags = _memory->ReadArray(id, DOT_FLAGS, numIntersections); + _numIntersections = _memory->ReadEntityData(id, NUM_DOTS, 1)[0]; + _intersectionFlags = _memory->ReadArray(id, DOT_FLAGS, _numIntersections); int numConnections = _memory->ReadEntityData(id, NUM_CONNECTIONS, 1)[0]; _connectionsA = _memory->ReadArray(id, DOT_CONNECTION_A, numConnections); _connectionsB = _memory->ReadArray(id, DOT_CONNECTION_B, numConnections); - _intersectionLocations = _memory->ReadArray(id, DOT_POSITIONS, numIntersections*2); + _intersectionLocations = _memory->ReadArray(id, DOT_POSITIONS, _numIntersections*2); Puzzle p; p.NewGrid(width, height); @@ -27,6 +27,7 @@ Puzzle PuzzleSerializer::ReadPuzzle(int id) { ReadExtras(p); ReadDecorations(p, id); ReadSequence(p, id); + ReadSymmetry(p, id); return p; } @@ -80,7 +81,7 @@ void PuzzleSerializer::ReadIntersections(Puzzle& p) { } } - for (int j=0; j<_intersectionFlags.size(); j++) { + for (int j=0; j<_numIntersections; j++) { if (_intersectionFlags[_connectionsA[j]] & Flags::IS_ENDPOINT) break; if (_intersectionFlags[_connectionsB[j]] & Flags::IS_ENDPOINT) break; float x1 = _intersectionLocations[2*_connectionsA[j]]; @@ -100,7 +101,7 @@ void PuzzleSerializer::ReadIntersections(Puzzle& p) { void PuzzleSerializer::ReadExtras(Puzzle& p) { // This iterates bottom-top, left-right int i = 0; - for (; i < _intersectionFlags.size(); i++) { + for (; i < _numIntersections; i++) { int flags = _intersectionFlags[i]; auto [x, y] = loc_to_xy(p, i); if (y < 0) break; // This is the expected exit point @@ -114,7 +115,7 @@ void PuzzleSerializer::ReadExtras(Puzzle& p) { } // Iterate the remaining intersections (endpoints, dots, gaps) - for (; i < _intersectionFlags.size(); i++) { + for (; i < _numIntersections; i++) { int location = FindConnection(i); if (location == -1) continue; // @Error: Unable to find connection point // (x1, y1) location of this intersection @@ -177,8 +178,23 @@ void PuzzleSerializer::ReadSequence(Puzzle& p, int id) { std::vector sequence = _memory->ReadArray(id, SEQUENCE, sequenceLength); for (int location : sequence) { - auto [x, y] = loc_to_xy(p, location); - p.sequence.emplace_back(Pos{x, y}); + p.sequence.emplace_back(loc_to_xy(p, location)); + } +} + +void PuzzleSerializer::ReadSymmetry(Puzzle& p, int id) { + int hasSymmetry = _memory->ReadEntityData(id, REFLECTION_DATA, 1)[0]; + if (hasSymmetry == 0) return; // Array is null, no puzzle symmetry + + std::vector reflectionData = _memory->ReadArray(id, REFLECTION_DATA, _numIntersections); + Pos p1 = loc_to_xy(p, reflectionData[0]); + Pos p2 = loc_to_xy(p, reflectionData[reflectionData[0]]); + if (p1.x != p2.x) { + p.symmetry = Puzzle::Symmetry::Y; + } else if (p1.y != p2.y) { + p.symmetry = Puzzle::Symmetry::X; + } else { + p.symmetry = Puzzle::Symmetry::XY; } } @@ -188,9 +204,6 @@ void PuzzleSerializer::WriteIntersections(const Puzzle& p) { // Grided intersections for (int y=p.height-1; y>=0; y-=2) { for (int x=0; x(_intersectionFlags.size())); - _intersectionLocations.push_back(xPos); - _intersectionLocations.push_back(yPos); - _intersectionFlags.push_back(Flags::IS_ENDPOINT); + AddIntersection(x, y, xPos, yPos, Flags::IS_ENDPOINT); } } } @@ -300,11 +311,6 @@ void PuzzleSerializer::WriteDots(const Puzzle& p) { _connectionsA.push_back(other_connection); _connectionsB.push_back(static_cast(_intersectionFlags.size())); - // Add this dot to the end - auto [xPos, yPos] = xy_to_pos(p, x, y); - _intersectionLocations.push_back(xPos); - _intersectionLocations.push_back(yPos); - int flags = Flags::HAS_DOT; switch (p.grid[x][y].dot) { case Cell::Dot::BLACK: @@ -319,7 +325,9 @@ void PuzzleSerializer::WriteDots(const Puzzle& p) { flags |= DOT_IS_INVISIBLE; break; } - _intersectionFlags.push_back(flags); + + auto [xPos, yPos] = xy_to_pos(p, x, y); + AddIntersection(x, y, xPos, yPos, flags); } } } @@ -409,17 +417,36 @@ void PuzzleSerializer::WriteSequence(const Puzzle& p, int id) { } Pos endpoint = p.sequence[p.sequence.size() - 1]; - for (auto [x, y, location] : _endpointLocations) { - if (x == endpoint.x && y == endpoint.y) { - sequence.emplace_back(location); - break; - } - } + int location = extra_xy_to_loc(endpoint); _memory->WriteEntityData(id, SEQUENCE_LEN, {static_cast(sequence.size())}); _memory->WriteNewArray(id, SEQUENCE, sequence); } +void PuzzleSerializer::WriteSymmetry(const Puzzle& p, int id) { + if (p.symmetry == Puzzle::Symmetry::NONE) { + _memory->WriteEntityData(id, REFLECTION_DATA, {0}); + return; + } + + // TODO: This. Probably 3 different sections for the different types? + // The idea is simple, though, just write symmetry data for all endpoints. + // Handle the default grid... then just separate iterators for dots/gaps/endpoints? Gross, but might work. + // I think this might put constraints on how I build the dots/gaps, actually. Let me see. + /* + Pos p1 = loc_to_xy(p, reflectionData[0]); + Pos p2 = loc_to_xy(p, reflectionData[reflectionData[0]]); + if (p1.x != p2.x) { + p.symmetry = Puzzle::Symmetry::Y; + } else if (p1.y != p2.y) { + p.symmetry = Puzzle::Symmetry::X; + } else { + p.symmetry = Puzzle::Symmetry::XY; + } + + */ +} + std::tuple PuzzleSerializer::loc_to_xy(const Puzzle& p, int location) const { int height2 = (p.height - 1) / 2; int width2 = (p.width + 1) / 2; @@ -437,6 +464,14 @@ int PuzzleSerializer::xy_to_loc(const Puzzle& p, int x, int y) const { return rowsFromBottom * width2 + x/2; } +int PuzzleSerializer::extra_xy_to_loc(Pos pos) const { + for (auto [x, y, location] : _extraLocations) { + if (pos.x == x && pos.y == y) return location; + } + + return -1; // @Error +} + std::tuple PuzzleSerializer::dloc_to_xy(const Puzzle& p, int location) const { int height2 = (p.height - 3) / 2; int width2 = (p.width - 1) / 2; @@ -476,3 +511,10 @@ int PuzzleSerializer::FindConnection(int location) const { } return -1; } + +void PuzzleSerializer::AddIntersection(int x, int y, float xPos, float yPos, int flags) { + _extraLocations.emplace_back(x, y, static_cast(_intersectionFlags.size())); + _intersectionLocations.push_back(xPos); + _intersectionLocations.push_back(yPos); + _intersectionFlags.push_back(flags); +} diff --git a/Source/PuzzleSerializer.h b/Source/PuzzleSerializer.h index d9b9edd..3c8f480 100644 --- a/Source/PuzzleSerializer.h +++ b/Source/PuzzleSerializer.h @@ -31,6 +31,7 @@ private: void ReadExtras(Puzzle& p); void ReadDecorations(Puzzle& p, int id); void ReadSequence(Puzzle& p, int id); + void ReadSymmetry(Puzzle& p, int id); void WriteIntersections(const Puzzle& p); void WriteDots(const Puzzle& p); @@ -38,9 +39,11 @@ private: void WriteEndpoints(const Puzzle& p); void WriteDecorations(const Puzzle& p, int id); void WriteSequence(const Puzzle& p, int id); + void WriteSymmetry(const Puzzle& p, int id); std::tuple loc_to_xy(const Puzzle& p, int location) const; int xy_to_loc(const Puzzle& p, int x, int y) const; + int extra_xy_to_loc(Pos pos) const; // Decoration location std::tuple dloc_to_xy(const Puzzle& p, int location) const; int xy_to_dloc(const Puzzle& p, int x, int y) const; @@ -49,14 +52,17 @@ private: Cell::Dot FlagsToDot(int flags) const; // Iterate connection lists for another location which is connected to us; return that other location. int FindConnection(int location) const; + void AddIntersection(int x, int y, float xPos, float yPos, int flags); std::shared_ptr _memory; std::vector _intersectionLocations; + int _numIntersections; std::vector _intersectionFlags; std::vector _connectionsA; std::vector _connectionsB; - std::vector> _endpointLocations; + // Locations of non-grid points, i.e. dots, gaps, and endpoints + std::vector> _extraLocations; float MIN, MAX, WIDTH_INTERVAL, HEIGHT_INTERVAL, HORIZ_GAP_SIZE, VERTI_GAP_SIZE; }; diff --git a/Source/Randomizer2.cpp b/Source/Randomizer2.cpp index 00b584e..e4f2b9f 100644 --- a/Source/Randomizer2.cpp +++ b/Source/Randomizer2.cpp @@ -14,6 +14,7 @@ Randomizer2::Randomizer2(const std::shared_ptr& memory) : _memory(memory void Randomizer2::Randomize() { RandomizeTutorial(); + RandomizeSymmetry(); // RandomizeKeep(); } @@ -105,44 +106,44 @@ void Randomizer2::RandomizeTutorial() { x = 1; y = 1; toTheRight = true; - cuts.emplace_back(Pos{0, 1}); + cuts.emplace_back(0, 1); break; case 2: x = 1; y = 1; toTheRight = true; - cuts.emplace_back(Pos{1, 0}); + cuts.emplace_back(1, 0); break; case 3: x = 11; y = 1; toTheRight = false; - cuts.emplace_back(Pos{12, 1}); + cuts.emplace_back(12, 1); break; case 4: x = 11; y = 1; toTheRight = false; - cuts.emplace_back(Pos{11, 0}); + cuts.emplace_back(11, 0); break; } while (y < p.height) { // The final cut will push y below the bottom of the puzzle, which means we're done. switch (Random::RandInt(1, 4)) { case 1: // Go right if (x < p.width-2) { - cuts.emplace_back(Pos{x+1, y}); + cuts.emplace_back(x+1, y); x += 2; } break; case 2: // Go left if (x > 1) { - cuts.emplace_back(Pos{x-1, y}); + cuts.emplace_back(x-1, y); x -= 2; } break; case 3: case 4: // Go down (biased) - cuts.emplace_back(Pos{x, y+1}); + cuts.emplace_back(x, y+1); y += 2; break; } @@ -159,6 +160,12 @@ void Randomizer2::RandomizeTutorial() { } } +void Randomizer2::RandomizeSymmetry() { + { // + + } +} + void Randomizer2::RandomizeKeep() { { // Hedges 1 Puzzle p; diff --git a/Source/Randomizer2.h b/Source/Randomizer2.h index 6e79694..47a9ebd 100644 --- a/Source/Randomizer2.h +++ b/Source/Randomizer2.h @@ -8,6 +8,7 @@ public: Randomizer2(const std::shared_ptr& memory); void Randomize(); void RandomizeTutorial(); + void RandomizeSymmetry(); void RandomizeKeep(); private: diff --git a/Source/Randomizer2Core.cpp b/Source/Randomizer2Core.cpp index c34fec6..f8d1312 100644 --- a/Source/Randomizer2Core.cpp +++ b/Source/Randomizer2Core.cpp @@ -24,7 +24,7 @@ std::vector Randomizer2Core::CutEdges(const Puzzle& p, size_t numEdges, boo bool inSequence = false; for (Pos pos : p.sequence) inSequence |= (pos.x == x && pos.y == y); if (inSequence) continue; - edges.emplace_back(Pos{x, y}); + edges.emplace_back(x, y); } } return CutEdgesInternal(p, edges, numEdges); diff --git a/Source/Solver.cpp b/Source/Solver.cpp index a8710a2..c0b35ef 100644 --- a/Source/Solver.cpp +++ b/Source/Solver.cpp @@ -27,10 +27,10 @@ void Solver::SolveLoop(Puzzle& p, int x, int y, std::vector& solutions) if (cell.undefined) return; if (cell.gap != Cell::Gap::NONE) return; - if (p.sym == Puzzle::Symmetry::NONE) { + if (p.symmetry == Puzzle::Symmetry::NONE) { if (cell.color != Cell::Color::NONE) return; // Collided with ourselves p.grid[x][y].color = Cell::Color::BLACK; // Otherwise, mark this cell as visited - p.sequence.emplace_back(Pos{x, y}); + p.sequence.emplace_back(x, y); } else { /* // Get the symmetrical position, and try coloring it @@ -71,7 +71,7 @@ void Solver::SolveLoop(Puzzle& p, int x, int y, std::vector& solutions) // Tail recursion: Back out of this cell p.grid[x][y].color = Cell::Color::NONE; p.sequence.pop_back(); - if (p.sym != Puzzle::Symmetry::NONE) { + if (p.symmetry != Puzzle::Symmetry::NONE) { /* auto sym = p.GetSymmetricalPos(x, y); p.grid[sym.x][sym.y].color = Cell::Color::NONE; diff --git a/Source/Validator.cpp b/Source/Validator.cpp index 82d6779..e71dc34 100644 --- a/Source/Validator.cpp +++ b/Source/Validator.cpp @@ -32,7 +32,7 @@ void Validator::Validate(Puzzle& p) { if (p.GetLine(x, y + 1) != Cell::Color::NONE) actualCount++; if (decoration->count != actualCount) { // console.log('Triangle at grid['+x+']['+y+'] has', actualCount, 'borders') - p.invalidElements.emplace_back(Pos{x, y}); + p.invalidElements.emplace_back(x, y); } } } @@ -43,7 +43,7 @@ void Validator::Validate(Puzzle& p) { if (cell.dot != Cell::Dot::NONE) { if (cell.color == Cell::Color::NONE) { // console.log('Dot at', x, y, 'is not covered') - p.invalidElements.emplace_back(Pos{x, y}); + p.invalidElements.emplace_back(x, y); } else if (cell.color == Cell::Color::BLUE && cell.dot == Cell::Dot::YELLOW) { // console.log('Yellow dot at', x, y, 'is covered by blue line') p.valid = false; -- cgit 1.4.1