about summary refs log tree commit diff stats
path: root/Source/PuzzlerSerializer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/PuzzlerSerializer.cpp')
-rw-r--r--Source/PuzzlerSerializer.cpp280
1 files changed, 140 insertions, 140 deletions
diff --git a/Source/PuzzlerSerializer.cpp b/Source/PuzzlerSerializer.cpp index abdfafd..2ba0ce7 100644 --- a/Source/PuzzlerSerializer.cpp +++ b/Source/PuzzlerSerializer.cpp
@@ -7,22 +7,22 @@
7PuzzleSerializer::PuzzleSerializer(const std::shared_ptr<Memory>& memory) : _memory(memory) {} 7PuzzleSerializer::PuzzleSerializer(const std::shared_ptr<Memory>& memory) : _memory(memory) {}
8 8
9Puzzle PuzzleSerializer::ReadPuzzle(int id) { 9Puzzle PuzzleSerializer::ReadPuzzle(int id) {
10 int width = 2 * _memory->ReadPanelData<int>(id, GRID_SIZE_X, 1)[0] - 1; 10 int width = 2 * _memory->ReadEntityData<int>(id, GRID_SIZE_X, 1)[0] - 1;
11 int height = 2 * _memory->ReadPanelData<int>(id, GRID_SIZE_Y, 1)[0] - 1; 11 int height = 2 * _memory->ReadEntityData<int>(id, GRID_SIZE_Y, 1)[0] - 1;
12 if (width < 0 || height < 0) return Puzzle(); // @Error: Grid size should be always positive? Looks like the starting panels break this rule, though. 12 if (width < 0 || height < 0) return Puzzle(); // @Error: Grid size should be always positive? Looks like the starting panels break this rule, though.
13 13
14 int numIntersections = _memory->ReadPanelData<int>(id, NUM_DOTS, 1)[0]; 14 int numIntersections = _memory->ReadEntityData<int>(id, NUM_DOTS, 1)[0];
15 _intersectionFlags = _memory->ReadArray<int>(id, DOT_FLAGS, numIntersections); 15 _intersectionFlags = _memory->ReadArray<int>(id, DOT_FLAGS, numIntersections);
16 int numConnections = _memory->ReadPanelData<int>(id, NUM_CONNECTIONS, 1)[0]; 16 int numConnections = _memory->ReadEntityData<int>(id, NUM_CONNECTIONS, 1)[0];
17 _connectionsA = _memory->ReadArray<int>(id, DOT_CONNECTION_A, numConnections); 17 _connectionsA = _memory->ReadArray<int>(id, DOT_CONNECTION_A, numConnections);
18 _connectionsB = _memory->ReadArray<int>(id, DOT_CONNECTION_B, numConnections); 18 _connectionsB = _memory->ReadArray<int>(id, DOT_CONNECTION_B, numConnections);
19 _intersectionLocations = _memory->ReadArray<float>(id, DOT_POSITIONS, numIntersections*2); 19 _intersectionLocations = _memory->ReadArray<float>(id, DOT_POSITIONS, numIntersections*2);
20 20
21 Puzzle p; 21 Puzzle p;
22 p.NewGrid(width, height); 22 p.NewGrid(width, height);
23 ReadIntersections(p); 23 ReadIntersections(p);
24 ReadExtras(p); 24 ReadExtras(p);
25 ReadDecorations(p, id); 25 ReadDecorations(p, id);
26 ReadSequence(p, id); 26 ReadSequence(p, id);
27 return p; 27 return p;
28} 28}
@@ -34,28 +34,28 @@ void PuzzleSerializer::WritePuzzle(const Puzzle& p, int id) {
34 _intersectionLocations.clear(); 34 _intersectionLocations.clear();
35 35
36 MIN = 0.1f; 36 MIN = 0.1f;
37 MAX = 0.9f; 37 MAX = 0.9f;
38 WIDTH_INTERVAL = (MAX - MIN) / (p.width/2); 38 WIDTH_INTERVAL = (MAX - MIN) / (p.width/2);
39 HEIGHT_INTERVAL = (MAX - MIN) / (p.height/2); 39 HEIGHT_INTERVAL = (MAX - MIN) / (p.height/2);
40 HORIZ_GAP_SIZE = WIDTH_INTERVAL / 2; 40 HORIZ_GAP_SIZE = WIDTH_INTERVAL / 2;
41 VERTI_GAP_SIZE = HEIGHT_INTERVAL / 2; 41 VERTI_GAP_SIZE = HEIGHT_INTERVAL / 2;
42 42
43 WriteIntersections(p); 43 WriteIntersections(p);
44 WriteDots(p); 44 WriteDots(p);
45 WriteGaps(p); 45 WriteGaps(p);
46 WriteEndpoints(p); 46 WriteEndpoints(p);
47 WriteDecorations(p, id); 47 WriteDecorations(p, id);
48 WriteSequence(p, id); 48 WriteSequence(p, id);
49 49
50 _memory->WritePanelData<int>(id, GRID_SIZE_X, {(p.width + 1)/2}); 50 _memory->WriteEntityData<int>(id, GRID_SIZE_X, {(p.width + 1)/2});
51 _memory->WritePanelData<int>(id, GRID_SIZE_Y, {(p.height + 1)/2}); 51 _memory->WriteEntityData<int>(id, GRID_SIZE_Y, {(p.height + 1)/2});
52 _memory->WritePanelData<int>(id, NUM_DOTS, {static_cast<int>(_intersectionFlags.size())}); 52 _memory->WriteEntityData<int>(id, NUM_DOTS, {static_cast<int>(_intersectionFlags.size())});
53 _memory->WriteArray<float>(id, DOT_POSITIONS, _intersectionLocations); 53 _memory->WriteArray<float>(id, DOT_POSITIONS, _intersectionLocations);
54 _memory->WriteArray<int>(id, DOT_FLAGS, _intersectionFlags); 54 _memory->WriteArray<int>(id, DOT_FLAGS, _intersectionFlags);
55 _memory->WritePanelData<int>(id, NUM_CONNECTIONS, {static_cast<int>(_connectionsA.size())}); 55 _memory->WriteEntityData<int>(id, NUM_CONNECTIONS, {static_cast<int>(_connectionsA.size())});
56 _memory->WriteArray<int>(id, DOT_CONNECTION_A, _connectionsA); 56 _memory->WriteArray<int>(id, DOT_CONNECTION_A, _connectionsA);
57 _memory->WriteArray<int>(id, DOT_CONNECTION_B, _connectionsB); 57 _memory->WriteArray<int>(id, DOT_CONNECTION_B, _connectionsB);
58 _memory->WritePanelData<int>(id, NEEDS_REDRAW, {1}); 58 _memory->WriteEntityData<int>(id, NEEDS_REDRAW, {1});
59} 59}
60 60
61void PuzzleSerializer::ReadIntersections(Puzzle& p) { 61void PuzzleSerializer::ReadIntersections(Puzzle& p) {
@@ -70,78 +70,78 @@ void PuzzleSerializer::ReadIntersections(Puzzle& p) {
70 for (int j=0; j<_intersectionFlags.size(); j++) { 70 for (int j=0; j<_intersectionFlags.size(); j++) {
71 if (_intersectionFlags[_connectionsA[j]] & Flags::IS_ENDPOINT) break; 71 if (_intersectionFlags[_connectionsA[j]] & Flags::IS_ENDPOINT) break;
72 if (_intersectionFlags[_connectionsB[j]] & Flags::IS_ENDPOINT) break; 72 if (_intersectionFlags[_connectionsB[j]] & Flags::IS_ENDPOINT) break;
73 float x1 = _intersectionLocations[2*_connectionsA[j]]; 73 float x1 = _intersectionLocations[2*_connectionsA[j]];
74 float y1 = _intersectionLocations[2*_connectionsA[j]+1]; 74 float y1 = _intersectionLocations[2*_connectionsA[j]+1];
75 float x2 = _intersectionLocations[2*_connectionsB[j]]; 75 float x2 = _intersectionLocations[2*_connectionsB[j]];
76 float y2 = _intersectionLocations[2*_connectionsB[j]+1]; 76 float y2 = _intersectionLocations[2*_connectionsB[j]+1];
77 auto [x, y] = loc_to_xy(p, _connectionsA[j]); 77 auto [x, y] = loc_to_xy(p, _connectionsA[j]);
78 78
79 if (x1 < x2) x++; 79 if (x1 < x2) x++;
80 else if (x1 > x2) x--; 80 else if (x1 > x2) x--;
81 else if (y1 < y2) y--; 81 else if (y1 < y2) y--;
82 else if (y1 > y2) y++; 82 else if (y1 > y2) y++;
83 p.grid[x][y].gap = Cell::Gap::NONE; 83 p.grid[x][y].gap = Cell::Gap::NONE;
84 } 84 }
85} 85}
86 86
87void PuzzleSerializer::ReadExtras(Puzzle& p) { 87void PuzzleSerializer::ReadExtras(Puzzle& p) {
88 // This iterates bottom-top, left-right 88 // This iterates bottom-top, left-right
89 int i = 0; 89 int i = 0;
90 for (; i < _intersectionFlags.size(); i++) { 90 for (; i < _intersectionFlags.size(); i++) {
91 int flags = _intersectionFlags[i]; 91 int flags = _intersectionFlags[i];
92 auto [x, y] = loc_to_xy(p, i); 92 auto [x, y] = loc_to_xy(p, i);
93 if (y < 0) break; // This is the expected exit point 93 if (y < 0) break; // This is the expected exit point
94 if (flags & Flags::IS_STARTPOINT) { 94 if (flags & Flags::IS_STARTPOINT) {
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::HAS_NO_CONN) { 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 }
102 102
103 // Iterate the remaining intersections (endpoints, dots, gaps) 103 // Iterate the remaining intersections (endpoints, dots, gaps)
104 for (; i < _intersectionFlags.size(); i++) { 104 for (; i < _intersectionFlags.size(); i++) {
105 int location = FindConnection(i); 105 int location = FindConnection(i);
106 if (location == -1) continue; // @Error: Unable to find connection point 106 if (location == -1) continue; // @Error: Unable to find connection point
107 // (x1, y1) location of this intersection 107 // (x1, y1) location of this intersection
108 // (x2, y2) location of the connected intersection 108 // (x2, y2) location of the connected intersection
109 float x1 = _intersectionLocations[2*i]; 109 float x1 = _intersectionLocations[2*i];
110 float y1 = _intersectionLocations[2*i+1]; 110 float y1 = _intersectionLocations[2*i+1];
111 float x2 = _intersectionLocations[2*location]; 111 float x2 = _intersectionLocations[2*location];
112 float y2 = _intersectionLocations[2*location+1]; 112 float y2 = _intersectionLocations[2*location+1];
113 auto [x, y] = loc_to_xy(p, location); 113 auto [x, y] = loc_to_xy(p, location);
114 114
115 if (_intersectionFlags[i] & Flags::IS_ENDPOINT) { 115 if (_intersectionFlags[i] & Flags::IS_ENDPOINT) {
116 // Our x coordinate is less than the target's 116 // Our x coordinate is less than the target's
117 if (x1 < x2) p.grid[x][y].end = Cell::Dir::LEFT; 117 if (x1 < x2) p.grid[x][y].end = Cell::Dir::LEFT;
118 else if (x1 > x2) p.grid[x][y].end = Cell::Dir::RIGHT; 118 else if (x1 > x2) p.grid[x][y].end = Cell::Dir::RIGHT;
119 // Note that Y coordinates are reversed: 0.0 (bottom) 1.0 (top) 119 // Note that Y coordinates are reversed: 0.0 (bottom) 1.0 (top)
120 else if (y1 < y2) p.grid[x][y].end = Cell::Dir::DOWN; 120 else if (y1 < y2) p.grid[x][y].end = Cell::Dir::DOWN;
121 else if (y1 > y2) p.grid[x][y].end = Cell::Dir::UP; 121 else if (y1 > y2) p.grid[x][y].end = Cell::Dir::UP;
122 } else if (_intersectionFlags[i] & Flags::HAS_DOT) { 122 } else if (_intersectionFlags[i] & Flags::HAS_DOT) {
123 if (x1 < x2) x--; 123 if (x1 < x2) x--;
124 else if (x1 > x2) x++; 124 else if (x1 > x2) x++;
125 else if (y1 < y2) y++; 125 else if (y1 < y2) y++;
126 else if (y1 > y2) y--; 126 else if (y1 > y2) y--;
127 p.grid[x][y].dot = FlagsToDot(_intersectionFlags[i]); 127 p.grid[x][y].dot = FlagsToDot(_intersectionFlags[i]);
128 } else if (_intersectionFlags[i] & Flags::HAS_ONE_CONN) { 128 } else if (_intersectionFlags[i] & Flags::HAS_ONE_CONN) {
129 if (x1 < x2) x--; 129 if (x1 < x2) x--;
130 else if (x1 > x2) x++; 130 else if (x1 > x2) x++;
131 else if (y1 < y2) y++; 131 else if (y1 < y2) y++;
132 else if (y1 > y2) y--; 132 else if (y1 > y2) y--;
133 p.grid[x][y].gap = Cell::Gap::BREAK; 133 p.grid[x][y].gap = Cell::Gap::BREAK;
134 } 134 }
135 } 135 }
136} 136}
137 137
138void PuzzleSerializer::ReadDecorations(Puzzle& p, int id) { 138void PuzzleSerializer::ReadDecorations(Puzzle& p, int id) {
139 int numDecorations = _memory->ReadPanelData<int>(id, NUM_DECORATIONS, 1)[0]; 139 int numDecorations = _memory->ReadEntityData<int>(id, NUM_DECORATIONS, 1)[0];
140 std::vector<int> decorations = _memory->ReadArray<int>(id, DECORATIONS, numDecorations); 140 std::vector<int> decorations = _memory->ReadArray<int>(id, DECORATIONS, numDecorations);
141 if (numDecorations > 0) p.hasDecorations = true; 141 if (numDecorations > 0) p.hasDecorations = true;
142 142
143 for (int i=0; i<numDecorations; i++) { 143 for (int i=0; i<numDecorations; i++) {
144 auto [x, y] = dloc_to_xy(p, i); 144 auto [x, y] = dloc_to_xy(p, i);
145 auto d = std::make_shared<Decoration>(); 145 auto d = std::make_shared<Decoration>();
146 p.grid[x][y].decoration = d; 146 p.grid[x][y].decoration = d;
147 d->type = static_cast<Type>(decorations[i] & 0xFF00); 147 d->type = static_cast<Type>(decorations[i] & 0xFF00);
@@ -156,11 +156,11 @@ void PuzzleSerializer::ReadDecorations(Puzzle& p, int id) {
156 break; 156 break;
157 } 157 }
158 d->color = static_cast<Color>(decorations[i] & 0xF); 158 d->color = static_cast<Color>(decorations[i] & 0xF);
159 } 159 }
160} 160}
161 161
162void PuzzleSerializer::ReadSequence(Puzzle& p, int id) { 162void PuzzleSerializer::ReadSequence(Puzzle& p, int id) {
163 int sequenceLength = _memory->ReadPanelData<int>(id, SEQUENCE_LEN, 1)[0]; 163 int sequenceLength = _memory->ReadEntityData<int>(id, SEQUENCE_LEN, 1)[0];
164 std::vector<int> sequence = _memory->ReadArray<int>(id, SEQUENCE, sequenceLength); 164 std::vector<int> sequence = _memory->ReadArray<int>(id, SEQUENCE, sequenceLength);
165 165
166 for (int location : sequence) { 166 for (int location : sequence) {
@@ -170,15 +170,15 @@ void PuzzleSerializer::ReadSequence(Puzzle& p, int id) {
170} 170}
171 171
172void PuzzleSerializer::WriteIntersections(const Puzzle& p) { 172void PuzzleSerializer::WriteIntersections(const Puzzle& p) {
173 // @Cleanup: If I write directly to locations, then I can simplify this gross loop iterator. 173 // @Cleanup: If I write directly to locations, then I can simplify this gross loop iterator.
174 // int numIntersections = (p.width / 2 + 1) * (p.height / 2 + 1); 174 // int numIntersections = (p.width / 2 + 1) * (p.height / 2 + 1);
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 auto [xPos, yPos] = xy_to_pos(p, x, y); 178 auto [xPos, yPos] = xy_to_pos(p, x, y);
179 _intersectionLocations.push_back(xPos); 179 _intersectionLocations.push_back(xPos);
180 _intersectionLocations.push_back(yPos); 180 _intersectionLocations.push_back(yPos);
181 int flags = 0; 181 int flags = 0;
182 if (p.grid[x][y].start) { 182 if (p.grid[x][y].start) {
183 flags |= Flags::IS_STARTPOINT; 183 flags |= Flags::IS_STARTPOINT;
184 } 184 }
@@ -199,26 +199,26 @@ void PuzzleSerializer::WriteIntersections(const Puzzle& p) {
199 199
200 int numConnections = 0; 200 int numConnections = 0;
201 if (p.grid[x][y].end != Cell::Dir::NONE) numConnections++; 201 if (p.grid[x][y].end != Cell::Dir::NONE) numConnections++;
202 // Create connections for this intersection for top/left only. 202 // Create connections for this intersection for top/left only.
203 // Top connection 203 // Top connection
204 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) {
205 _connectionsA.push_back(xy_to_loc(p, x, y-2)); 205 _connectionsA.push_back(xy_to_loc(p, x, y-2));
206 _connectionsB.push_back(xy_to_loc(p, x, y)); 206 _connectionsB.push_back(xy_to_loc(p, x, y));
207 flags |= Flags::HAS_VERTI_CONN; 207 flags |= Flags::HAS_VERTI_CONN;
208 numConnections++; 208 numConnections++;
209 } 209 }
210 // Bottom connection 210 // Bottom connection
211 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) {
212 flags |= Flags::HAS_VERTI_CONN; 212 flags |= Flags::HAS_VERTI_CONN;
213 numConnections++; 213 numConnections++;
214 } 214 }
215 // Left connection 215 // Left connection
216 if (x > 0 && p.grid[x-1][y].gap != Cell::Gap::FULL) { 216 if (x > 0 && p.grid[x-1][y].gap != Cell::Gap::FULL) {
217 _connectionsA.push_back(xy_to_loc(p, x-2, y)); 217 _connectionsA.push_back(xy_to_loc(p, x-2, y));
218 _connectionsB.push_back(xy_to_loc(p, x, y)); 218 _connectionsB.push_back(xy_to_loc(p, x, y));
219 flags |= Flags::HAS_HORIZ_CONN; 219 flags |= Flags::HAS_HORIZ_CONN;
220 numConnections++; 220 numConnections++;
221 } 221 }
222 // Right connection 222 // Right connection
223 if (x < p.width - 1 && p.grid[x+1][y].gap != Cell::Gap::FULL) { 223 if (x < p.width - 1 && p.grid[x+1][y].gap != Cell::Gap::FULL) {
224 flags |= Flags::HAS_HORIZ_CONN; 224 flags |= Flags::HAS_HORIZ_CONN;
@@ -227,9 +227,9 @@ void PuzzleSerializer::WriteIntersections(const Puzzle& p) {
227 if (numConnections == 0) flags |= HAS_NO_CONN; 227 if (numConnections == 0) flags |= HAS_NO_CONN;
228 if (numConnections == 1) flags |= HAS_ONE_CONN; 228 if (numConnections == 1) flags |= HAS_ONE_CONN;
229 229
230 _intersectionFlags.push_back(flags); 230 _intersectionFlags.push_back(flags);
231 } 231 }
232 } 232 }
233} 233}
234 234
235void PuzzleSerializer::WriteEndpoints(const Puzzle& p) { 235void PuzzleSerializer::WriteEndpoints(const Puzzle& p) {
@@ -237,27 +237,27 @@ void PuzzleSerializer::WriteEndpoints(const Puzzle& p) {
237 for (int y=0; y<p.height; y++) { 237 for (int y=0; y<p.height; y++) {
238 if (p.grid[x][y].end == Cell::Dir::NONE) continue; 238 if (p.grid[x][y].end == Cell::Dir::NONE) continue;
239 _connectionsA.push_back(xy_to_loc(p, x, y)); 239 _connectionsA.push_back(xy_to_loc(p, x, y));
240 _connectionsB.push_back(static_cast<int>(_intersectionFlags.size())); 240 _connectionsB.push_back(static_cast<int>(_intersectionFlags.size()));
241 241
242 auto [xPos, yPos] = xy_to_pos(p, x, y); 242 auto [xPos, yPos] = xy_to_pos(p, x, y);
243 switch (p.grid[x][y].end) { 243 switch (p.grid[x][y].end) {
244 case Cell::Dir::LEFT: 244 case Cell::Dir::LEFT:
245 xPos -= .05f; 245 xPos -= .05f;
246 break; 246 break;
247 case Cell::Dir::RIGHT: 247 case Cell::Dir::RIGHT:
248 xPos += .05f; 248 xPos += .05f;
249 break; 249 break;
250 case Cell::Dir::UP: 250 case Cell::Dir::UP:
251 yPos += .05f; // Y position goes from 0 (bottom) to 1 (top), so this is reversed. 251 yPos += .05f; // Y position goes from 0 (bottom) to 1 (top), so this is reversed.
252 break; 252 break;
253 case Cell::Dir::DOWN: 253 case Cell::Dir::DOWN:
254 yPos -= .05f; 254 yPos -= .05f;
255 break; 255 break;
256 } 256 }
257 _endpointLocations.emplace_back(x, y, static_cast<int>(_intersectionFlags.size())); 257 _endpointLocations.emplace_back(x, y, static_cast<int>(_intersectionFlags.size()));
258 _intersectionLocations.push_back(xPos); 258 _intersectionLocations.push_back(xPos);
259 _intersectionLocations.push_back(yPos); 259 _intersectionLocations.push_back(yPos);
260 _intersectionFlags.push_back(Flags::IS_ENDPOINT); 260 _intersectionFlags.push_back(Flags::IS_ENDPOINT);
261 } 261 }
262 } 262 }
263} 263}
@@ -265,32 +265,32 @@ void PuzzleSerializer::WriteEndpoints(const Puzzle& p) {
265void PuzzleSerializer::WriteDots(const Puzzle& p) { 265void PuzzleSerializer::WriteDots(const Puzzle& p) {
266 for (int x=0; x<p.width; x++) { 266 for (int x=0; x<p.width; x++) {
267 for (int y=0; y<p.height; y++) { 267 for (int y=0; y<p.height; y++) {
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 which contains this dot. Break the existing segment, and add one. 271 // We need to introduce a new segment which contains this dot. Break the existing segment, and add one.
272 int connectionLocation = -1; 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 connectionLocation = i; 278 connectionLocation = i;
279 break; 279 break;
280 } 280 }
281 } 281 }
282 if (connectionLocation == -1) continue; // @Error 282 if (connectionLocation == -1) continue; // @Error
283 283
284 // @Assume: B > A for connections. To remove, add the horiz/verti check, see gaps. 284 // @Assume: B > A for connections. To remove, add the horiz/verti check, see gaps.
285 int other_connection = _connectionsB[connectionLocation]; 285 int other_connection = _connectionsB[connectionLocation];
286 _connectionsB[connectionLocation] = static_cast<int>(_intersectionFlags.size()); 286 _connectionsB[connectionLocation] = static_cast<int>(_intersectionFlags.size());
287 _connectionsA.push_back(other_connection); 287 _connectionsA.push_back(other_connection);
288 _connectionsB.push_back(static_cast<int>(_intersectionFlags.size())); 288 _connectionsB.push_back(static_cast<int>(_intersectionFlags.size()));
289 289
290 // Add this dot to the end 290 // Add this dot to the end
291 auto [xPos, yPos] = xy_to_pos(p, x, y); 291 auto [xPos, yPos] = xy_to_pos(p, x, y);
292 _intersectionLocations.push_back(xPos); 292 _intersectionLocations.push_back(xPos);
293 _intersectionLocations.push_back(yPos); 293 _intersectionLocations.push_back(yPos);
294 294
295 int flags = Flags::HAS_DOT; 295 int flags = Flags::HAS_DOT;
296 switch (p.grid[x][y].dot) { 296 switch (p.grid[x][y].dot) {
@@ -307,27 +307,27 @@ void PuzzleSerializer::WriteDots(const Puzzle& p) {
307 break; 307 break;
308 } 308 }
309 _intersectionFlags.push_back(flags); 309 _intersectionFlags.push_back(flags);
310 } 310 }
311 } 311 }
312} 312}
313 313
314void PuzzleSerializer::WriteGaps(const Puzzle& p) { 314void PuzzleSerializer::WriteGaps(const Puzzle& p) {
315 for (int x=0; x<p.width; x++) { 315 for (int x=0; x<p.width; x++) {
316 for (int y=0; y<p.height; y++) { 316 for (int y=0; y<p.height; y++) {
317 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.
318 if (p.grid[x][y].gap != Cell::Gap::BREAK) continue; 318 if (p.grid[x][y].gap != Cell::Gap::BREAK) continue;
319 319
320 // We need to introduce a new segment which contains this dot. Break the existing segment, and add one. 320 // We need to introduce a new segment which contains this dot. Break the existing segment, and add one.
321 int connectionLocation = -1; 321 int connectionLocation = -1;
322 for (int i=0; i<_connectionsA.size(); i++) { 322 for (int i=0; i<_connectionsA.size(); i++) {
323 auto [x1, y1] = loc_to_xy(p, _connectionsA[i]); 323 auto [x1, y1] = loc_to_xy(p, _connectionsA[i]);
324 auto [x2, y2] = loc_to_xy(p, _connectionsB[i]); 324 auto [x2, y2] = loc_to_xy(p, _connectionsB[i]);
325 if ((x1+1 == x && x2-1 == x && y1 == y && y2 == y) || 325 if ((x1+1 == x && x2-1 == x && y1 == y && y2 == y) ||
326 (y1+1 == y && y2-1 == y && x1 == x && x2 == x)) { 326 (y1+1 == y && y2-1 == y && x1 == x && x2 == x)) {
327 connectionLocation = i; 327 connectionLocation = i;
328 break; 328 break;
329 } 329 }
330 } 330 }
331 if (connectionLocation == -1) continue; // @Error 331 if (connectionLocation == -1) continue; // @Error
332 332
333 auto [xPos, yPos] = xy_to_pos(p, x, y); 333 auto [xPos, yPos] = xy_to_pos(p, x, y);
@@ -335,49 +335,49 @@ void PuzzleSerializer::WriteGaps(const Puzzle& p) {
335 if (x%2 == 0) { // Vertical gap 335 if (x%2 == 0) { // Vertical gap
336 _connectionsA[connectionLocation] = xy_to_loc(p, x, y-1); 336 _connectionsA[connectionLocation] = xy_to_loc(p, x, y-1);
337 _connectionsB[connectionLocation] = static_cast<int>(_intersectionFlags.size()); 337 _connectionsB[connectionLocation] = static_cast<int>(_intersectionFlags.size());
338 _intersectionLocations.push_back(xPos); 338 _intersectionLocations.push_back(xPos);
339 _intersectionLocations.push_back(yPos + VERTI_GAP_SIZE / 2); 339 _intersectionLocations.push_back(yPos + VERTI_GAP_SIZE / 2);
340 _intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_VERTI_CONN); 340 _intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_VERTI_CONN);
341 341
342 _connectionsA.push_back(xy_to_loc(p, x, y+1)); 342 _connectionsA.push_back(xy_to_loc(p, x, y+1));
343 _connectionsB.push_back(static_cast<int>(_intersectionFlags.size())); 343 _connectionsB.push_back(static_cast<int>(_intersectionFlags.size()));
344 _intersectionLocations.push_back(xPos); 344 _intersectionLocations.push_back(xPos);
345 _intersectionLocations.push_back(yPos - VERTI_GAP_SIZE / 2); 345 _intersectionLocations.push_back(yPos - VERTI_GAP_SIZE / 2);
346 _intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_VERTI_CONN); 346 _intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_VERTI_CONN);
347 } else if (y%2 == 0) { // Horizontal gap 347 } else if (y%2 == 0) { // Horizontal gap
348 _connectionsA[connectionLocation] = xy_to_loc(p, x-1, y); 348 _connectionsA[connectionLocation] = xy_to_loc(p, x-1, y);
349 _connectionsB[connectionLocation] = static_cast<int>(_intersectionFlags.size()); 349 _connectionsB[connectionLocation] = static_cast<int>(_intersectionFlags.size());
350 _intersectionLocations.push_back(xPos - HORIZ_GAP_SIZE / 2); 350 _intersectionLocations.push_back(xPos - HORIZ_GAP_SIZE / 2);
351 _intersectionLocations.push_back(yPos); 351 _intersectionLocations.push_back(yPos);
352 _intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_HORIZ_CONN); 352 _intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_HORIZ_CONN);
353 353
354 _connectionsA.push_back(xy_to_loc(p, x+1, y)); 354 _connectionsA.push_back(xy_to_loc(p, x+1, y));
355 _connectionsB.push_back(static_cast<int>(_intersectionFlags.size())); 355 _connectionsB.push_back(static_cast<int>(_intersectionFlags.size()));
356 _intersectionLocations.push_back(xPos + HORIZ_GAP_SIZE / 2); 356 _intersectionLocations.push_back(xPos + HORIZ_GAP_SIZE / 2);
357 _intersectionLocations.push_back(yPos); 357 _intersectionLocations.push_back(yPos);
358 _intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_HORIZ_CONN); 358 _intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_HORIZ_CONN);
359 } 359 }
360 } 360 }
361 } 361 }
362} 362}
363 363
364void PuzzleSerializer::WriteDecorations(const Puzzle& p, int id) { 364void PuzzleSerializer::WriteDecorations(const Puzzle& p, int id) {
365 if (!p.hasDecorations) return; 365 if (!p.hasDecorations) return;
366 366
367 std::vector<int> decorations; 367 std::vector<int> decorations;
368 for (int y=p.height-2; y>0; y-=2) { 368 for (int y=p.height-2; y>0; y-=2) {
369 for (int x=1; x<p.width-1; x+=2) { 369 for (int x=1; x<p.width-1; x+=2) {
370 auto d = p.grid[x][y].decoration; 370 auto d = p.grid[x][y].decoration;
371 if (d) { 371 if (d) {
372 decorations.push_back(d->color | d->type | d->count | d->polyshape); 372 decorations.push_back(d->color | d->type | d->count | d->polyshape);
373 } else { 373 } else {
374 decorations.push_back(0); 374 decorations.push_back(0);
375 } 375 }
376 } 376 }
377 } 377 }
378 378
379 _memory->WritePanelData<int>(id, NUM_DECORATIONS, {static_cast<int>(decorations.size())}); 379 _memory->WriteEntityData<int>(id, NUM_DECORATIONS, {static_cast<int>(decorations.size())});
380 _memory->WriteArray<int>(id, DECORATIONS, decorations); 380 _memory->WriteArray<int>(id, DECORATIONS, decorations);
381} 381}
382 382
383void PuzzleSerializer::WriteSequence(const Puzzle& p, int id) { 383void PuzzleSerializer::WriteSequence(const Puzzle& p, int id) {
@@ -399,7 +399,7 @@ void PuzzleSerializer::WriteSequence(const Puzzle& p, int id) {
399 } 399 }
400 } 400 }
401 401
402 _memory->WritePanelData<int>(id, SEQUENCE_LEN, {static_cast<int>(sequence.size())}); 402 _memory->WriteEntityData<int>(id, SEQUENCE_LEN, {static_cast<int>(sequence.size())});
403 _memory->WriteNewArray<int>(id, SEQUENCE, sequence); 403 _memory->WriteNewArray<int>(id, SEQUENCE, sequence);
404} 404}
405 405
@@ -438,7 +438,7 @@ int PuzzleSerializer::xy_to_dloc(const Puzzle& p, int x, int y) const {
438} 438}
439 439
440std::tuple<float, float> PuzzleSerializer::xy_to_pos(const Puzzle& p, int x, int y) const { 440std::tuple<float, float> PuzzleSerializer::xy_to_pos(const Puzzle& p, int x, int y) const {
441 return { 441 return {
442 MIN + (x/2.0f) * WIDTH_INTERVAL, 442 MIN + (x/2.0f) * WIDTH_INTERVAL,
443 MAX - (y/2.0f) * HEIGHT_INTERVAL 443 MAX - (y/2.0f) * HEIGHT_INTERVAL
444 }; 444 };
@@ -454,8 +454,8 @@ Cell::Dot PuzzleSerializer::FlagsToDot(int flags) const {
454 454
455int PuzzleSerializer::FindConnection(int location) const { 455int PuzzleSerializer::FindConnection(int location) const {
456 for (int j=0; j<_connectionsA.size(); j++) { 456 for (int j=0; j<_connectionsA.size(); j++) {
457 if (_connectionsA[j] == location) return _connectionsB[j]; 457 if (_connectionsA[j] == location) return _connectionsB[j];
458 if (_connectionsB[j] == location) return _connectionsA[j]; 458 if (_connectionsB[j] == location) return _connectionsA[j];
459 } 459 }
460 return -1; 460 return -1;
461} 461}