diff options
Diffstat (limited to 'ext')
| -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 | } |
