diff options
author | Star Rauchenberger <fefferburbia@gmail.com> | 2023-10-27 17:20:23 -0400 |
---|---|---|
committer | Star Rauchenberger <fefferburbia@gmail.com> | 2023-10-27 17:20:23 -0400 |
commit | 4f25fa9ae42a0d43c20e954e8e50c66a6b057c92 (patch) | |
tree | 6cdfc57f5e1f54d025610757efb0ec57c3b88b0b /ext/wittle_generator | |
parent | dde56d26837dc52e05207c0672b3c4a1046f6cb2 (diff) | |
download | wittle-4f25fa9ae42a0d43c20e954e8e50c66a6b057c92.tar.gz wittle-4f25fa9ae42a0d43c20e954e8e50c66a6b057c92.tar.bz2 wittle-4f25fa9ae42a0d43c20e954e8e50c66a6b057c92.zip |
We can output a code for witnesspuzzles
Diffstat (limited to 'ext/wittle_generator')
-rw-r--r-- | ext/wittle_generator/Base64.h | 127 | ||||
-rw-r--r-- | ext/wittle_generator/CMakeLists.txt | 2 | ||||
-rw-r--r-- | ext/wittle_generator/Generate.cpp | 57 | ||||
-rw-r--r-- | ext/wittle_generator/Generate.h | 2 | ||||
-rw-r--r-- | ext/wittle_generator/Panel.cpp | 110 | ||||
-rw-r--r-- | ext/wittle_generator/Panel.h | 10 | ||||
-rw-r--r-- | ext/wittle_generator/Serializer.cpp | 135 | ||||
-rw-r--r-- | ext/wittle_generator/Serializer.h | 76 | ||||
-rw-r--r-- | ext/wittle_generator/Test.cpp | 7 |
9 files changed, 506 insertions, 20 deletions
diff --git a/ext/wittle_generator/Base64.h b/ext/wittle_generator/Base64.h new file mode 100644 index 0000000..2f30c1a --- /dev/null +++ b/ext/wittle_generator/Base64.h | |||
@@ -0,0 +1,127 @@ | |||
1 | #ifndef _MACARON_BASE64_H_ | ||
2 | #define _MACARON_BASE64_H_ | ||
3 | |||
4 | /** | ||
5 | * The MIT License (MIT) | ||
6 | * Copyright (c) 2016 tomykaira | ||
7 | * | ||
8 | * Permission is hereby granted, free of charge, to any person obtaining | ||
9 | * a copy of this software and associated documentation files (the | ||
10 | * "Software"), to deal in the Software without restriction, including | ||
11 | * without limitation the rights to use, copy, modify, merge, publish, | ||
12 | * distribute, sublicense, and/or sell copies of the Software, and to | ||
13 | * permit persons to whom the Software is furnished to do so, subject to | ||
14 | * the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be | ||
17 | * included in all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
20 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
21 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
22 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
23 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
24 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
25 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | #include <string> | ||
29 | |||
30 | namespace macaron { | ||
31 | |||
32 | class Base64 { | ||
33 | public: | ||
34 | static std::string Encode(const std::string data) { | ||
35 | static constexpr char sEncodingTable[] = { | ||
36 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', | ||
37 | 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', | ||
38 | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', | ||
39 | 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', | ||
40 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; | ||
41 | |||
42 | size_t in_len = data.size(); | ||
43 | size_t out_len = 4 * ((in_len + 2) / 3); | ||
44 | std::string ret(out_len, '\0'); | ||
45 | size_t i; | ||
46 | char* p = const_cast<char*>(ret.c_str()); | ||
47 | |||
48 | for (i = 0; i < in_len - 2; i += 3) { | ||
49 | *p++ = sEncodingTable[(data[i] >> 2) & 0x3F]; | ||
50 | *p++ = sEncodingTable[((data[i] & 0x3) << 4) | | ||
51 | ((int)(data[i + 1] & 0xF0) >> 4)]; | ||
52 | *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2) | | ||
53 | ((int)(data[i + 2] & 0xC0) >> 6)]; | ||
54 | *p++ = sEncodingTable[data[i + 2] & 0x3F]; | ||
55 | } | ||
56 | if (i < in_len) { | ||
57 | *p++ = sEncodingTable[(data[i] >> 2) & 0x3F]; | ||
58 | if (i == (in_len - 1)) { | ||
59 | *p++ = sEncodingTable[((data[i] & 0x3) << 4)]; | ||
60 | *p++ = '='; | ||
61 | } else { | ||
62 | *p++ = sEncodingTable[((data[i] & 0x3) << 4) | | ||
63 | ((int)(data[i + 1] & 0xF0) >> 4)]; | ||
64 | *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2)]; | ||
65 | } | ||
66 | *p++ = '='; | ||
67 | } | ||
68 | |||
69 | return ret; | ||
70 | } | ||
71 | |||
72 | static std::string Decode(const std::string& input, std::string& out) { | ||
73 | static constexpr unsigned char kDecodingTable[] = { | ||
74 | 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, | ||
75 | 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, | ||
76 | 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, 52, 53, 54, 55, 56, 57, | ||
77 | 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, 64, 0, 1, 2, 3, 4, 5, 6, | ||
78 | 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, | ||
79 | 25, 64, 64, 64, 64, 64, 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, | ||
80 | 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, | ||
81 | 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, | ||
82 | 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, | ||
83 | 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, | ||
84 | 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, | ||
85 | 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, | ||
86 | 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, | ||
87 | 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, | ||
88 | 64, 64, 64, 64}; | ||
89 | |||
90 | size_t in_len = input.size(); | ||
91 | if (in_len % 4 != 0) return "Input data size is not a multiple of 4"; | ||
92 | |||
93 | size_t out_len = in_len / 4 * 3; | ||
94 | if (input[in_len - 1] == '=') out_len--; | ||
95 | if (input[in_len - 2] == '=') out_len--; | ||
96 | |||
97 | out.resize(out_len); | ||
98 | |||
99 | for (size_t i = 0, j = 0; i < in_len;) { | ||
100 | uint32_t a = input[i] == '=' | ||
101 | ? 0 & i++ | ||
102 | : kDecodingTable[static_cast<int>(input[i++])]; | ||
103 | uint32_t b = input[i] == '=' | ||
104 | ? 0 & i++ | ||
105 | : kDecodingTable[static_cast<int>(input[i++])]; | ||
106 | uint32_t c = input[i] == '=' | ||
107 | ? 0 & i++ | ||
108 | : kDecodingTable[static_cast<int>(input[i++])]; | ||
109 | uint32_t d = input[i] == '=' | ||
110 | ? 0 & i++ | ||
111 | : kDecodingTable[static_cast<int>(input[i++])]; | ||
112 | |||
113 | uint32_t triple = | ||
114 | (a << 3 * 6) + (b << 2 * 6) + (c << 1 * 6) + (d << 0 * 6); | ||
115 | |||
116 | if (j < out_len) out[j++] = (triple >> 2 * 8) & 0xFF; | ||
117 | if (j < out_len) out[j++] = (triple >> 1 * 8) & 0xFF; | ||
118 | if (j < out_len) out[j++] = (triple >> 0 * 8) & 0xFF; | ||
119 | } | ||
120 | |||
121 | return ""; | ||
122 | } | ||
123 | }; | ||
124 | |||
125 | } // namespace macaron | ||
126 | |||
127 | #endif /* _MACARON_BASE64_H_ */ | ||
diff --git a/ext/wittle_generator/CMakeLists.txt b/ext/wittle_generator/CMakeLists.txt index 236cc83..561e78a 100644 --- a/ext/wittle_generator/CMakeLists.txt +++ b/ext/wittle_generator/CMakeLists.txt | |||
@@ -1,6 +1,6 @@ | |||
1 | cmake_minimum_required (VERSION 3.1) | 1 | cmake_minimum_required (VERSION 3.1) |
2 | project (wittle_generator) | 2 | project (wittle_generator) |
3 | 3 | ||
4 | add_executable(wittle_generator Generate.cpp Panel.cpp Random.cpp Test.cpp) | 4 | add_executable(wittle_generator Generate.cpp Panel.cpp Random.cpp Serializer.cpp Test.cpp) |
5 | set_property(TARGET wittle_generator PROPERTY CXX_STANDARD 17) | 5 | set_property(TARGET wittle_generator PROPERTY CXX_STANDARD 17) |
6 | set_property(TARGET wittle_generator PROPERTY CXX_STANDARD_REQUIRED ON) | 6 | set_property(TARGET wittle_generator PROPERTY CXX_STANDARD_REQUIRED ON) |
diff --git a/ext/wittle_generator/Generate.cpp b/ext/wittle_generator/Generate.cpp index 22c211f..5776386 100644 --- a/ext/wittle_generator/Generate.cpp +++ b/ext/wittle_generator/Generate.cpp | |||
@@ -55,6 +55,33 @@ void Generate::initPanel() { | |||
55 | init_treehouse_layout(); | 55 | init_treehouse_layout(); |
56 | } | 56 | } |
57 | 57 | ||
58 | if (_custom_grid.size() > | ||
59 | 0) { // If we want to start with a certain default grid when generating | ||
60 | if (_custom_grid.size() < _panel->width()) { | ||
61 | _custom_grid.resize(_panel->width()); | ||
62 | } | ||
63 | if (_custom_grid[_custom_grid.size() - 1].size() < _panel->height()) { | ||
64 | for (auto& row : _custom_grid) { | ||
65 | row.resize(_panel->height()); | ||
66 | } | ||
67 | } | ||
68 | for (int x = 0; x < _panel->width(); x++) { | ||
69 | for (int y = 0; y < _panel->height(); y++) { | ||
70 | set(x, y, _custom_grid[x][y]); | ||
71 | } | ||
72 | } | ||
73 | } | ||
74 | // Sync up start/exit points between panel and generator. If both are | ||
75 | // different, the generator's start/exit point list will be used | ||
76 | for (Point e : _starts) { | ||
77 | _panel->SetGridSymbol(e.first, e.second, Decoration::Start, | ||
78 | Decoration::Color::None); | ||
79 | } | ||
80 | for (Point e : _exits) { | ||
81 | _panel->SetGridSymbol(e.first, e.second, Decoration::Exit, | ||
82 | Decoration::Color::None); | ||
83 | } | ||
84 | |||
58 | // Fill gridpos with every available grid block | 85 | // Fill gridpos with every available grid block |
59 | _gridpos.clear(); | 86 | _gridpos.clear(); |
60 | for (int x = 1; x < _panel->width(); x += 2) { | 87 | for (int x = 1; x < _panel->width(); x += 2) { |
@@ -503,6 +530,9 @@ bool Generate::generateInternal(int width, int height, PuzzleSymbols symbols) { | |||
503 | std::cout << row << std::endl; | 530 | std::cout << row << std::endl; |
504 | } | 531 | } |
505 | 532 | ||
533 | erase_path(); | ||
534 | std::cout << _panel->Write() << std::endl; | ||
535 | |||
506 | return true; | 536 | return true; |
507 | } | 537 | } |
508 | 538 | ||
@@ -944,12 +974,14 @@ bool Generate::place_start(int amount) { | |||
944 | } | 974 | } |
945 | if (adjacent && Random::rand() % 10 > 0) continue; | 975 | if (adjacent && Random::rand() % 10 > 0) continue; |
946 | _starts.insert(pos); | 976 | _starts.insert(pos); |
947 | set(pos.first, pos.second, Decoration::Start | Decoration::Color::None); | 977 | _panel->SetGridSymbol(pos.first, pos.second, Decoration::Start, |
978 | Decoration::Color::None); | ||
948 | amount--; | 979 | amount--; |
949 | if (_panel->symmetry) { | 980 | if (_panel->symmetry) { |
950 | Point sp = get_sym_point(pos); | 981 | Point sp = get_sym_point(pos); |
951 | _starts.insert(sp); | 982 | _starts.insert(sp); |
952 | set(sp.first, sp.second, Decoration::Start | Decoration::Color::None); | 983 | _panel->SetGridSymbol(sp.first, sp.second, Decoration::Start, |
984 | Decoration::Color::None); | ||
953 | } | 985 | } |
954 | } | 986 | } |
955 | return true; | 987 | return true; |
@@ -994,12 +1026,14 @@ bool Generate::place_exit(int amount) { | |||
994 | } | 1026 | } |
995 | if (adjacent) continue; | 1027 | if (adjacent) continue; |
996 | _exits.insert(pos); | 1028 | _exits.insert(pos); |
997 | set(pos.first, pos.second, Decoration::Exit | Decoration::Color::None); | 1029 | _panel->SetGridSymbol(pos.first, pos.second, Decoration::Exit, |
1030 | Decoration::Color::None); | ||
998 | amount--; | 1031 | amount--; |
999 | if (_panel->symmetry) { | 1032 | if (_panel->symmetry) { |
1000 | Point sp = get_sym_point(pos); | 1033 | Point sp = get_sym_point(pos); |
1001 | _exits.insert(sp); | 1034 | _exits.insert(sp); |
1002 | set(sp.first, sp.second, Decoration::Exit | Decoration::Color::None); | 1035 | _panel->SetGridSymbol(sp.first, sp.second, Decoration::Exit, |
1036 | Decoration::Color::None); | ||
1003 | } | 1037 | } |
1004 | } | 1038 | } |
1005 | return true; | 1039 | return true; |
@@ -1123,8 +1157,7 @@ bool Generate::can_place_dot(Point pos, bool intersectionOnly) { | |||
1123 | } | 1157 | } |
1124 | 1158 | ||
1125 | // Place the given amount of dots at random points on the path | 1159 | // Place the given amount of dots at random points on the path |
1126 | bool Generate::place_dots(int amount, Decoration::Color color, | 1160 | bool Generate::place_dots(int amount, int color, bool intersectionOnly) { |
1127 | bool intersectionOnly) { | ||
1128 | if (_parity != -1) { // For full dot puzzles, don't put dots on the starts | 1161 | if (_parity != -1) { // For full dot puzzles, don't put dots on the starts |
1129 | // and exits unless there are multiple | 1162 | // and exits unless there are multiple |
1130 | for (int x = 0; x < _panel->width(); x += 2) { | 1163 | for (int x = 0; x < _panel->width(); x += 2) { |
@@ -1141,19 +1174,17 @@ bool Generate::place_dots(int amount, Decoration::Color color, | |||
1141 | setFlagOnce(Config::DisableDotIntersection); | 1174 | setFlagOnce(Config::DisableDotIntersection); |
1142 | } | 1175 | } |
1143 | 1176 | ||
1144 | /*if (color == Decoration::Color::Blue || color == Decoration::Color::Cyan) | 1177 | if (color == Decoration::Color::Blue || color == Decoration::Color::Cyan) |
1145 | color = IntersectionFlags::DOT_IS_BLUE; | 1178 | color = IntersectionFlags::DOT_IS_BLUE; |
1146 | else if (color == Decoration::Color::Yellow || | 1179 | else if (color == Decoration::Color::Yellow || |
1147 | color == Decoration::Color::Orange) | 1180 | color == Decoration::Color::Orange) |
1148 | color = IntersectionFlags::DOT_IS_ORANGE; | 1181 | color = IntersectionFlags::DOT_IS_ORANGE; |
1149 | else | 1182 | else |
1150 | color = 0;*/ | 1183 | color = 0; |
1151 | 1184 | ||
1152 | std::set<Point> open = | 1185 | std::set<Point> open = (color == 0 ? _path |
1153 | (color == 0 ? _path | 1186 | : (color == IntersectionFlags::DOT_IS_BLUE) ? _path1 |
1154 | : (color == Decoration::Color::Blue || color == Decoration::Color::Cyan) | 1187 | : _path2); |
1155 | ? _path1 | ||
1156 | : _path2); | ||
1157 | for (Point p : _starts) open.erase(p); | 1188 | for (Point p : _starts) open.erase(p); |
1158 | for (Point p : _exits) open.erase(p); | 1189 | for (Point p : _exits) open.erase(p); |
1159 | for (Point p : blockPos) open.erase(p); | 1190 | for (Point p : blockPos) open.erase(p); |
diff --git a/ext/wittle_generator/Generate.h b/ext/wittle_generator/Generate.h index c28a47d..e37c2fd 100644 --- a/ext/wittle_generator/Generate.h +++ b/ext/wittle_generator/Generate.h | |||
@@ -175,7 +175,7 @@ class Generate { | |||
175 | bool can_place_gap(Point pos); | 175 | bool can_place_gap(Point pos); |
176 | bool place_gaps(int amount); | 176 | bool place_gaps(int amount); |
177 | bool can_place_dot(Point pos, bool intersectionOnly); | 177 | bool can_place_dot(Point pos, bool intersectionOnly); |
178 | bool place_dots(int amount, Decoration::Color color, bool intersectionOnly); | 178 | bool place_dots(int amount, int color, bool intersectionOnly); |
179 | bool can_place_stone(const std::set<Point>& region, int color); | 179 | bool can_place_stone(const std::set<Point>& region, int color); |
180 | bool place_stones(int color, int amount); | 180 | bool place_stones(int color, int amount); |
181 | Shape generate_shape(std::set<Point>& region, std::set<Point>& bufferRegion, | 181 | Shape generate_shape(std::set<Point>& region, std::set<Point>& bufferRegion, |
diff --git a/ext/wittle_generator/Panel.cpp b/ext/wittle_generator/Panel.cpp index a005467..54c7283 100644 --- a/ext/wittle_generator/Panel.cpp +++ b/ext/wittle_generator/Panel.cpp | |||
@@ -3,6 +3,8 @@ | |||
3 | #include <fstream> | 3 | #include <fstream> |
4 | #include <sstream> | 4 | #include <sstream> |
5 | 5 | ||
6 | #include "Serializer.h" | ||
7 | |||
6 | template <class T> | 8 | template <class T> |
7 | int find(const std::vector<T>& data, T search, size_t startIndex = 0) { | 9 | int find(const std::vector<T>& data, T search, size_t startIndex = 0) { |
8 | for (size_t i = startIndex; i < data.size(); i++) { | 10 | for (size_t i = startIndex; i < data.size(); i++) { |
@@ -114,3 +116,111 @@ void Panel::Resize(int width, int height) { | |||
114 | for (auto& row : _grid) row.resize(height); | 116 | for (auto& row : _grid) row.resize(height); |
115 | _resized = true; | 117 | _resized = true; |
116 | } | 118 | } |
119 | |||
120 | std::string Panel::Write() { | ||
121 | Serializer serializer; | ||
122 | serializer.writeInt(SERIALIZER_VERSION); | ||
123 | serializer.writeByte(_width); | ||
124 | serializer.writeByte(_height); | ||
125 | serializer.writeString("Generated"); | ||
126 | |||
127 | int genericFlags = 0; | ||
128 | if (symmetry != Symmetry::None) { | ||
129 | genericFlags |= Serializer::Symmetrical; | ||
130 | if (symmetry == Symmetry::Horizontal) { | ||
131 | genericFlags |= Serializer::SymmetryX; | ||
132 | } | ||
133 | if (symmetry == Symmetry::Vertical) { | ||
134 | genericFlags |= Serializer::SymmetryY; | ||
135 | } | ||
136 | } | ||
137 | serializer.writeByte(genericFlags); | ||
138 | |||
139 | for (int x = 0; x < _width; x++) { | ||
140 | for (int y = 0; y < _height; y++) { | ||
141 | int val = _grid[x][y]; | ||
142 | |||
143 | if (x % 2 == 1 && y % 2 == 1) { | ||
144 | // This is a grid cell. | ||
145 | int symbol = val & 0xF00; | ||
146 | if (symbol == Decoration::Triangle) { | ||
147 | serializer.writeByte(Serializer::Triangle); | ||
148 | serializer.writeColor(val & 0xF); | ||
149 | serializer.writeByte((val & 0xF0000) >> 16); | ||
150 | } else if (symbol == Decoration::Star) { | ||
151 | serializer.writeByte(Serializer::Star); | ||
152 | serializer.writeColor(val & 0xF); | ||
153 | } else if (symbol == Decoration::Stone) { | ||
154 | serializer.writeByte(Serializer::Square); | ||
155 | serializer.writeColor(val & 0xF); | ||
156 | } else if (symbol == Decoration::Eraser) { | ||
157 | serializer.writeByte(Serializer::Nega); | ||
158 | serializer.writeColor(val & 0xF); | ||
159 | } else if (symbol == Decoration::Poly) { | ||
160 | serializer.writeByte(Serializer::Poly); | ||
161 | serializer.writeColor(val & 0xF); | ||
162 | // TODO: write polyshape | ||
163 | } else if (symbol == Decoration::Negative) { | ||
164 | serializer.writeByte(Serializer::Ylop); | ||
165 | serializer.writeColor(val & 0xF); | ||
166 | // TODO: write polyshape | ||
167 | } else { | ||
168 | serializer.writeByte(Serializer::Nonce); | ||
169 | } | ||
170 | } else { | ||
171 | serializer.writeByte(Serializer::Line); | ||
172 | // line, dot, gap | ||
173 | serializer.writeByte(Serializer::LineNone); | ||
174 | if (val & Decoration::Dot) { | ||
175 | if (val & IntersectionFlags::DOT_IS_BLUE) { | ||
176 | serializer.writeByte(Serializer::DotBlue); | ||
177 | } else if (val & IntersectionFlags::DOT_IS_ORANGE) { | ||
178 | serializer.writeByte(Serializer::DotYellow); | ||
179 | } else if (val & IntersectionFlags::DOT_IS_INVISIBLE) { | ||
180 | serializer.writeByte(Serializer::DotInvisible); | ||
181 | } else { | ||
182 | serializer.writeByte(Serializer::DotBlack); | ||
183 | } | ||
184 | } else { | ||
185 | serializer.writeByte(Serializer::DotNone); | ||
186 | } | ||
187 | if (val & Decoration::Gap) { | ||
188 | serializer.writeByte(Serializer::GapBreak); | ||
189 | } else { | ||
190 | serializer.writeByte(Serializer::GapNone); | ||
191 | } | ||
192 | } | ||
193 | |||
194 | char startEnd = 0; | ||
195 | for (const Point& pos : _startpoints) { | ||
196 | if (pos.first == x && pos.second == y) { | ||
197 | startEnd |= Serializer::Start; | ||
198 | } | ||
199 | } | ||
200 | for (const Endpoint& endpoint : _endpoints) { | ||
201 | if (endpoint.GetX() == x && endpoint.GetY() == y) { | ||
202 | if (endpoint.GetDir() & Endpoint::LEFT) { | ||
203 | startEnd |= Serializer::EndLeft; | ||
204 | } | ||
205 | if (endpoint.GetDir() & Endpoint::RIGHT) { | ||
206 | startEnd |= Serializer::EndRight; | ||
207 | } | ||
208 | if (endpoint.GetDir() & Endpoint::UP) { | ||
209 | startEnd |= Serializer::EndTop; | ||
210 | } | ||
211 | if (endpoint.GetDir() & Endpoint::DOWN) { | ||
212 | startEnd |= Serializer::EndBottom; | ||
213 | } | ||
214 | } | ||
215 | } | ||
216 | serializer.writeByte(startEnd); | ||
217 | } | ||
218 | } | ||
219 | |||
220 | serializer.writeInt(0); | ||
221 | serializer.writeByte(Serializer::NegationsCancelNegations | | ||
222 | Serializer::PrecisePolyominos | | ||
223 | Serializer::FlashForErrors); | ||
224 | |||
225 | return serializer.str(); | ||
226 | } | ||
diff --git a/ext/wittle_generator/Panel.h b/ext/wittle_generator/Panel.h index 7444a9a..7f1588d 100644 --- a/ext/wittle_generator/Panel.h +++ b/ext/wittle_generator/Panel.h | |||
@@ -119,12 +119,12 @@ class Endpoint { | |||
119 | _flags = flags; | 119 | _flags = flags; |
120 | } | 120 | } |
121 | 121 | ||
122 | int GetX() { return _x; } | 122 | int GetX() const { return _x; } |
123 | void SetX(int x) { _x = x; } | 123 | void SetX(int x) { _x = x; } |
124 | int GetY() { return _y; } | 124 | int GetY() const { return _y; } |
125 | void SetY(int y) { _y = y; } | 125 | void SetY(int y) { _y = y; } |
126 | Direction GetDir() { return _dir; } | 126 | Direction GetDir() const { return _dir; } |
127 | int GetFlags() { return _flags; } | 127 | int GetFlags() const { return _flags; } |
128 | void SetDir(Direction dir) { _dir = dir; } | 128 | void SetDir(Direction dir) { _dir = dir; } |
129 | 129 | ||
130 | private: | 130 | private: |
@@ -167,6 +167,8 @@ class Panel { | |||
167 | int get(int x, int y) { return _grid[x][y]; } | 167 | int get(int x, int y) { return _grid[x][y]; } |
168 | void set(int x, int y, int val) { _grid[x][y] = val; } | 168 | void set(int x, int y, int val) { _grid[x][y] = val; } |
169 | 169 | ||
170 | std::string Write(); | ||
171 | |||
170 | enum Style { | 172 | enum Style { |
171 | SYMMETRICAL = 0x2, // Not on the town symmetry puzzles? IDK why. | 173 | SYMMETRICAL = 0x2, // Not on the town symmetry puzzles? IDK why. |
172 | NO_BLINK = 0x4, | 174 | NO_BLINK = 0x4, |
diff --git a/ext/wittle_generator/Serializer.cpp b/ext/wittle_generator/Serializer.cpp new file mode 100644 index 0000000..420926f --- /dev/null +++ b/ext/wittle_generator/Serializer.cpp | |||
@@ -0,0 +1,135 @@ | |||
1 | #include "Serializer.h" | ||
2 | |||
3 | #include <iostream> | ||
4 | #include <string> | ||
5 | |||
6 | #include "Base64.h" | ||
7 | |||
8 | void Serializer::writeByte(char val) { buffer_.push_back(val); } | ||
9 | |||
10 | void Serializer::writeInt(int val) { | ||
11 | int b1 = (val & 0x000000FF) >> 0; | ||
12 | int b2 = (val & 0x0000FF00) >> 8; | ||
13 | int b3 = (val & 0x00FF0000) >> 16; | ||
14 | int b4 = (val & 0xFF000000) >> 24; | ||
15 | writeByte(b1); | ||
16 | writeByte(b2); | ||
17 | writeByte(b3); | ||
18 | writeByte(b4); | ||
19 | } | ||
20 | |||
21 | void Serializer::writeLong(long val) { | ||
22 | long i1 = val & 0xFFFFFFFF; | ||
23 | long i2 = (val - i1) / 0x100000000; | ||
24 | writeInt(i1); | ||
25 | writeInt(i2); | ||
26 | } | ||
27 | |||
28 | void Serializer::writeColor(int val) { | ||
29 | switch (val) { | ||
30 | case 0x1: { | ||
31 | // Black | ||
32 | writeByte(0xFF); | ||
33 | writeByte(0xFF); | ||
34 | writeByte(0xFF); | ||
35 | writeByte(0xFF); | ||
36 | break; | ||
37 | } | ||
38 | case 0x2: { | ||
39 | // White | ||
40 | writeByte(0x00); | ||
41 | writeByte(0x00); | ||
42 | writeByte(0x00); | ||
43 | writeByte(0xFF); | ||
44 | break; | ||
45 | } | ||
46 | case 0x3: { | ||
47 | // Red | ||
48 | writeByte(0xFF); | ||
49 | writeByte(0x00); | ||
50 | writeByte(0x00); | ||
51 | writeByte(0xFF); | ||
52 | break; | ||
53 | } | ||
54 | case 0x4: { | ||
55 | // Purple | ||
56 | writeByte(0x80); | ||
57 | writeByte(0x00); | ||
58 | writeByte(0x80); | ||
59 | writeByte(0xFF); | ||
60 | break; | ||
61 | } | ||
62 | case 0x5: { | ||
63 | // Green | ||
64 | writeByte(0x00); | ||
65 | writeByte(0xFF); | ||
66 | writeByte(0x00); | ||
67 | writeByte(0xFF); | ||
68 | break; | ||
69 | } | ||
70 | case 0x6: { | ||
71 | // Cyan | ||
72 | writeByte(0x00); | ||
73 | writeByte(0xFF); | ||
74 | writeByte(0xFF); | ||
75 | writeByte(0xFF); | ||
76 | break; | ||
77 | } | ||
78 | case 0x7: { | ||
79 | // Magenta | ||
80 | writeByte(0xFF); | ||
81 | writeByte(0x00); | ||
82 | writeByte(0xFF); | ||
83 | writeByte(0xFF); | ||
84 | break; | ||
85 | } | ||
86 | case 0x8: { | ||
87 | // Yellow | ||
88 | writeByte(0xFF); | ||
89 | writeByte(0xFF); | ||
90 | writeByte(0x00); | ||
91 | writeByte(0xFF); | ||
92 | break; | ||
93 | } | ||
94 | case 0x9: { | ||
95 | // Blue | ||
96 | writeByte(0x00); | ||
97 | writeByte(0x00); | ||
98 | writeByte(0xFF); | ||
99 | writeByte(0xFF); | ||
100 | break; | ||
101 | } | ||
102 | case 0xA: { | ||
103 | // Orange | ||
104 | writeByte(0xFF); | ||
105 | writeByte(0x8C); | ||
106 | writeByte(0x00); | ||
107 | writeByte(0xFF); | ||
108 | break; | ||
109 | } | ||
110 | case 0xF: { | ||
111 | // X???? | ||
112 | break; | ||
113 | } | ||
114 | } | ||
115 | } | ||
116 | |||
117 | void Serializer::writeString(const std::string& val) { | ||
118 | writeInt(val.length()); | ||
119 | for (char ch : val) { | ||
120 | writeByte(ch); | ||
121 | } | ||
122 | } | ||
123 | |||
124 | std::string Serializer::str() const { | ||
125 | int i = 0; | ||
126 | for (char ch : buffer_) { | ||
127 | std::cout << std::hex << static_cast<int>(ch); | ||
128 | if (i++ % 4 == 3) { | ||
129 | std::cout << " "; | ||
130 | } | ||
131 | } | ||
132 | std::cout << std::endl; | ||
133 | |||
134 | return "_" + macaron::Base64::Encode(buffer_); | ||
135 | } | ||
diff --git a/ext/wittle_generator/Serializer.h b/ext/wittle_generator/Serializer.h new file mode 100644 index 0000000..86b262d --- /dev/null +++ b/ext/wittle_generator/Serializer.h | |||
@@ -0,0 +1,76 @@ | |||
1 | #ifndef SERIALIZER_H_51D08D41 | ||
2 | #define SERIALIZER_H_51D08D41 | ||
3 | |||
4 | #include <string> | ||
5 | |||
6 | constexpr int SERIALIZER_VERSION = 0; | ||
7 | |||
8 | class Serializer { | ||
9 | public: | ||
10 | enum CellType : char { | ||
11 | Null = 0, | ||
12 | Line = 1, | ||
13 | Square = 2, | ||
14 | Star = 3, | ||
15 | Nega = 4, | ||
16 | Triangle = 5, | ||
17 | Poly = 6, | ||
18 | Ylop = 7, | ||
19 | Nonce = 8 | ||
20 | }; | ||
21 | |||
22 | enum CellPart : char { | ||
23 | Start = 1, | ||
24 | EndLeft = 2, | ||
25 | EndRight = 4, | ||
26 | EndTop = 8, | ||
27 | EndBottom = 16 | ||
28 | }; | ||
29 | |||
30 | enum GenericFlag : char { | ||
31 | Autosolved = 1, | ||
32 | Symmetrical = 2, | ||
33 | SymmetryX = 4, | ||
34 | SymmetryY = 8, | ||
35 | Pillar = 16 | ||
36 | }; | ||
37 | |||
38 | enum LineColor : char { | ||
39 | LineNone = 0, | ||
40 | LineBlack = 1, | ||
41 | LineBlue = 2, | ||
42 | LineYellow = 3 | ||
43 | }; | ||
44 | |||
45 | enum DotColor : char { | ||
46 | DotNone = 0, | ||
47 | DotBlack = 1, | ||
48 | DotBlue = 2, | ||
49 | DotYellow = 3, | ||
50 | DotInvisible = 4 | ||
51 | }; | ||
52 | |||
53 | enum SettingsFlag : char { | ||
54 | NegationsCancelNegations = 1, | ||
55 | ShapelessZeroPoly = 2, | ||
56 | PrecisePolyominos = 4, | ||
57 | FlashForErrors = 8, | ||
58 | FatStartpoints = 16, | ||
59 | CustomMechanics = 32 | ||
60 | }; | ||
61 | |||
62 | enum GapType : char { GapNone = 0, GapBreak = 1, GapFull = 2 }; | ||
63 | |||
64 | void writeByte(char val); | ||
65 | void writeInt(int val); | ||
66 | void writeLong(long val); | ||
67 | void writeColor(int val); | ||
68 | void writeString(const std::string& val); | ||
69 | |||
70 | std::string str() const; | ||
71 | |||
72 | private: | ||
73 | std::string buffer_; | ||
74 | }; | ||
75 | |||
76 | #endif /* end of include guard: SERIALIZER_H_51D08D41 */ | ||
diff --git a/ext/wittle_generator/Test.cpp b/ext/wittle_generator/Test.cpp index 6139215..1da6cd8 100644 --- a/ext/wittle_generator/Test.cpp +++ b/ext/wittle_generator/Test.cpp | |||
@@ -4,7 +4,12 @@ int main(int, char**) { | |||
4 | Generate generator; | 4 | Generate generator; |
5 | generator.setSymbol(Decoration::Start, 0, 4 * 2); | 5 | generator.setSymbol(Decoration::Start, 0, 4 * 2); |
6 | generator.setSymbol(Decoration::Exit, 4 * 2, 0); | 6 | generator.setSymbol(Decoration::Exit, 4 * 2, 0); |
7 | generator.generate(4 * 2 + 1, 4 * 2 + 1, {{{Decoration::Triangle, 6}}}); | 7 | /*generator.generate(4 * 2 + 1, 4 * 2 + 1, |
8 | {{{Decoration::Triangle | Decoration::Orange, 6}}});*/ | ||
9 | generator.generate(4 * 2 + 1, 4 * 2 + 1, | ||
10 | {{{Decoration::Star | Decoration::Color::Magenta, 4}, | ||
11 | {Decoration::Stone | Decoration::Color::Black, 4}, | ||
12 | {Decoration::Stone | Decoration::Color::White, 4}}}); | ||
8 | 13 | ||
9 | return 0; | 14 | return 0; |
10 | } | 15 | } |