about summary refs log tree commit diff stats
path: root/ext/wittle_generator
diff options
context:
space:
mode:
authorStar Rauchenberger <fefferburbia@gmail.com>2023-10-27 17:20:23 -0400
committerStar Rauchenberger <fefferburbia@gmail.com>2023-10-27 17:20:23 -0400
commit4f25fa9ae42a0d43c20e954e8e50c66a6b057c92 (patch)
tree6cdfc57f5e1f54d025610757efb0ec57c3b88b0b /ext/wittle_generator
parentdde56d26837dc52e05207c0672b3c4a1046f6cb2 (diff)
downloadwittle-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.h127
-rw-r--r--ext/wittle_generator/CMakeLists.txt2
-rw-r--r--ext/wittle_generator/Generate.cpp57
-rw-r--r--ext/wittle_generator/Generate.h2
-rw-r--r--ext/wittle_generator/Panel.cpp110
-rw-r--r--ext/wittle_generator/Panel.h10
-rw-r--r--ext/wittle_generator/Serializer.cpp135
-rw-r--r--ext/wittle_generator/Serializer.h76
-rw-r--r--ext/wittle_generator/Test.cpp7
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
30namespace macaron {
31
32class 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 @@
1cmake_minimum_required (VERSION 3.1) 1cmake_minimum_required (VERSION 3.1)
2project (wittle_generator) 2project (wittle_generator)
3 3
4add_executable(wittle_generator Generate.cpp Panel.cpp Random.cpp Test.cpp) 4add_executable(wittle_generator Generate.cpp Panel.cpp Random.cpp Serializer.cpp Test.cpp)
5set_property(TARGET wittle_generator PROPERTY CXX_STANDARD 17) 5set_property(TARGET wittle_generator PROPERTY CXX_STANDARD 17)
6set_property(TARGET wittle_generator PROPERTY CXX_STANDARD_REQUIRED ON) 6set_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
1126bool Generate::place_dots(int amount, Decoration::Color color, 1160bool 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
6template <class T> 8template <class T>
7int find(const std::vector<T>& data, T search, size_t startIndex = 0) { 9int 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
120std::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
8void Serializer::writeByte(char val) { buffer_.push_back(val); }
9
10void 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
21void Serializer::writeLong(long val) {
22 long i1 = val & 0xFFFFFFFF;
23 long i2 = (val - i1) / 0x100000000;
24 writeInt(i1);
25 writeInt(i2);
26}
27
28void 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
117void Serializer::writeString(const std::string& val) {
118 writeInt(val.length());
119 for (char ch : val) {
120 writeByte(ch);
121 }
122}
123
124std::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
6constexpr int SERIALIZER_VERSION = 0;
7
8class 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}