summary refs log tree commit diff stats
path: root/generator.h
diff options
context:
space:
mode:
Diffstat (limited to 'generator.h')
-rw-r--r--generator.h230
1 files changed, 230 insertions, 0 deletions
diff --git a/generator.h b/generator.h new file mode 100644 index 0000000..1381cd3 --- /dev/null +++ b/generator.h
@@ -0,0 +1,230 @@
1#ifndef GENERATOR_H_811386CE
2#define GENERATOR_H_811386CE
3
4#include <string>
5#include <random>
6#include <map>
7#include <tuple>
8#include <memory>
9#include <verbly.h>
10#include <hkutil/string.h>
11
12enum Height {
13 kTop,
14 kMiddle,
15 kBottom,
16 kHeightCount
17};
18
19enum Colour {
20 kWhite,
21 kBlack,
22 kRed,
23 kBlue,
24 kPurple,
25 kBrown,
26 kYellow,
27 kGreen,
28 kOrange,
29 kColourCount
30};
31
32enum FilterDirection {
33 kTowardSolution,
34 kTowardQuestion
35};
36
37enum PalindromeQuery {
38 kPalindromeUnspecified,
39 kForcePalindrome,
40 kRejectPalindrome
41};
42
43struct GenerateOptions {
44 bool obscure_hint = false;
45 int max_answer_len = 0;
46 int max_hint_len = 0;
47 int exact_len = 0;
48 bool multiword = false;
49 bool save_for_later = false;
50 bool reuse_solution = false; // supported by single, double, and stack
51 std::string unique_pool; // supported by single, double, and stack
52 PalindromeQuery palindrome = kPalindromeUnspecified; // only important for middle black. supported by single and paired
53 std::string copy_to; // supported by single and paired
54 std::string copy_to2; // supported by paired
55 bool force_two_words = false;
56};
57
58class Wanderlust {
59public:
60 Wanderlust(const std::string& words_filename, const std::string& puzzles_filename) {
61 std::ifstream words_file(words_filename);
62 std::string line;
63 while (std::getline(words_file, line)) {
64 words_.push_back(line);
65 }
66
67 std::ifstream puzzles_file(puzzles_filename);
68 while (std::getline(puzzles_file, line)) {
69 std::string line2;
70 if (!std::getline(puzzles_file, line2)) {
71 throw std::invalid_argument("Wanderlust file is malformed.");
72 }
73
74 puzzles_.emplace_back(line, line2);
75 }
76 }
77
78 std::tuple<std::string, std::string> GetPuzzle(std::mt19937& rng) const {
79 return puzzles_.at(std::uniform_int_distribution<int>(0, puzzles_.size()-1)(rng));
80 }
81
82 const std::string& GetWord(std::mt19937& rng) const {
83 return words_.at(std::uniform_int_distribution<int>(0, words_.size()-1)(rng));
84 }
85
86private:
87 std::vector<std::tuple<std::string, std::string>> puzzles_;
88 std::vector<std::string> words_;
89};
90
91class CrossTower {
92public:
93 explicit CrossTower(std::string filename) {
94 std::ifstream file(filename);
95 std::string line;
96 while (std::getline(file, line)) {
97 sets_.push_back(hatkirby::split<std::vector<std::string>>(line, " "));
98 }
99 }
100
101 std::vector<std::vector<std::string>> GetPuzzleSet(std::mt19937& rng) const {
102 std::vector<std::vector<std::string>> result = sets_;
103 std::shuffle(result.begin(), result.end(), rng);
104 result.resize(4);
105
106 for (std::vector<std::string>& set : result) {
107 std::shuffle(set.begin(), set.end(), rng);
108 }
109
110 return result;
111 }
112
113private:
114 std::vector<std::vector<std::string>> sets_;
115};
116
117class Generator {
118public:
119
120 explicit Generator(unsigned int seed) : seed_(seed), rng_(seed) {
121 database_ = std::make_unique<verbly::database>("/Users/hatkirby/Dropbox/Programming/verbly-datafiles/d1.3_lingo7");
122 wanderlust_ = std::make_unique<Wanderlust>("../wanderlust_words.txt", "../wanderlust_puzzles.txt");
123 cross_tower_ = std::make_unique<CrossTower>("../cross_tower.txt");
124 }
125
126 // Querying
127 bool IsPanelRandomized(const std::string& name) const {
128 return panels_.count(name);
129 }
130
131 const std::tuple<std::string, std::string>& GetPanel(const std::string& name) const {
132 return panels_.at(name);
133 }
134
135 // Sets the panel's question and answer to static values.
136 void GenerateStaticPanel(std::string name, std::string question, std::string answer = "");
137
138 // Generates a one-block puzzle with the given height and colour.
139 void GenerateSinglePanel(std::string name, Height height, Colour colour, GenerateOptions options = {});
140
141 // Generates a one-block puzzle with the given height and colour, where there is a panel on two faces of the block.
142 // Both puzzles will have the same answer.
143 void GenerateDoublePanel(std::string name1, std::string name2, Height height, Colour colour, GenerateOptions options = {});
144
145 // Generates two puzzles with the same hint but different answers.
146 void GenerateCohintedPanels(std::string name1, std::string name2, Height height, Colour colour, GenerateOptions options = {});
147
148 // Generates two panels at once, where the question for one is the answer to the other.
149 // Colour must be white, black, or yellow.
150 // Middle white is a special case; the puzzles will be antonyms of one another.
151 void GeneratePairedPanels(std::string name1, std::string name2, Height height, Colour colour, GenerateOptions options = {});
152
153 // Generates a vertical stack of panels that all have the same answer.
154 // If a name is left blank, that height will be ignored.
155 void GeneratePanelStack(std::string top_name, Colour top_colour, std::string middle_name, Colour middle_colour, std::string bottom_name, Colour bottom_colour, GenerateOptions options = {});
156
157 // Generate an orange puzzle, with a number for the hint.
158 void GenerateOrangeNumberPanel(std::string name);
159
160 // Generate an orange puzzle, with a word for the hint.
161 void GenerateOrangeWordPanel(std::string name);
162
163 // Generate an orange puzzle, with an addition problem for the hint.
164 void GenerateOrangeAdditionPanel(std::string name);
165
166 // Generates the ONE ROAD MANY TURNS panel by combining the solutions to four other panels.
167 void GenerateOneRoadManyTurns(std::string order_name, std::string part1_name, std::string part2_name, std::string part3_name, std::string part4_name);
168
169 // Generates a hybrid puzzle where the solution is two words and each word is provided by a different colour/height puzzle.
170 void GenerateComboPanel(std::string name, Height left_height, Colour left_colour, Height right_height, Colour right_colour, GenerateOptions options = {});
171
172 // Generates the cross tower sets-of-four puzzles.
173 void GenerateCrossTower(
174 std::string north_tower_name,
175 std::string south_tower_name,
176 std::string east_tower_name,
177 std::string west_tower_name,
178 std::string north_lookout_name,
179 std::string south_lookout_name,
180 std::string east_lookout_name,
181 std::string west_lookout_name,
182 std::string north_other_name1,
183 std::string north_other_name2,
184 std::string north_other_name3,
185 std::string south_other_name1,
186 std::string south_other_name2,
187 std::string south_other_name3,
188 std::string east_other_name1,
189 std::string east_other_name2,
190 std::string east_other_name3,
191 std::string west_other_name1,
192 std::string west_other_name2,
193 std::string west_other_name3);
194
195private:
196
197 verbly::filter MakeHintFilter(verbly::filter subfilter, Height height, Colour colour, FilterDirection filter_direction);
198
199 bool GenerateSinglePanelImpl(std::string name, Height height, Colour colour, GenerateOptions options);
200
201 bool GenerateDoublePanelImpl(std::string name1, std::string name2, Height height, Colour colour, GenerateOptions options);
202
203 bool GenerateCohintedPanelsImpl(std::string name1, std::string name2, Height height, Colour colour, GenerateOptions options);
204
205 bool GeneratePairedPanelsImpl(std::string name1, std::string name2, Height height, Colour colour, GenerateOptions options);
206
207 bool GeneratePanelStackImpl(std::string top_name, Colour top_colour, std::string middle_name, Colour middle_colour, std::string bottom_name, Colour bottom_colour, GenerateOptions options);
208
209 bool GenerateComboPanelImpl(std::string name, Height left_height, Colour left_colour, Height right_height, Colour right_colour, GenerateOptions options);
210
211 void SavePanel(std::string name, std::string question, std::string answer, GenerateOptions options = {});
212
213 verbly::filter GetWordFilter(FilterDirection direction, GenerateOptions options) const;
214
215 bool IsClueTrivial(Height height, Colour colour, const verbly::form& clue, const verbly::form& solution) const;
216
217 unsigned int seed_;
218 std::mt19937 rng_;
219 std::unique_ptr<verbly::database> database_;
220 std::unique_ptr<Wanderlust> wanderlust_;
221 std::unique_ptr<CrossTower> cross_tower_;
222
223 // name, question, answer
224 std::map<std::string, std::tuple<std::string, std::string>> panels_;
225
226 std::vector<std::string> reusable_;
227 std::map<std::string, std::set<std::string>> pools_;
228};
229
230#endif /* end of include guard: GENERATOR_H_811386CE */