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.cpp285
1 files changed, 159 insertions, 126 deletions
diff --git a/Source/PuzzlerSerializer.cpp b/Source/PuzzlerSerializer.cpp index 779336d..86f59e7 100644 --- a/Source/PuzzlerSerializer.cpp +++ b/Source/PuzzlerSerializer.cpp
@@ -11,21 +11,52 @@ Puzzle PuzzleSerializer::ReadPuzzle(int id) {
11 int height = 2 * _memory->ReadPanelData<int>(id, GRID_SIZE_Y, 1)[0] - 1; 11 int height = 2 * _memory->ReadPanelData<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];
15 _intersectionFlags = _memory->ReadArray<int>(id, DOT_FLAGS, numIntersections);
16 int numConnections = _memory->ReadPanelData<int>(id, NUM_CONNECTIONS, 1)[0];
17 _connectionsA = _memory->ReadArray<int>(id, DOT_CONNECTION_A, numConnections);
18 _connectionsB = _memory->ReadArray<int>(id, DOT_CONNECTION_B, numConnections);
19 _intersectionLocations = _memory->ReadArray<float>(id, DOT_POSITIONS, numIntersections*2);
20
14 Puzzle p; 21 Puzzle p;
15 p.NewGrid(width, height); 22 p.NewGrid(width, height);
16 ReadIntersections(p, id); 23 ReadIntersections(p);
24 ReadExtras(p);
17 ReadDecorations(p, id); 25 ReadDecorations(p, id);
26 ReadSequence(p, id);
18 return p; 27 return p;
19} 28}
20 29
21void PuzzleSerializer::ReadIntersections(Puzzle& p, int id) { 30void PuzzleSerializer::WritePuzzle(const Puzzle& p, int id) {
22 int numIntersections = _memory->ReadPanelData<int>(id, NUM_DOTS, 1)[0]; 31 _intersectionFlags.clear();
23 std::vector<int> intersectionFlags = _memory->ReadArray<int>(id, DOT_FLAGS, numIntersections); 32 _connectionsA.clear();
24 int numConnections = _memory->ReadPanelData<int>(id, NUM_CONNECTIONS, 1)[0]; 33 _connectionsB.clear();
25 std::vector<int> connections_a = _memory->ReadArray<int>(id, DOT_CONNECTION_A, numConnections); 34 _intersectionLocations.clear();
26 std::vector<int> connections_b = _memory->ReadArray<int>(id, DOT_CONNECTION_B, numConnections); 35
27 std::vector<float> intersectionLocations = _memory->ReadArray<float>(id, DOT_POSITIONS, numIntersections*2); 36 MIN = 0.1f;
37 MAX = 0.9f;
38 WIDTH_INTERVAL = (MAX - MIN) / (p.width/2);
39 HEIGHT_INTERVAL = (MAX - MIN) / (p.height/2);
40 HORIZ_GAP_SIZE = WIDTH_INTERVAL / 2;
41 VERTI_GAP_SIZE = HEIGHT_INTERVAL / 2;
42
43 WriteIntersections(p);
44 WriteEndpoints(p);
45 WriteDecorations(p, id);
46 WriteSequence(p, id);
47
48 _memory->WritePanelData<int>(id, GRID_SIZE_X, {(p.width + 1)/2});
49 _memory->WritePanelData<int>(id, GRID_SIZE_Y, {(p.height + 1)/2});
50 _memory->WritePanelData<int>(id, NUM_DOTS, {static_cast<int>(_intersectionFlags.size())});
51 _memory->WriteArray<float>(id, DOT_POSITIONS, _intersectionLocations);
52 _memory->WriteArray<int>(id, DOT_FLAGS, _intersectionFlags);
53 _memory->WritePanelData<int>(id, NUM_CONNECTIONS, {static_cast<int>(_connectionsA.size())});
54 _memory->WriteArray<int>(id, DOT_CONNECTION_A, _connectionsA);
55 _memory->WriteArray<int>(id, DOT_CONNECTION_B, _connectionsB);
56 _memory->WritePanelData<int>(id, NEEDS_REDRAW, {1});
57}
28 58
59void PuzzleSerializer::ReadIntersections(Puzzle& p) {
29 // @Cleanup: Change defaults? 60 // @Cleanup: Change defaults?
30 for (int x=0; x<p.width; x++) { 61 for (int x=0; x<p.width; x++) {
31 for (int y=0; y<p.height; y++) { 62 for (int y=0; y<p.height; y++) {
@@ -34,14 +65,14 @@ void PuzzleSerializer::ReadIntersections(Puzzle& p, int id) {
34 } 65 }
35 } 66 }
36 67
37 for (int j=0; j<numIntersections; j++) { 68 for (int j=0; j<_intersectionFlags.size(); j++) {
38 if (intersectionFlags[connections_a[j]] & Flags::IS_ENDPOINT) break; 69 if (_intersectionFlags[_connectionsA[j]] & Flags::IS_ENDPOINT) break;
39 if (intersectionFlags[connections_b[j]] & Flags::IS_ENDPOINT) break; 70 if (_intersectionFlags[_connectionsB[j]] & Flags::IS_ENDPOINT) break;
40 float x1 = intersectionLocations[2*connections_a[j]]; 71 float x1 = _intersectionLocations[2*_connectionsA[j]];
41 float y1 = intersectionLocations[2*connections_a[j]+1]; 72 float y1 = _intersectionLocations[2*_connectionsA[j]+1];
42 float x2 = intersectionLocations[2*connections_b[j]]; 73 float x2 = _intersectionLocations[2*_connectionsB[j]];
43 float y2 = intersectionLocations[2*connections_b[j]+1]; 74 float y2 = _intersectionLocations[2*_connectionsB[j]+1];
44 auto [x, y] = loc_to_xy(p, connections_a[j]); 75 auto [x, y] = loc_to_xy(p, _connectionsA[j]);
45 76
46 if (x1 < x2) x++; 77 if (x1 < x2) x++;
47 else if (x1 > x2) x--; 78 else if (x1 > x2) x--;
@@ -49,13 +80,15 @@ void PuzzleSerializer::ReadIntersections(Puzzle& p, int id) {
49 else if (y1 > y2) y++; 80 else if (y1 > y2) y++;
50 p.grid[x][y].gap = Cell::Gap::NONE; 81 p.grid[x][y].gap = Cell::Gap::NONE;
51 } 82 }
83}
52 84
85void PuzzleSerializer::ReadExtras(Puzzle& p) {
53 // This iterates bottom-top, left-right 86 // This iterates bottom-top, left-right
54 int i = 0; 87 int i = 0;
55 for (;; i++) { 88 for (; i < _intersectionFlags.size(); i++) {
56 int flags = intersectionFlags[i]; 89 int flags = _intersectionFlags[i];
57 auto [x, y] = loc_to_xy(p, i); 90 auto [x, y] = loc_to_xy(p, i);
58 if (y < 0) break; 91 if (y < 0) break; // This is the expected exit point
59 if (flags & Flags::IS_STARTPOINT) { 92 if (flags & Flags::IS_STARTPOINT) {
60 p.grid[x][y].start = true; 93 p.grid[x][y].start = true;
61 } 94 }
@@ -66,31 +99,31 @@ void PuzzleSerializer::ReadIntersections(Puzzle& p, int id) {
66 } 99 }
67 100
68 // Iterate the remaining intersections (endpoints, dots, gaps) 101 // Iterate the remaining intersections (endpoints, dots, gaps)
69 for (; i < numIntersections; i++) { 102 for (; i < _intersectionFlags.size(); i++) {
70 int location = FindConnection(i, connections_a, connections_b); 103 int location = FindConnection(i);
71 if (location == -1) continue; // @Error: Unable to find connection point 104 if (location == -1) continue; // @Error: Unable to find connection point
72 // (x1, y1) location of this intersection 105 // (x1, y1) location of this intersection
73 // (x2, y2) location of the connected intersection 106 // (x2, y2) location of the connected intersection
74 float x1 = intersectionLocations[2*i]; 107 float x1 = _intersectionLocations[2*i];
75 float y1 = intersectionLocations[2*i+1]; 108 float y1 = _intersectionLocations[2*i+1];
76 float x2 = intersectionLocations[2*location]; 109 float x2 = _intersectionLocations[2*location];
77 float y2 = intersectionLocations[2*location+1]; 110 float y2 = _intersectionLocations[2*location+1];
78 auto [x, y] = loc_to_xy(p, location); 111 auto [x, y] = loc_to_xy(p, location);
79 112
80 if (intersectionFlags[i] & Flags::IS_ENDPOINT) { 113 if (_intersectionFlags[i] & Flags::IS_ENDPOINT) {
81 // Our x coordinate is less than the target's 114 // Our x coordinate is less than the target's
82 if (x1 < x2) p.grid[x][y].end = Cell::Dir::LEFT; 115 if (x1 < x2) p.grid[x][y].end = Cell::Dir::LEFT;
83 else if (x1 > x2) p.grid[x][y].end = Cell::Dir::RIGHT; 116 else if (x1 > x2) p.grid[x][y].end = Cell::Dir::RIGHT;
84 // Note that Y coordinates are reversed: 0.0 (bottom) 1.0 (top) 117 // Note that Y coordinates are reversed: 0.0 (bottom) 1.0 (top)
85 else if (y1 < y2) p.grid[x][y].end = Cell::Dir::DOWN; 118 else if (y1 < y2) p.grid[x][y].end = Cell::Dir::DOWN;
86 else if (y1 > y2) p.grid[x][y].end = Cell::Dir::UP; 119 else if (y1 > y2) p.grid[x][y].end = Cell::Dir::UP;
87 } else if (intersectionFlags[i] & Flags::HAS_DOT) { 120 } else if (_intersectionFlags[i] & Flags::HAS_DOT) {
88 if (x1 < x2) x--; 121 if (x1 < x2) x--;
89 else if (x1 > x2) x++; 122 else if (x1 > x2) x++;
90 else if (y1 < y2) y++; 123 else if (y1 < y2) y++;
91 else if (y1 > y2) y--; 124 else if (y1 > y2) y--;
92 p.grid[x][y].dot = FlagsToDot(intersectionFlags[i]); 125 p.grid[x][y].dot = FlagsToDot(_intersectionFlags[i]);
93 } else if (intersectionFlags[i] & Flags::HAS_ONE_CONN) { 126 } else if (_intersectionFlags[i] & Flags::HAS_ONE_CONN) {
94 if (x1 < x2) x--; 127 if (x1 < x2) x--;
95 else if (x1 > x2) x++; 128 else if (x1 > x2) x++;
96 else if (y1 < y2) y++; 129 else if (y1 < y2) y++;
@@ -124,36 +157,24 @@ void PuzzleSerializer::ReadDecorations(Puzzle& p, int id) {
124 } 157 }
125} 158}
126 159
127void PuzzleSerializer::WritePuzzle(const Puzzle& p, int id) { 160void PuzzleSerializer::ReadSequence(Puzzle& p, int id) {
128 _memory->WritePanelData<int>(id, GRID_SIZE_X, {(p.width + 1)/2}); 161 int sequenceLength = _memory->ReadPanelData<int>(id, SEQUENCE_LEN, 1)[0];
129 _memory->WritePanelData<int>(id, GRID_SIZE_Y, {(p.height + 1)/2}); 162 std::vector<int> sequence = _memory->ReadArray<int>(id, SEQUENCE, sequenceLength);
130
131 WriteIntersections(p, id);
132 if (p.hasDecorations) WriteDecorations(p, id);
133 163
134 _memory->WritePanelData<int>(id, NEEDS_REDRAW, {1}); 164 for (int location : sequence) {
165 auto [x, y] = loc_to_xy(p, location);
166 p.sequence.emplace_back(Pos{x, y});
167 }
135} 168}
136 169
137void PuzzleSerializer::WriteIntersections(const Puzzle& p, int id) { 170void PuzzleSerializer::WriteIntersections(const Puzzle& p) {
138 std::vector<float> intersectionLocations;
139 std::vector<int> intersectionFlags;
140 std::vector<int> connections_a;
141 std::vector<int> connections_b;
142
143 float min = 0.1f;
144 float max = 0.9f;
145 float width_interval = (max - min) / (p.width/2);
146 float height_interval = (max - min) / (p.height/2);
147 float horiz_gap_size = width_interval / 2;
148 float verti_gap_size = height_interval / 2;
149
150 // @Cleanup: If I write directly to locations, then I can simplify this gross loop iterator. 171 // @Cleanup: If I write directly to locations, then I can simplify this gross loop iterator.
151 // int numIntersections = (p.width / 2 + 1) * (p.height / 2 + 1); 172 // int numIntersections = (p.width / 2 + 1) * (p.height / 2 + 1);
152 // Grided intersections 173 // Grided intersections
153 for (int y=p.height-1; y>=0; y-=2) { 174 for (int y=p.height-1; y>=0; y-=2) {
154 for (int x=0; x<p.width; x+=2) { 175 for (int x=0; x<p.width; x+=2) {
155 intersectionLocations.push_back(min + (x/2) * width_interval); 176 _intersectionLocations.push_back(MIN + (x/2) * WIDTH_INTERVAL);
156 intersectionLocations.push_back(max - (y/2) * height_interval); 177 _intersectionLocations.push_back(MAX - (y/2) * HEIGHT_INTERVAL);
157 int flags = 0; 178 int flags = 0;
158 if (p.grid[x][y].start) { 179 if (p.grid[x][y].start) {
159 flags |= Flags::IS_STARTPOINT; 180 flags |= Flags::IS_STARTPOINT;
@@ -180,43 +201,43 @@ void PuzzleSerializer::WriteIntersections(const Puzzle& p, int id) {
180 if (p.grid[x][y].end != Cell::Dir::NONE) numConnections++; 201 if (p.grid[x][y].end != Cell::Dir::NONE) numConnections++;
181 // Create connections for this intersection for bottom/left only. 202 // Create connections for this intersection for bottom/left only.
182 // Bottom connection 203 // Bottom connection
183 if (y > 0 && p.grid[x][y-1].gap == Cell::Gap::NONE) { 204 if (y > 0 && p.grid[x][y-1].gap != Cell::Gap::FULL) {
184 connections_a.push_back(xy_to_loc(p, x, y-2)); 205 _connectionsA.push_back(xy_to_loc(p, x, y-2));
185 connections_b.push_back(xy_to_loc(p, x, y)); 206 _connectionsB.push_back(xy_to_loc(p, x, y));
186 flags |= Flags::HAS_VERTI_CONN; 207 flags |= Flags::HAS_VERTI_CONN;
187 numConnections++; 208 numConnections++;
188 } 209 }
189 // Top connection 210 // Top connection
190 if (y < p.height - 1 && p.grid[x][y+1].gap == Cell::Gap::NONE) { 211 if (y < p.height - 1 && p.grid[x][y+1].gap != Cell::Gap::FULL) {
191 flags |= Flags::HAS_VERTI_CONN; 212 flags |= Flags::HAS_VERTI_CONN;
192 numConnections++; 213 numConnections++;
193 } 214 }
194 // Left connection 215 // Left connection
195 if (x > 0 && p.grid[x-1][y].gap == Cell::Gap::NONE) { 216 if (x > 0 && p.grid[x-1][y].gap != Cell::Gap::FULL) {
196 connections_a.push_back(xy_to_loc(p, x-2, y)); 217 _connectionsA.push_back(xy_to_loc(p, x-2, y));
197 connections_b.push_back(xy_to_loc(p, x, y)); 218 _connectionsB.push_back(xy_to_loc(p, x, y));
198 flags |= Flags::HAS_HORIZ_CONN; 219 flags |= Flags::HAS_HORIZ_CONN;
199 numConnections++; 220 numConnections++;
200 } 221 }
201 // Right connection 222 // Right connection
202 if (x < p.width - 1 && p.grid[x+1][y].gap == Cell::Gap::NONE) { 223 if (x < p.width - 1 && p.grid[x+1][y].gap != Cell::Gap::FULL) {
203 flags |= Flags::HAS_HORIZ_CONN; 224 flags |= Flags::HAS_HORIZ_CONN;
204 numConnections++; 225 numConnections++;
205 } 226 }
206 if (numConnections == 1) flags |= HAS_ONE_CONN; 227 if (numConnections == 1) flags |= HAS_ONE_CONN;
207 intersectionFlags.push_back(flags); 228 _intersectionFlags.push_back(flags);
208 } 229 }
209 } 230 }
231}
210 232
211 // Endpoints 233void PuzzleSerializer::WriteEndpoints(const Puzzle& p) {
212 for (int x=0; x<p.width; x++) { 234 for (int x=0; x<p.width; x++) {
213 for (int y=0; y<p.height; y++) { 235 for (int y=0; y<p.height; y++) {
214 if (p.grid[x][y].end == Cell::Dir::NONE) continue; 236 if (p.grid[x][y].end == Cell::Dir::NONE) continue;
215 connections_a.push_back(xy_to_loc(p, x, y)); // Target to connect to 237 _connectionsA.push_back(xy_to_loc(p, x, y)); // Target to connect to
216 connections_b.push_back(static_cast<int>(intersectionFlags.size())); // This endpoint 238 _connectionsB.push_back(static_cast<int>(_intersectionFlags.size())); // This endpoint
217 239
218 float xPos = min + (x/2) * width_interval; 240 auto [xPos, yPos] = xy_to_pos(p, x, y);
219 float yPos = max - (y/2) * height_interval;
220 switch (p.grid[x][y].end) { 241 switch (p.grid[x][y].end) {
221 case Cell::Dir::LEFT: 242 case Cell::Dir::LEFT:
222 xPos -= .05f; 243 xPos -= .05f;
@@ -231,13 +252,14 @@ void PuzzleSerializer::WriteIntersections(const Puzzle& p, int id) {
231 yPos -= .05f; 252 yPos -= .05f;
232 break; 253 break;
233 } 254 }
234 intersectionLocations.push_back(xPos); 255 _intersectionLocations.push_back(xPos);
235 intersectionLocations.push_back(yPos); 256 _intersectionLocations.push_back(yPos);
236 intersectionFlags.push_back(Flags::IS_ENDPOINT); 257 _intersectionFlags.push_back(Flags::IS_ENDPOINT);
237 } 258 }
238 } 259 }
260}
239 261
240 // Dots 262void PuzzleSerializer::WriteDots(const Puzzle& p) {
241 for (int x=0; x<p.width; x++) { 263 for (int x=0; x<p.width; x++) {
242 for (int y=0; y<p.height; y++) { 264 for (int y=0; y<p.height; y++) {
243 if (x%2 == y%2) continue; // Cells are invalid, intersections are already handled. 265 if (x%2 == y%2) continue; // Cells are invalid, intersections are already handled.
@@ -245,24 +267,23 @@ void PuzzleSerializer::WriteIntersections(const Puzzle& p, int id) {
245 267
246 // We need to introduce a new segment -- 268 // We need to introduce a new segment --
247 // Locate the segment we're breaking 269 // Locate the segment we're breaking
248 for (int i=0; i<connections_a.size(); i++) { 270 for (int i=0; i<_connectionsA.size(); i++) {
249 auto [x1, y1] = loc_to_xy(p, connections_a[i]); 271 auto [x1, y1] = loc_to_xy(p, _connectionsA[i]);
250 auto [x2, y2] = loc_to_xy(p, connections_b[i]); 272 auto [x2, y2] = loc_to_xy(p, _connectionsB[i]);
251 if ((x1+1 == x && x2-1 == x && y1 == y && y2 == y) || 273 if ((x1+1 == x && x2-1 == x && y1 == y && y2 == y) ||
252 (y1+1 == y && y2-1 == y && x1 == x && x2 == x)) { 274 (y1+1 == y && y2-1 == y && x1 == x && x2 == x)) {
253 int other_connection = connections_b[i]; 275 int other_connection = _connectionsB[i];
254 connections_b[i] = static_cast<int>(intersectionFlags.size()); // This endpoint 276 _connectionsB[i] = static_cast<int>(_intersectionFlags.size()); // This endpoint
255 277
256 connections_a.push_back(other_connection); 278 _connectionsA.push_back(other_connection);
257 connections_b.push_back(static_cast<int>(intersectionFlags.size())); // This endpoint 279 _connectionsB.push_back(static_cast<int>(_intersectionFlags.size())); // This endpoint
258 break; 280 break;
259 } 281 }
260 } 282 }
261 // Add this dot to the end 283 // Add this dot to the end
262 float xPos = min + (x/2.0f) * width_interval; 284 auto [xPos, yPos] = xy_to_pos(p, x, y);
263 float yPos = max - (y/2.0f) * height_interval; 285 _intersectionLocations.push_back(xPos);
264 intersectionLocations.push_back(xPos); 286 _intersectionLocations.push_back(yPos);
265 intersectionLocations.push_back(yPos);
266 287
267 int flags = Flags::HAS_DOT; 288 int flags = Flags::HAS_DOT;
268 switch (p.grid[x][y].dot) { 289 switch (p.grid[x][y].dot) {
@@ -278,56 +299,51 @@ void PuzzleSerializer::WriteIntersections(const Puzzle& p, int id) {
278 flags |= DOT_IS_INVISIBLE; 299 flags |= DOT_IS_INVISIBLE;
279 break; 300 break;
280 } 301 }
281 intersectionFlags.push_back(flags); 302 _intersectionFlags.push_back(flags);
282 } 303 }
283 } 304 }
305}
284 306
285 // Gaps 307void PuzzleSerializer::WriteGaps(const Puzzle& p) {
286 for (int x=0; x<p.width; x++) { 308 for (int x=0; x<p.width; x++) {
287 for (int y=0; y<p.height; y++) { 309 for (int y=0; y<p.height; y++) {
288 if (x%2 == y%2) continue; // Cells are invalid, intersections are already handled. 310 if (x%2 == y%2) continue; // Cells are invalid, intersections are already handled.
289 if (p.grid[x][y].gap != Cell::Gap::BREAK) continue; 311 if (p.grid[x][y].gap != Cell::Gap::BREAK) continue;
290 312
291 float xPos = min + (x/2.0f) * width_interval; 313 auto [xPos, yPos] = xy_to_pos(p, x, y);
292 float yPos = max - (y/2.0f) * height_interval;
293 // Reminder: Y goes from 0.0 (bottom) to 1.0 (top) 314 // Reminder: Y goes from 0.0 (bottom) to 1.0 (top)
294 if (x%2 == 0) { // Vertical gap 315 if (x%2 == 0) { // Vertical gap
295 connections_a.push_back(xy_to_loc(p, x, y-1)); 316 _connectionsA.push_back(xy_to_loc(p, x, y-1));
296 connections_b.push_back(static_cast<int>(intersectionFlags.size())); // This endpoint 317 _connectionsB.push_back(static_cast<int>(_intersectionFlags.size())); // This endpoint
297 intersectionLocations.push_back(xPos); 318 _intersectionLocations.push_back(xPos);
298 intersectionLocations.push_back(yPos + verti_gap_size / 2); 319 _intersectionLocations.push_back(yPos + VERTI_GAP_SIZE / 2);
299 intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_VERTI_CONN); 320 _intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_VERTI_CONN);
300 321
301 connections_a.push_back(xy_to_loc(p, x, y+1)); 322 _connectionsA.push_back(xy_to_loc(p, x, y+1));
302 connections_b.push_back(static_cast<int>(intersectionFlags.size())); // This endpoint 323 _connectionsB.push_back(static_cast<int>(_intersectionFlags.size())); // This endpoint
303 intersectionLocations.push_back(xPos); 324 _intersectionLocations.push_back(xPos);
304 intersectionLocations.push_back(yPos - verti_gap_size / 2); 325 _intersectionLocations.push_back(yPos - VERTI_GAP_SIZE / 2);
305 intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_VERTI_CONN); 326 _intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_VERTI_CONN);
306 } else if (y%2 == 0) { // Horizontal gap 327 } else if (y%2 == 0) { // Horizontal gap
307 connections_a.push_back(xy_to_loc(p, x-1, y)); 328 _connectionsA.push_back(xy_to_loc(p, x-1, y));
308 connections_b.push_back(static_cast<int>(intersectionFlags.size())); // This endpoint 329 _connectionsB.push_back(static_cast<int>(_intersectionFlags.size())); // This endpoint
309 intersectionLocations.push_back(xPos - horiz_gap_size / 2); 330 _intersectionLocations.push_back(xPos - HORIZ_GAP_SIZE / 2);
310 intersectionLocations.push_back(yPos); 331 _intersectionLocations.push_back(yPos);
311 intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_HORIZ_CONN); 332 _intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_HORIZ_CONN);
312 333
313 connections_a.push_back(xy_to_loc(p, x+1, y)); 334 _connectionsA.push_back(xy_to_loc(p, x+1, y));
314 connections_b.push_back(static_cast<int>(intersectionFlags.size())); // This endpoint 335 _connectionsB.push_back(static_cast<int>(_intersectionFlags.size())); // This endpoint
315 intersectionLocations.push_back(xPos + horiz_gap_size / 2); 336 _intersectionLocations.push_back(xPos + HORIZ_GAP_SIZE / 2);
316 intersectionLocations.push_back(yPos); 337 _intersectionLocations.push_back(yPos);
317 intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_HORIZ_CONN); 338 _intersectionFlags.push_back(Flags::HAS_ONE_CONN | Flags::HAS_HORIZ_CONN);
318 } 339 }
319 } 340 }
320 } 341 }
321
322 _memory->WritePanelData<int>(id, NUM_DOTS, {static_cast<int>(intersectionFlags.size())});
323 _memory->WriteArray<float>(id, DOT_POSITIONS, intersectionLocations);
324 _memory->WriteArray<int>(id, DOT_FLAGS, intersectionFlags);
325 _memory->WritePanelData<int>(id, NUM_CONNECTIONS, {static_cast<int>(connections_a.size())});
326 _memory->WriteArray<int>(id, DOT_CONNECTION_A, connections_a);
327 _memory->WriteArray<int>(id, DOT_CONNECTION_B, connections_b);
328} 342}
329 343
330void PuzzleSerializer::WriteDecorations(const Puzzle& p, int id) { 344void PuzzleSerializer::WriteDecorations(const Puzzle& p, int id) {
345 if (!p.hasDecorations) return;
346
331 std::vector<int> decorations; 347 std::vector<int> decorations;
332 for (int y=p.height-2; y>0; y-=2) { 348 for (int y=p.height-2; y>0; y-=2) {
333 for (int x=1; x<p.width-1; x+=2) { 349 for (int x=1; x<p.width-1; x+=2) {
@@ -344,6 +360,21 @@ void PuzzleSerializer::WriteDecorations(const Puzzle& p, int id) {
344 _memory->WriteArray<int>(id, DECORATIONS, decorations); 360 _memory->WriteArray<int>(id, DECORATIONS, decorations);
345} 361}
346 362
363void PuzzleSerializer::WriteSequence(const Puzzle& p, int id) {
364 if (p.sequence.size() == 0) return;
365
366 std::vector<int> sequence;
367 for (Pos pos : p.sequence) {
368 // Only include intersections, the game does not treat segments as real objects
369 if (pos.x%2 == 0 && pos.y%2 == 0) {
370 sequence.emplace_back(xy_to_loc(p, pos.x, pos.y));
371 }
372 }
373
374 _memory->WritePanelData<int>(id, SEQUENCE_LEN, {static_cast<int>(sequence.size())});
375 _memory->WriteNewArray<int>(id, SEQUENCE, sequence);
376}
377
347std::tuple<int, int> PuzzleSerializer::loc_to_xy(const Puzzle& p, int location) const { 378std::tuple<int, int> PuzzleSerializer::loc_to_xy(const Puzzle& p, int location) const {
348 int height2 = (p.height - 1) / 2; 379 int height2 = (p.height - 1) / 2;
349 int width2 = (p.width + 1) / 2; 380 int width2 = (p.width + 1) / 2;
@@ -378,23 +409,25 @@ int PuzzleSerializer::xy_to_dloc(const Puzzle& p, int x, int y) const {
378 return rowsFromBottom * width2 + (x - 1)/2; 409 return rowsFromBottom * width2 + (x - 1)/2;
379} 410}
380 411
412std::tuple<float, float> PuzzleSerializer::xy_to_pos(const Puzzle& p, int x, int y) const {
413 return {
414 MIN + (x/2) * WIDTH_INTERVAL,
415 MAX - (y/2) * HEIGHT_INTERVAL
416 };
417}
418
381Cell::Dot PuzzleSerializer::FlagsToDot(int flags) const { 419Cell::Dot PuzzleSerializer::FlagsToDot(int flags) const {
382 if (!(flags & Flags::HAS_DOT)) return Cell::Dot::NONE; 420 if (!(flags & Flags::HAS_DOT)) return Cell::Dot::NONE;
383 if (flags & Flags::DOT_IS_BLUE) { 421 if (flags & Flags::DOT_IS_BLUE) return Cell::Dot::BLUE;
384 return Cell::Dot::BLUE; 422 else if (flags & Flags::DOT_IS_ORANGE) return Cell::Dot::YELLOW;
385 } else if (flags & Flags::DOT_IS_ORANGE) { 423 else if (flags & Flags::DOT_IS_INVISIBLE) return Cell::Dot::INVISIBLE;
386 return Cell::Dot::YELLOW; 424 else return Cell::Dot::BLACK;
387 } else if (flags & Flags::DOT_IS_INVISIBLE) {
388 return Cell::Dot::INVISIBLE;
389 } else {
390 return Cell::Dot::BLACK;
391 }
392} 425}
393 426
394int PuzzleSerializer::FindConnection(int i, const std::vector<int>& connections_a, const std::vector<int>& connections_b) const { 427int PuzzleSerializer::FindConnection(int location) const {
395 for (int j=0; j<connections_a.size(); j++) { 428 for (int j=0; j<_connectionsA.size(); j++) {
396 if (connections_a[j] == i) return connections_b[j]; 429 if (_connectionsA[j] == location) return _connectionsB[j];
397 if (connections_b[j] == i) return connections_a[j]; 430 if (_connectionsB[j] == location) return _connectionsA[j];
398 } 431 }
399 return -1; 432 return -1;
400} 433}