diff options
| -rw-r--r-- | Source/Puzzle.h | 25 | ||||
| -rw-r--r-- | Source/PuzzlerSerializer.cpp | 63 | ||||
| -rw-r--r-- | Source/PuzzlerSerializer.h | 2 |
3 files changed, 54 insertions, 36 deletions
| diff --git a/Source/Puzzle.h b/Source/Puzzle.h index fdf51be..962874e 100644 --- a/Source/Puzzle.h +++ b/Source/Puzzle.h | |||
| @@ -38,25 +38,26 @@ struct Decoration { | |||
| 38 | }; | 38 | }; |
| 39 | 39 | ||
| 40 | struct Cell { | 40 | struct Cell { |
| 41 | inline static Cell Undefined() { | ||
| 42 | Cell c; | ||
| 43 | c.undefined = true; | ||
| 44 | return c; | ||
| 45 | } | ||
| 46 | bool undefined = false; | ||
| 47 | |||
| 48 | bool start = false; | ||
| 49 | enum class Dir {NONE, LEFT, RIGHT, UP, DOWN}; | ||
| 50 | Dir end = Dir::NONE; | ||
| 51 | std::shared_ptr<Decoration> decoration = nullptr; | ||
| 52 | enum class Dot {NONE, BLACK, BLUE, YELLOW, INVISIBLE}; | 41 | enum class Dot {NONE, BLACK, BLUE, YELLOW, INVISIBLE}; |
| 53 | Dot dot = Dot::NONE; | 42 | Dot dot = Dot::NONE; |
| 54 | enum class Gap {NONE, BREAK, FULL}; | 43 | enum class Gap {NONE, BREAK, FULL}; |
| 55 | Gap gap = Gap::NONE; | 44 | Gap gap = Gap::NONE; |
| 56 | |||
| 57 | // Line color | 45 | // Line color |
| 58 | enum class Color {NONE, BLACK, BLUE, YELLOW}; | 46 | enum class Color {NONE, BLACK, BLUE, YELLOW}; |
| 59 | Color color = Color::NONE; | 47 | Color color = Color::NONE; |
| 48 | |||
| 49 | std::shared_ptr<Decoration> decoration = nullptr; | ||
| 50 | |||
| 51 | bool start = false; | ||
| 52 | enum class Dir {NONE, LEFT, RIGHT, UP, DOWN}; | ||
| 53 | Dir end = Dir::NONE; | ||
| 54 | |||
| 55 | inline static Cell Undefined() { | ||
| 56 | Cell c; | ||
| 57 | c.undefined = true; | ||
| 58 | return c; | ||
| 59 | } | ||
| 60 | bool undefined = false; | ||
| 60 | }; | 61 | }; |
| 61 | 62 | ||
| 62 | struct Negation {}; | 63 | struct Negation {}; |
| diff --git a/Source/PuzzlerSerializer.cpp b/Source/PuzzlerSerializer.cpp index 8ab1649..abdfafd 100644 --- a/Source/PuzzlerSerializer.cpp +++ b/Source/PuzzlerSerializer.cpp | |||
| @@ -95,7 +95,7 @@ void PuzzleSerializer::ReadExtras(Puzzle& p) { | |||
| 95 | p.grid[x][y].start = true; | 95 | p.grid[x][y].start = true; |
| 96 | } | 96 | } |
| 97 | p.grid[x][y].dot = FlagsToDot(flags); | 97 | p.grid[x][y].dot = FlagsToDot(flags); |
| 98 | if (flags & Flags::IS_FULL_GAP) { | 98 | if (flags & Flags::HAS_NO_CONN) { |
| 99 | p.grid[x][y].gap = Cell::Gap::FULL; | 99 | p.grid[x][y].gap = Cell::Gap::FULL; |
| 100 | } | 100 | } |
| 101 | } | 101 | } |
| @@ -175,15 +175,13 @@ void PuzzleSerializer::WriteIntersections(const Puzzle& p) { | |||
| 175 | // Grided intersections | 175 | // Grided intersections |
| 176 | for (int y=p.height-1; y>=0; y-=2) { | 176 | for (int y=p.height-1; y>=0; y-=2) { |
| 177 | for (int x=0; x<p.width; x+=2) { | 177 | for (int x=0; x<p.width; x+=2) { |
| 178 | _intersectionLocations.push_back(MIN + (x/2) * WIDTH_INTERVAL); | 178 | auto [xPos, yPos] = xy_to_pos(p, x, y); |
| 179 | _intersectionLocations.push_back(MAX - (y/2) * HEIGHT_INTERVAL); | 179 | _intersectionLocations.push_back(xPos); |
| 180 | _intersectionLocations.push_back(yPos); | ||
| 180 | int flags = 0; | 181 | int flags = 0; |
| 181 | if (p.grid[x][y].start) { | 182 | if (p.grid[x][y].start) { |
| 182 | flags |= Flags::IS_STARTPOINT; | 183 | flags |= Flags::IS_STARTPOINT; |
| 183 | } | 184 | } |
| 184 | if (p.grid[x][y].gap == Cell::Gap::FULL) { | ||
| 185 | flags |= Flags::IS_FULL_GAP; | ||
| 186 | } | ||
| 187 | switch (p.grid[x][y].dot) { | 185 | switch (p.grid[x][y].dot) { |
| 188 | case Cell::Dot::BLACK: | 186 | case Cell::Dot::BLACK: |
| 189 | flags |= Flags::HAS_DOT; | 187 | flags |= Flags::HAS_DOT; |
| @@ -201,15 +199,15 @@ void PuzzleSerializer::WriteIntersections(const Puzzle& p) { | |||
| 201 | 199 | ||
| 202 | int numConnections = 0; | 200 | int numConnections = 0; |
| 203 | if (p.grid[x][y].end != Cell::Dir::NONE) numConnections++; | 201 | if (p.grid[x][y].end != Cell::Dir::NONE) numConnections++; |
| 204 | // Create connections for this intersection for bottom/left only. | 202 | // Create connections for this intersection for top/left only. |
| 205 | // Bottom connection | 203 | // Top connection |
| 206 | if (y > 0 && p.grid[x][y-1].gap != Cell::Gap::FULL) { | 204 | if (y > 0 && p.grid[x][y-1].gap != Cell::Gap::FULL) { |
| 207 | _connectionsA.push_back(xy_to_loc(p, x, y-2)); | 205 | _connectionsA.push_back(xy_to_loc(p, x, y-2)); |
| 208 | _connectionsB.push_back(xy_to_loc(p, x, y)); | 206 | _connectionsB.push_back(xy_to_loc(p, x, y)); |
| 209 | flags |= Flags::HAS_VERTI_CONN; | 207 | flags |= Flags::HAS_VERTI_CONN; |
| 210 | numConnections++; | 208 | numConnections++; |
| 211 | } | 209 | } |
| 212 | // Top connection | 210 | // Bottom connection |
| 213 | if (y < p.height - 1 && p.grid[x][y+1].gap != Cell::Gap::FULL) { | 211 | if (y < p.height - 1 && p.grid[x][y+1].gap != Cell::Gap::FULL) { |
| 214 | flags |= Flags::HAS_VERTI_CONN; | 212 | flags |= Flags::HAS_VERTI_CONN; |
| 215 | numConnections++; | 213 | numConnections++; |
| @@ -226,7 +224,9 @@ void PuzzleSerializer::WriteIntersections(const Puzzle& p) { | |||
| 226 | flags |= Flags::HAS_HORIZ_CONN; | 224 | flags |= Flags::HAS_HORIZ_CONN; |
| 227 | numConnections++; | 225 | numConnections++; |
| 228 | } | 226 | } |
| 227 | if (numConnections == 0) flags |= HAS_NO_CONN; | ||
| 229 | if (numConnections == 1) flags |= HAS_ONE_CONN; | 228 | if (numConnections == 1) flags |= HAS_ONE_CONN; |
| 229 | |||
| 230 | _intersectionFlags.push_back(flags); | 230 | _intersectionFlags.push_back(flags); |
| 231 | } | 231 | } |
| 232 | } | 232 | } |
| @@ -268,21 +268,25 @@ void PuzzleSerializer::WriteDots(const Puzzle& p) { | |||
| 268 | if (x%2 == y%2) continue; // Cells are invalid, intersections are already handled. | 268 | if (x%2 == y%2) continue; // Cells are invalid, intersections are already handled. |
| 269 | if (p.grid[x][y].dot == Cell::Dot::NONE) continue; | 269 | if (p.grid[x][y].dot == Cell::Dot::NONE) continue; |
| 270 | 270 | ||
| 271 | // We need to introduce a new segment -- | 271 | // We need to introduce a new segment which contains this dot. Break the existing segment, and add one. |
| 272 | // Locate the segment we're breaking | 272 | int connectionLocation = -1; |
| 273 | for (int i=0; i<_connectionsA.size(); i++) { | 273 | for (int i=0; i<_connectionsA.size(); i++) { |
| 274 | auto [x1, y1] = loc_to_xy(p, _connectionsA[i]); | 274 | auto [x1, y1] = loc_to_xy(p, _connectionsA[i]); |
| 275 | auto [x2, y2] = loc_to_xy(p, _connectionsB[i]); | 275 | auto [x2, y2] = loc_to_xy(p, _connectionsB[i]); |
| 276 | if ((x1+1 == x && x2-1 == x && y1 == y && y2 == y) || | 276 | if ((x1+1 == x && x2-1 == x && y1 == y && y2 == y) || |
| 277 | (y1+1 == y && y2-1 == y && x1 == x && x2 == x)) { | 277 | (y1+1 == y && y2-1 == y && x1 == x && x2 == x)) { |
| 278 | int other_connection = _connectionsB[i]; | 278 | connectionLocation = i; |
| 279 | _connectionsB[i] = static_cast<int>(_intersectionFlags.size()); | 279 | break; |
| 280 | |||
| 281 | _connectionsA.push_back(other_connection); | ||
| 282 | _connectionsB.push_back(static_cast<int>(_intersectionFlags.size())); | ||
| 283 | break; | ||
| 284 | } | 280 | } |
| 285 | } | 281 | } |
| 282 | if (connectionLocation == -1) continue; // @Error | ||
| 283 | |||
| 284 | // @Assume: B > A for connections. To remove, add the horiz/verti check, see gaps. | ||
| 285 | int other_connection = _connectionsB[connectionLocation]; | ||
| 286 | _connectionsB[connectionLocation] = static_cast<int>(_intersectionFlags.size()); | ||
| 287 | _connectionsA.push_back(other_connection); | ||
| 288 | _connectionsB.push_back(static_cast<int>(_intersectionFlags.size())); | ||
| 289 | |||
| 286 | // Add this dot to the end | 290 | // Add this dot to the end |
| 287 | auto [xPos, yPos] = xy_to_pos(p, x, y); | 291 | auto [xPos, yPos] = xy_to_pos(p, x, y); |
| 288 | _intersectionLocations.push_back(xPos); | 292 | _intersectionLocations.push_back(xPos); |
| @@ -313,11 +317,24 @@ void PuzzleSerializer::WriteGaps(const Puzzle& p) { | |||
| 313 | if (x%2 == y%2) continue; // Cells are invalid, intersections are already handled. | 317 | if (x%2 == y%2) continue; // Cells are invalid, intersections are already handled. |
| 314 | if (p.grid[x][y].gap != Cell::Gap::BREAK) continue; | 318 | if (p.grid[x][y].gap != Cell::Gap::BREAK) continue; |
| 315 | 319 | ||
| 320 | // We need to introduce a new segment which contains this dot. Break the existing segment, and add one. | ||
| 321 | int connectionLocation = -1; | ||
| 322 | for (int i=0; i<_connectionsA.size(); i++) { | ||
| 323 | auto [x1, y1] = loc_to_xy(p, _connectionsA[i]); | ||
| 324 | auto [x2, y2] = loc_to_xy(p, _connectionsB[i]); | ||
| 325 | if ((x1+1 == x && x2-1 == x && y1 == y && y2 == y) || | ||
| 326 | (y1+1 == y && y2-1 == y && x1 == x && x2 == x)) { | ||
| 327 | connectionLocation = i; | ||
| 328 | break; | ||
| 329 | } | ||
| 330 | } | ||
| 331 | if (connectionLocation == -1) continue; // @Error | ||
| 332 | |||
| 316 | auto [xPos, yPos] = xy_to_pos(p, x, y); | 333 | auto [xPos, yPos] = xy_to_pos(p, x, y); |
| 317 | // Reminder: Y goes from 0.0 (bottom) to 1.0 (top) | 334 | // Reminder: Y goes from 0.0 (bottom) to 1.0 (top) |
| 318 | if (x%2 == 0) { // Vertical gap | 335 | if (x%2 == 0) { // Vertical gap |
| 319 | _connectionsA.push_back(xy_to_loc(p, x, y-1)); | 336 | _connectionsA[connectionLocation] = xy_to_loc(p, x, y-1); |
| 320 | _connectionsB.push_back(static_cast<int>(_intersectionFlags.size())); | 337 | _connectionsB[connectionLocation] = static_cast<int>(_intersectionFlags.size()); |
| 321 | _intersectionLocations.push_back(xPos); | 338 | _intersectionLocations.push_back(xPos); |
| 322 | _intersectionLocations.push_back(yPos + VERTI_GAP_SIZE / 2); | 339 | _intersectionLocations.push_back(yPos + VERTI_GAP_SIZE / 2); |
| 323 | _intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_VERTI_CONN); | 340 | _intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_VERTI_CONN); |
| @@ -328,8 +345,8 @@ void PuzzleSerializer::WriteGaps(const Puzzle& p) { | |||
| 328 | _intersectionLocations.push_back(yPos - VERTI_GAP_SIZE / 2); | 345 | _intersectionLocations.push_back(yPos - VERTI_GAP_SIZE / 2); |
| 329 | _intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_VERTI_CONN); | 346 | _intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_VERTI_CONN); |
| 330 | } else if (y%2 == 0) { // Horizontal gap | 347 | } else if (y%2 == 0) { // Horizontal gap |
| 331 | _connectionsA.push_back(xy_to_loc(p, x-1, y)); | 348 | _connectionsA[connectionLocation] = xy_to_loc(p, x-1, y); |
| 332 | _connectionsB.push_back(static_cast<int>(_intersectionFlags.size())); | 349 | _connectionsB[connectionLocation] = static_cast<int>(_intersectionFlags.size()); |
| 333 | _intersectionLocations.push_back(xPos - HORIZ_GAP_SIZE / 2); | 350 | _intersectionLocations.push_back(xPos - HORIZ_GAP_SIZE / 2); |
| 334 | _intersectionLocations.push_back(yPos); | 351 | _intersectionLocations.push_back(yPos); |
| 335 | _intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_HORIZ_CONN); | 352 | _intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_HORIZ_CONN); |
| @@ -422,8 +439,8 @@ int PuzzleSerializer::xy_to_dloc(const Puzzle& p, int x, int y) const { | |||
| 422 | 439 | ||
| 423 | std::tuple<float, float> PuzzleSerializer::xy_to_pos(const Puzzle& p, int x, int y) const { | 440 | std::tuple<float, float> PuzzleSerializer::xy_to_pos(const Puzzle& p, int x, int y) const { |
| 424 | return { | 441 | return { |
| 425 | MIN + (x/2) * WIDTH_INTERVAL, | 442 | MIN + (x/2.0f) * WIDTH_INTERVAL, |
| 426 | MAX - (y/2) * HEIGHT_INTERVAL | 443 | MAX - (y/2.0f) * HEIGHT_INTERVAL |
| 427 | }; | 444 | }; |
| 428 | } | 445 | } |
| 429 | 446 | ||
| diff --git a/Source/PuzzlerSerializer.h b/Source/PuzzlerSerializer.h index a49dd90..a3d821c 100644 --- a/Source/PuzzlerSerializer.h +++ b/Source/PuzzlerSerializer.h | |||
| @@ -17,7 +17,7 @@ private: | |||
| 17 | enum Flags { | 17 | enum Flags { |
| 18 | IS_ENDPOINT = 0x1, | 18 | IS_ENDPOINT = 0x1, |
| 19 | IS_STARTPOINT = 0x2, | 19 | IS_STARTPOINT = 0x2, |
| 20 | IS_FULL_GAP = 0x8, | 20 | HAS_NO_CONN = 0x8, |
| 21 | HAS_DOT = 0x20, | 21 | HAS_DOT = 0x20, |
| 22 | DOT_IS_BLUE = 0x100, | 22 | DOT_IS_BLUE = 0x100, |
| 23 | DOT_IS_ORANGE = 0x200, | 23 | DOT_IS_ORANGE = 0x200, |
