about summary refs log tree commit diff stats
path: root/Source/Randomizer2.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Randomizer2.cpp')
-rw-r--r--Source/Randomizer2.cpp310
1 files changed, 161 insertions, 149 deletions
diff --git a/Source/Randomizer2.cpp b/Source/Randomizer2.cpp index b5218bf..81b6874 100644 --- a/Source/Randomizer2.cpp +++ b/Source/Randomizer2.cpp
@@ -3,6 +3,7 @@
3#include "Random.h" 3#include "Random.h"
4#include "Solver.h" 4#include "Solver.h"
5#include "Memory.h" 5#include "Memory.h"
6#include "Randomizer2Core.h"
6#include "PuzzlerSerializer.h" 7#include "PuzzlerSerializer.h"
7#include <cassert> 8#include <cassert>
8#include <string> 9#include <string>
@@ -155,173 +156,184 @@ void Randomizer2::Randomize() {
155 156
156} 157}
157 158
158void DebugColorGrid(const std::vector<std::vector<int>>& colorGrid) { 159void Randomizer2::RandomizeKeep() {
159 for (int y=0; y<colorGrid[0].size(); y++) { 160 // *** Hedges 1 ***
160 std::wstring row; 161 {
161 for (int x=0; x<colorGrid.size(); x++) { 162 Puzzle p;
162 row += std::to_wstring(colorGrid[x][y]); 163 p.NewGrid(4, 4);
164
165 p.grid[2][1].gap = Cell::Gap::FULL;
166 p.grid[4][1].gap = Cell::Gap::FULL;
167 p.grid[6][1].gap = Cell::Gap::FULL;
168 p.grid[3][2].gap = Cell::Gap::FULL;
169 p.grid[5][2].gap = Cell::Gap::FULL;
170 p.grid[8][3].gap = Cell::Gap::FULL;
171 p.grid[2][5].gap = Cell::Gap::FULL;
172 p.grid[6][5].gap = Cell::Gap::FULL;
173 p.grid[7][6].gap = Cell::Gap::FULL;
174 p.grid[2][7].gap = Cell::Gap::FULL;
175 p.grid[4][7].gap = Cell::Gap::FULL;
176
177 p.grid[4][8].start = true;
178 p.grid[6][0].end = Cell::Dir::UP;
179
180 std::vector<Pos> cutEdges = Randomizer2Core::CutEdgesToBeUnique(p);
181 assert(cutEdges.size() == 5);
182 Puzzle copy = p;
183 std::vector<int> gates = {0x00344, 0x00488, 0x00489, 0x00495, 0x00496};
184 for (int i=0; i<gates.size(); i++) {
185 Pos pos = cutEdges[i];
186 copy.grid[pos.x][pos.y].gap = Cell::Gap::BREAK;
187 SetGate(gates[i], pos.x, pos.y);
163 } 188 }
164 row += L'\n'; 189 auto solutions = Solver::Solve(copy);
165 OutputDebugString(row.c_str()); 190 assert(solutions.size() == 1);
191 p.sequence = solutions[0].sequence;
192 PuzzleSerializer(_memory).WritePuzzle(solutions[0], 0x139);
166 } 193 }
167 OutputDebugString(L"\n");
168}
169
170void FloodFill(const Puzzle& p, std::vector<std::vector<int>>& colorGrid, int color, int x, int y) {
171 if (!p.SafeCell(x, y)) return;
172 if (colorGrid[x][y] != 0) return; // Already processed.
173 colorGrid[x][y] = color;
174 194
175 FloodFill(p, colorGrid, color, x, y+1); 195 // *** Hedges 2 ***
176 FloodFill(p, colorGrid, color, x, y-1); 196 {
177 FloodFill(p, colorGrid, color, x+1, y); 197 Puzzle p;
178 FloodFill(p, colorGrid, color, x-1, y); 198 p.NewGrid(4, 4);
179}
180
181void FloodFillOutside(const Puzzle&p, std::vector<std::vector<int>>& colorGrid, int x, int y) {
182 if (!p.SafeCell(x, y)) return;
183 if (colorGrid[x][y] != 0) return; // Already processed.
184 if (x%2 != y%2 && p.grid[x][y].gap != Cell::Gap::FULL) return; // Only flood-fill through full gaps
185 colorGrid[x][y] = 1; // Outside color
186
187 FloodFillOutside(p, colorGrid, x, y+1);
188 FloodFillOutside(p, colorGrid, x, y-1);
189 FloodFillOutside(p, colorGrid, x+1, y);
190 FloodFillOutside(p, colorGrid, x-1, y);
191}
192 199
193/* 200 p.grid[2][1].gap = Cell::Gap::FULL;
194 undefined -> 1 (color of outside) or * (any colored cell) or -1 (edge/intersection not part of any region) 201 p.grid[1][2].gap = Cell::Gap::FULL;
202 p.grid[5][2].gap = Cell::Gap::FULL;
203 p.grid[7][4].gap = Cell::Gap::FULL;
204 p.grid[4][5].gap = Cell::Gap::FULL;
205 p.grid[6][5].gap = Cell::Gap::FULL;
206 p.grid[1][6].gap = Cell::Gap::FULL;
207 p.grid[2][7].gap = Cell::Gap::FULL;
208 p.grid[5][8].gap = Cell::Gap::FULL;
195 209
196 0 -> {} (this is a special edge case, which I don't need right now) 210 p.grid[0][8].start = true;
197 1 -> 0 (uncolored / ready to color) 211 p.grid[8][0].end = Cell::Dir::RIGHT;
198 2 ->
199*/
200std::vector<std::vector<int>> CreateColorGrid(const Puzzle& p) {
201 std::vector<std::vector<int>> colorGrid;
202 colorGrid.resize(p.width);
203 212
204 for (int x=0; x<p.width; x++) { 213 std::vector<Pos> cutEdges = Randomizer2Core::CutEdgesToBeUnique(p);
205 colorGrid[x].resize(p.height); 214 assert(cutEdges.size() == 7);
206 for (int y=0; y<p.height; y++) { 215 for (Pos pos : cutEdges) {
207 // Mark all unbroken edges and intersections as 'do not color' 216 p.grid[pos.x][pos.y].gap = Cell::Gap::FULL;
208 if (x%2 != y%2) { 217 }
209 if (p.grid[x][y].gap == Cell::Gap::NONE) colorGrid[x][y] = 1; 218 auto solutions = Solver::Solve(p);
210 } else if (x%2 == 0 && y%2 == 0) { 219 assert(solutions.size() == 1);
211 // @Future: What about empty intersections? 220
212 colorGrid[x][y] = 1; // do not color intersections 221 Puzzle q;
213 } 222 q.NewGrid(4, 4);
223 q.grid[0][8].start = true;
224 q.grid[8][0].end = Cell::Dir::RIGHT;
225 q.sequence = solutions[0].sequence;
226 for (Pos pos : cutEdges) {
227 q.grid[pos.x][pos.y].gap = Cell::Gap::FULL;
214 } 228 }
229 // Cut to 4 of 9 additional edges (total: 11)
230 Randomizer2Core::CutEdgesNotOutsideNotBreakingSequence(q, 4);
231 PuzzleSerializer(_memory).WritePuzzle(q, 0x19DC);
215 } 232 }
233
234 // *** Hedges 3 **
235 {
236 std::vector<int> audioMarkers = {
237 0x000034a9,
238 0x000034b1,
239 0x000034be,
240 0x000034c4,
241 0x000034cb,
242 0x000034cc,
243 0x000034cd,
244 0x000034ce,
245 0x000034df,
246 0x000034e0,
247 0x000034e1,
248 0x000034e2,
249 0x000034f3,
250 0x000131cb,
251 0x00017e34,
252 0x00017e6f,
253 0x00017e76,
254 0x00017e77,
255 0x00017e7a,
256 0x00017e7e,
257 0x00017e8b,
258 0x00017e8d,
259 0x00017eb5,
260 0x000394a4,
261 0x0003b54e,
262 };
263 std::vector<int> good;
264 for (int marker : audioMarkers) {
265 // std::vector<char> assetName = _memory->ReadArray<char>(marker, 0xD8, 100);
266 std::vector<char> name = {'m', 'a', 'z', 'e', '_', 'p', 'e', 'b', 'b', 'l', 'e', '\0'};
267 _memory->WriteNewArray(marker, 0xD8, name);
268 }
216 269
217 // @Future: Skip this loop if pillar = true; 270 Puzzle p;
218 for (int y=1; y<p.height; y+=2) { 271 p.NewGrid(4, 4);
219 FloodFillOutside(p, colorGrid, 0, y);
220 FloodFillOutside(p, colorGrid, p.width - 1, y);
221 }
222 272
223 for (int x=1; x<p.width; x+=2) { 273 p.grid[2][1].gap = Cell::Gap::FULL;
224 FloodFillOutside(p, colorGrid, x, 0); 274 p.grid[5][2].gap = Cell::Gap::FULL;
225 FloodFillOutside(p, colorGrid, x, p.height - 1); 275 p.grid[7][2].gap = Cell::Gap::FULL;
226 } 276 p.grid[4][3].gap = Cell::Gap::FULL;
277 p.grid[1][4].gap = Cell::Gap::FULL;
278 p.grid[6][5].gap = Cell::Gap::FULL;
279 p.grid[1][6].gap = Cell::Gap::FULL;
280 p.grid[3][6].gap = Cell::Gap::FULL;
281 p.grid[6][7].gap = Cell::Gap::FULL;
227 282
228 int color = 1; 283 p.grid[0][8].start = true;
229 for (int x=0; x<p.width; x++) { 284 p.grid[8][2].end = Cell::Dir::RIGHT;
230 for (int y=0; y<p.height; y++) { 285
231 if (colorGrid[x][y] != 0) continue; // No dead colors 286 std::vector<Pos> cutEdges = Randomizer2Core::CutEdgesToBeUnique(p);
232 color++; 287 assert(cutEdges.size() == 7);
233 FloodFill(p, colorGrid, color, x, y); 288 for (Pos pos : cutEdges) {
289 p.grid[pos.x][pos.y].gap = Cell::Gap::BREAK;
234 } 290 }
291 PuzzleSerializer(_memory).WritePuzzle(p, 0x19E7);
235 } 292 }
236 293
237 return colorGrid; 294 // *** Hedges 4 ***
238} 295 {
296 Puzzle p;
297 p.NewGrid(4, 4);
239 298
240void Randomizer2::RandomizeKeep() { 299 p.grid[3][0].gap = Cell::Gap::FULL;
241 Puzzle p; 300 p.grid[4][1].gap = Cell::Gap::FULL;
242 p.NewGrid(4, 4); 301 p.grid[8][1].gap = Cell::Gap::FULL;
243 // p.width = 9; 302 p.grid[1][2].gap = Cell::Gap::FULL;
244 // p.height = 10; 303 p.grid[4][3].gap = Cell::Gap::FULL;
245 // p.grid.clear(); 304 p.grid[8][3].gap = Cell::Gap::FULL;
246 // p.grid.resize(p.width); 305 p.grid[1][4].gap = Cell::Gap::FULL;
247 // for (int x=0; x<p.width; x++) p.grid[x].resize(p.height); 306 p.grid[5][4].gap = Cell::Gap::FULL;
248 307 p.grid[2][5].gap = Cell::Gap::FULL;
249 p.grid[2][1].gap = Cell::Gap::FULL; 308 p.grid[6][5].gap = Cell::Gap::FULL;
250 p.grid[4][1].gap = Cell::Gap::FULL; 309 p.grid[3][6].gap = Cell::Gap::FULL;
251 p.grid[6][1].gap = Cell::Gap::FULL; 310 p.grid[0][7].gap = Cell::Gap::FULL;
252 p.grid[3][2].gap = Cell::Gap::FULL; 311 p.grid[8][7].gap = Cell::Gap::FULL;
253 p.grid[5][2].gap = Cell::Gap::FULL; 312 p.grid[5][8].gap = Cell::Gap::FULL;
254 p.grid[8][3].gap = Cell::Gap::FULL;
255 p.grid[2][5].gap = Cell::Gap::FULL;
256 p.grid[6][5].gap = Cell::Gap::FULL;
257 p.grid[7][6].gap = Cell::Gap::FULL;
258 p.grid[2][7].gap = Cell::Gap::FULL;
259 p.grid[4][7].gap = Cell::Gap::FULL;
260 // p.grid[0][9].gap = Cell::Gap::FULL;
261 // p.grid[2][9].gap = Cell::Gap::FULL;
262 // p.grid[6][9].gap = Cell::Gap::FULL;
263 // p.grid[8][9].gap = Cell::Gap::FULL;
264
265 p.grid[6][0].end = Cell::Dir::UP;
266 p.grid[4][8].start = true;
267
268 auto colorGrid = CreateColorGrid(p);
269
270 std::vector<Pos> edges;
271 for (int x=0; x<p.width; x++) {
272 for (int y=0; y<p.height; y++) {
273 if (x%2 == y%2) continue;
274 if (p.grid[x][y].gap != Cell::Gap::NONE) continue;
275 edges.emplace_back(Pos{x, y});
276 }
277 }
278 313
279 Puzzle copy = p; 314 p.grid[0][8].start = true;
280 std::vector<int> gates = {0x00344, 0x00488, 0x00489, 0x00495, 0x00496}; 315 p.grid[4][0].end = Cell::Dir::UP;
281 for (int i=0; i<5; i++) { 316
282 for (int j=0; j<edges.size(); j++) { 317 std::vector<Pos> cutEdges = Randomizer2Core::CutEdgesToBeUnique(p);
283 int edge = Random::RandInt(0, static_cast<int>(edges.size() - 1)); 318 assert(cutEdges.size() == 2);
284 Pos pos = edges[edge]; 319 for (Pos pos : cutEdges) {
285 edges.erase(edges.begin() + edge); 320 p.grid[pos.x][pos.y].gap = Cell::Gap::FULL;
286
287 int color1 = 0;
288 int color2 = 0;
289 if (pos.x%2 == 0 && pos.y%2 == 1) { // Vertical
290 if (pos.x > 0) color1 = colorGrid[pos.x-1][pos.y];
291 else color1 = 1;
292
293 if (pos.x < p.width - 1) color2 = colorGrid[pos.x+1][pos.y];
294 else color2 = 1;
295 } else { // Horizontal
296 assert(pos.x%2 == 1 && pos.y%2 == 0);
297 if (pos.y > 0) color1 = colorGrid[pos.x][pos.y-1];
298 else color1 = 1;
299
300 if (pos.y < p.height - 1) color2 = colorGrid[pos.x][pos.y+1];
301 else color2 = 1;
302 }
303 // Enforce color1 < color2
304 if (color1 > color2) std::swap(color1, color2);
305
306 // Colors mismatch, valid cut
307 if (color1 != color2) {
308 // @Performance... have a lookup table instead?
309 for (int x=0; x<p.width; x++) {
310 for (int y=0; y<p.height; y++) {
311 if (colorGrid[x][y] == color2) colorGrid[x][y] = color1;
312 }
313 }
314 copy.grid[pos.x][pos.y].gap = Cell::Gap::BREAK;
315 SetGate(gates[i], pos.x, pos.y);
316 break;
317 }
318 } 321 }
322 auto solutions = Solver::Solve(p);
323 assert(solutions.size() == 1);
324
325 Puzzle q;
326 q.NewGrid(4, 4);
327 q.grid[0][8].start = true;
328 q.grid[4][0].end = Cell::Dir::UP;
329 q.sequence = solutions[0].sequence;
330 for (Pos pos : cutEdges) {
331 q.grid[pos.x][pos.y].gap = Cell::Gap::FULL;
332 }
333 // 9 cuts, -2 from existing cuts
334 Randomizer2Core::CutEdgesNotOutsideNotBreakingSequence(q, 7);
335 PuzzleSerializer(_memory).WritePuzzle(q, 0x1A0F);
319 } 336 }
320
321 auto solutions = Solver::Solve(copy);
322 assert(solutions.size() == 1);
323 p.sequence = solutions[0].sequence;
324 PuzzleSerializer(_memory).WritePuzzle(solutions[0], 0x139);
325} 337}
326 338
327void Randomizer2::SetGate(int panel, int X, int Y) { 339void Randomizer2::SetGate(int panel, int X, int Y) {