about summary refs log tree commit diff stats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/Memory.cpp3
-rw-r--r--Source/Memory.h8
-rw-r--r--Source/Randomizer2.cpp187
-rw-r--r--Source/Randomizer2.h3
-rw-r--r--Source/Solver.cpp2
-rw-r--r--Source/Solver.h5
6 files changed, 164 insertions, 44 deletions
diff --git a/Source/Memory.cpp b/Source/Memory.cpp index c3b89d0..98b06f9 100644 --- a/Source/Memory.cpp +++ b/Source/Memory.cpp
@@ -152,7 +152,8 @@ int Memory::ExecuteSigScans()
152 152
153void Memory::ThrowError() { 153void Memory::ThrowError() {
154 std::wstring message(256, '\0'); 154 std::wstring message(256, '\0');
155 int length = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(), 1024, &message[0], static_cast<DWORD>(message.size()), nullptr); 155 DWORD error = GetLastError();
156 int length = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, error, 1024, &message[0], static_cast<DWORD>(message.size()), nullptr);
156 message.resize(length); 157 message.resize(length);
157#ifndef NDEBUG 158#ifndef NDEBUG
158 MessageBox(NULL, message.c_str(), L"Please tell darkid about this", MB_OK); 159 MessageBox(NULL, message.c_str(), L"Please tell darkid about this", MB_OK);
diff --git a/Source/Memory.h b/Source/Memory.h index 95de884..6b8403f 100644 --- a/Source/Memory.h +++ b/Source/Memory.h
@@ -5,8 +5,8 @@
5#include <vector> 5#include <vector>
6#include <windows.h> 6#include <windows.h>
7 7
8// #define GLOBALS 0x5B28C0 8#define GLOBALS 0x5B28C0
9#define GLOBALS 0x62D0A0 9// #define GLOBALS 0x62D0A0
10 10
11#define HEARTBEAT 0x401 11#define HEARTBEAT 0x401
12enum class ProcStatus { 12enum class ProcStatus {
@@ -102,6 +102,8 @@ private:
102}; 102};
103 103
104#if GLOBALS == 0x5B28C0 104#if GLOBALS == 0x5B28C0
105#define POSITION 0x24
106#define ORIENTATION 0x34
105#define PATH_COLOR 0xC8 107#define PATH_COLOR 0xC8
106#define REFLECTION_PATH_COLOR 0xD8 108#define REFLECTION_PATH_COLOR 0xD8
107#define DOT_COLOR 0xF8 109#define DOT_COLOR 0xF8
@@ -169,6 +171,8 @@ private:
169#define METADATA 0xF2 // sizeof(short) 171#define METADATA 0xF2 // sizeof(short)
170#define HOTEL_EP_NAME 0x4BC640 172#define HOTEL_EP_NAME 0x4BC640
171#elif GLOBALS == 0x62D0A0 173#elif GLOBALS == 0x62D0A0
174#define POSITION #error
175#define ORIENTATION #error
172#define PATH_COLOR 0xC0 176#define PATH_COLOR 0xC0
173#define REFLECTION_PATH_COLOR 0xD0 177#define REFLECTION_PATH_COLOR 0xD0
174#define DOT_COLOR 0xF0 178#define DOT_COLOR 0xF0
diff --git a/Source/Randomizer2.cpp b/Source/Randomizer2.cpp index fcfec9a..537c30b 100644 --- a/Source/Randomizer2.cpp +++ b/Source/Randomizer2.cpp
@@ -2,6 +2,38 @@
2#include "Puzzle.h" 2#include "Puzzle.h"
3#include "Random.h" 3#include "Random.h"
4#include "Solver.h" 4#include "Solver.h"
5#include "Memory.h"
6
7void FloodFillInternal(const Puzzle& p, std::vector<std::vector<bool>>& reached, int x, int y) {
8 if (x%2 == 1 && y%2 == 1) return;
9 auto cell = p.GetCell(x, y);
10 if (cell.undefined) return;
11 if (cell.gap != Cell::Gap::NONE) return;
12 if (reached[x][y]) return;
13
14 reached[x][y] = true;
15 FloodFillInternal(p, reached, x-1, y);
16 FloodFillInternal(p, reached, x+1, y);
17 FloodFillInternal(p, reached, x, y-1);
18 FloodFillInternal(p, reached, x, y+1);
19}
20
21// Returns true: All nodes reachable / false: Some node disconnected
22bool FloodFill(const Puzzle& p) {
23 std::vector<std::vector<bool>> reached;
24 reached.resize(p.width);
25 for (int x=0; x<p.width; x++) reached[x].resize(p.height);
26 FloodFillInternal(p, reached, 0, 0);
27
28 for (int x=0; x<p.width; x++) {
29 for (int y=0; y<p.height; y++) {
30 if (x%2 == 0 && y%2 == 0) { // @Specialized
31 if (!reached[x][y]) return false;
32 }
33 }
34 }
35 return true;
36}
5 37
6Randomizer2::Randomizer2(const std::shared_ptr<Memory>& memory) : _memory(memory) {} 38Randomizer2::Randomizer2(const std::shared_ptr<Memory>& memory) : _memory(memory) {}
7 39
@@ -12,9 +44,7 @@ void Randomizer2::Randomize() {
12 // end (x=8, y=0) Up 44 // end (x=8, y=0) Up
13 // 1 solution 45 // 1 solution
14 Puzzle p; 46 Puzzle p;
15 int attemptCount = 0;
16 while (true) { 47 while (true) {
17 attemptCount++;
18 p.NewGrid(4, 4); 48 p.NewGrid(4, 4);
19 49
20 std::vector<Pos> corners; 50 std::vector<Pos> corners;
@@ -29,40 +59,34 @@ void Randomizer2::Randomize() {
29 } 59 }
30 60
31 for (int i=0; i<14; i++) { 61 for (int i=0; i<14; i++) {
32 int edge = Random::RandInt(0, static_cast<int>(edges.size() - 1)); 62 for (int j=0; j<edges.size(); j++) {
33 Pos pos = edges[edge]; 63 int edge = Random::RandInt(0, static_cast<int>(edges.size() - 1));
34 p.grid[pos.x][pos.y].gap = Cell::Gap::FULL; 64 Pos pos = edges[edge];
35 edges.erase(edges.begin() + edge); 65 p.grid[pos.x][pos.y].gap = Cell::Gap::FULL;
66 edges.erase(edges.begin() + edge);
67
68 if (FloodFill(p)) {
69 break;
70 } else {
71 p.grid[pos.x][pos.y].gap = Cell::Gap::NONE;
72 }
73 }
36 } 74 }
37 75
38 p.grid[0][8].start = true; 76 p.grid[0][8].start = true;
39 p.grid[8][0].end = Cell::Dir::UP; 77 p.grid[8][0].end = Cell::Dir::UP;
40 78
41 auto solutions = Solver::Solve(p); 79 auto solutions = Solver::Solve(p);
42 if (solutions.size() == 1) { 80 if (solutions.size() > 0) break;
43 auto solution = solutions[0];
44 int solutionLength = 0;
45 for (int x=0; x<solution.width; x++) {
46 for (int y=0; y<solution.height; y++) {
47 if (solution.grid[x][y].color == Cell::Color::BLACK) solutionLength++;
48 }
49 }
50 if (solutionLength == 25) break;
51 }
52 } 81 }
53 PuzzleSerializer(_memory).WritePuzzle(p, 0x293); 82 PuzzleSerializer(_memory).WritePuzzle(p, 0x293);
54 83
55
56
57
58 // 7x7 84 // 7x7
59 // 35 gaps 85 // 35 gaps
60 // start (x=8, y=8) 86 // start (x=8, y=8)
61 // end (x=4, y=0) Up 87 // end (x=4, y=0) Up
62 // 2 solutions, 37 & 39 88 // 2 solutions, 37 & 39
63 attemptCount = 0;
64 while (true) { 89 while (true) {
65 attemptCount++;
66 p.NewGrid(7, 7); 90 p.NewGrid(7, 7);
67 91
68 std::vector<Pos> corners; 92 std::vector<Pos> corners;
@@ -77,28 +101,117 @@ void Randomizer2::Randomize() {
77 } 101 }
78 102
79 for (int i=0; i<35; i++) { 103 for (int i=0; i<35; i++) {
80 int edge = Random::RandInt(0, static_cast<int>(edges.size() - 1)); 104 for (int j=0; j<edges.size(); j++) {
81 Pos pos = edges[edge]; 105 // TODO: Precompute edge weights and make a weighted cut.
82 p.grid[pos.x][pos.y].gap = Cell::Gap::FULL; 106 // This will also preclude the need for flood filling.
83 edges.erase(edges.begin() + edge); 107 // https://en.wikipedia.org/wiki/Biconnected_component
108
109 int edge = Random::RandInt(0, static_cast<int>(edges.size() - 1));
110 Pos pos = edges[edge];
111 p.grid[pos.x][pos.y].gap = Cell::Gap::FULL;
112 edges.erase(edges.begin() + edge);
113
114 if (FloodFill(p)) {
115 break;
116 } else {
117 p.grid[pos.x][pos.y].gap = Cell::Gap::NONE;
118 }
119 }
84 } 120 }
85 121
86 p.grid[8][8].start = true; 122 switch (Random::RandInt(1, 4)) {
87 p.grid[4][0].end = Cell::Dir::UP; 123 case 1:
124 p.grid[Random::RandInt(0, p.width-1)][0].end = Cell::Dir::UP;
125 break;
126 case 2:
127 p.grid[Random::RandInt(0, p.width-1)][p.height-1].end = Cell::Dir::DOWN;
128 break;
129 case 3:
130 p.grid[0][Random::RandInt(0, p.height-1)].end = Cell::Dir::LEFT;
131 break;
132 case 4:
133 p.grid[p.width-1][Random::RandInt(0, p.height-1)].end = Cell::Dir::RIGHT;
134 break;
135 }
136 switch (Random::RandInt(1, 3)) {
137 case 1: // Horiz (6) [5/7][4/6/8]
138 p.grid[Random::RandInt(0, 1)*2 + 5][Random::RandInt(0, 2)*2 + 4].start = true;
139 break;
140 case 2: // Verti (6) [4/6/8][5/7]
141 p.grid[Random::RandInt(0, 2)*2 + 4][Random::RandInt(0, 1)*2 + 5].start = true;
142 break;
143 case 3: // Inter (9) [4/6/8][4/6/8]
144 p.grid[Random::RandInt(0, 2)*2 + 4][Random::RandInt(0, 2)*2 + 4].start = true;
145 break;
146 }
88 147
89 auto solutions = Solver::Solve(p); 148 auto solutions = Solver::Solve(p);
90 if (solutions.size() > 0) break; 149 if (solutions.size() > 0) break;
91 if (solutions.size() > 0 && solutions.size() < 5) {
92 auto solution = solutions[0];
93 int solutionLength = 0;
94 for (int x=0; x<solution.width; x++) {
95 for (int y=0; y<solution.height; y++) {
96 if (solution.grid[x][y].color == Cell::Color::BLACK) solutionLength++;
97 }
98 }
99 if (solutionLength > 30 && solutionLength < 40) break;
100 }
101 } 150 }
102 PuzzleSerializer(_memory).WritePuzzle(p, 0x295); 151 PuzzleSerializer(_memory).WritePuzzle(p, 0x295);
103 152
104} 153}
154
155void Randomizer2::RandomizeKeep() {
156 Puzzle p;
157 p.width = 9;
158 p.height = 10;
159 p.grid.clear();
160 p.grid.resize(p.width);
161 for (int x=0; x<p.width; x++) p.grid[x].resize(p.height);
162
163 p.NewGrid(5, 5);
164 p.grid[2][1].gap = Cell::Gap::FULL;
165 p.grid[4][1].gap = Cell::Gap::FULL;
166 p.grid[6][1].gap = Cell::Gap::FULL;
167 p.grid[8][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 p.grid[0][9].gap = Cell::Gap::FULL;
177 p.grid[2][9].gap = Cell::Gap::FULL;
178 p.grid[6][9].gap = Cell::Gap::FULL;
179 p.grid[8][9].gap = Cell::Gap::FULL;
180
181 p.grid[8][0].end = Cell::Dir::UP;
182 p.grid[4][9].start = true;
183
184 // 0x00496
185 // 0x00344
186 // 0x00495
187 // 0x00488
188 // 0x00489
189
190 SetGate(0x00496, 2, 1);
191}
192
193void Randomizer2::SetGate(int panel, int X, int Y) {
194 // x: (-1.5)X + (0.7)Y + 67.1
195 // y: (0.3)X + (1.5)Y + 106.9
196 // z: -19.1
197 // Horizontal: (0, 0, -.1, 1)
198 // Vertical: (0, 0, -.77, .63)
199
200 float x = -1.5f * X + 0.7f * Y + 67.1f;
201 float y = 0.3f * X + 1.5f * Y + 106.9f;
202 _memory->WritePanelData<float>(panel, POSITION, {x, y, 19.1f});
203
204 float z, w;
205 if (X%2 == 0 && Y%2 == 1) { // Horizontal
206 z = -0.1f;
207 w = 1.0f;
208 } else if (X%2 == 1 && Y%2 == 0) { // Vertical
209 z = -.77f;
210 w = .63f;
211 } else {
212 assert(false);
213 return;
214 }
215
216 _memory->WritePanelData<float>(panel, ORIENTATION, {0.0f, 0.0f, z, w});
217} \ No newline at end of file
diff --git a/Source/Randomizer2.h b/Source/Randomizer2.h index 1aeae11..848fd22 100644 --- a/Source/Randomizer2.h +++ b/Source/Randomizer2.h
@@ -6,7 +6,10 @@ class Randomizer2 {
6public: 6public:
7 Randomizer2(const std::shared_ptr<Memory>& memory); 7 Randomizer2(const std::shared_ptr<Memory>& memory);
8 void Randomize(); 8 void Randomize();
9 void RandomizeKeep();
9 10
10private: 11private:
12 void SetGate(int panel, int X, int Y);
13
11 std::shared_ptr<Memory> _memory; 14 std::shared_ptr<Memory> _memory;
12}; 15};
diff --git a/Source/Solver.cpp b/Source/Solver.cpp index 244bfb2..bce1482 100644 --- a/Source/Solver.cpp +++ b/Source/Solver.cpp
@@ -2,6 +2,8 @@
2#include "Puzzle.h" 2#include "Puzzle.h"
3#include "Validator.h" 3#include "Validator.h"
4 4
5int Solver::MAX_SOLUTIONS = 10000;
6
5std::vector<Puzzle> Solver::Solve(Puzzle& p) { 7std::vector<Puzzle> Solver::Solve(Puzzle& p) {
6 std::vector<Puzzle> solutions; 8 std::vector<Puzzle> solutions;
7 // var start = (new Date()).getTime() 9 // var start = (new Date()).getTime()
diff --git a/Source/Solver.h b/Source/Solver.h index 09108c7..455d1eb 100644 --- a/Source/Solver.h +++ b/Source/Solver.h
@@ -1,13 +1,10 @@
1#pragma once 1#pragma once
2#include <vector> 2#include <vector>
3 3
4#ifndef MAX_SOLUTIONS
5#define MAX_SOLUTIONS 10000
6#endif
7
8class Puzzle; 4class Puzzle;
9class Solver { 5class Solver {
10public: 6public:
7 static int MAX_SOLUTIONS;
11 static std::vector<Puzzle> Solve(Puzzle& p); 8 static std::vector<Puzzle> Solve(Puzzle& p);
12 9
13private: 10private: