diff options
Diffstat (limited to 'lingo.cpp')
-rw-r--r-- | lingo.cpp | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/lingo.cpp b/lingo.cpp new file mode 100644 index 0000000..e13bb53 --- /dev/null +++ b/lingo.cpp | |||
@@ -0,0 +1,273 @@ | |||
1 | #include <mastodonpp/mastodonpp.hpp> | ||
2 | #include <random> | ||
3 | #include <yaml-cpp/yaml.h> | ||
4 | #include <iostream> | ||
5 | #include <thread> | ||
6 | #include <chrono> | ||
7 | #include <string> | ||
8 | #include <algorithm> | ||
9 | #include <verbly.h> | ||
10 | #include <json.hpp> | ||
11 | #include <optional> | ||
12 | #include <map> | ||
13 | #include <array> | ||
14 | |||
15 | enum Height { | ||
16 | kTop, | ||
17 | kMiddle, | ||
18 | kBottom, | ||
19 | kHeightCount | ||
20 | }; | ||
21 | |||
22 | enum Colour { | ||
23 | kWhite, | ||
24 | kBlack, | ||
25 | kRed, | ||
26 | kBlue, | ||
27 | kPurple, | ||
28 | kBrown, | ||
29 | kColourCount | ||
30 | }; | ||
31 | |||
32 | const std::string COLOUR_EMOJIS[kColourCount] = { | ||
33 | "⬜️", | ||
34 | "⬛️", | ||
35 | "🟥", | ||
36 | "🟦", | ||
37 | "🟪", | ||
38 | "🟫" | ||
39 | }; | ||
40 | |||
41 | int main(int argc, char** argv) | ||
42 | { | ||
43 | std::random_device randomDevice; | ||
44 | std::mt19937 rng{randomDevice()}; | ||
45 | |||
46 | if (argc != 2) | ||
47 | { | ||
48 | std::cout << "usage: lingo [configfile]" << std::endl; | ||
49 | return -1; | ||
50 | } | ||
51 | |||
52 | std::string configfile(argv[1]); | ||
53 | YAML::Node config = YAML::LoadFile(configfile); | ||
54 | |||
55 | verbly::database database(config["verbly_datafile"].as<std::string>()); | ||
56 | |||
57 | /*mastodonpp::Instance instance{ | ||
58 | config["mastodon_instance"].as<std::string>(), | ||
59 | config["mastodon_token"].as<std::string>()}; | ||
60 | mastodonpp::Connection connection{instance};*/ | ||
61 | |||
62 | std::set<std::tuple<Height, Colour>> filters = { | ||
63 | {kBottom, kWhite}, | ||
64 | {kBottom, kBlack}, | ||
65 | {kTop, kPurple}, | ||
66 | {kTop, kWhite}, | ||
67 | {kBottom, kRed}, | ||
68 | {kBottom, kBlue}, | ||
69 | }; | ||
70 | |||
71 | verbly::filter cleanFilter = | ||
72 | !(verbly::word::usageDomains %= (verbly::notion::wnid == 106718862)) // ethnic slurs | ||
73 | && !(verbly::notion::wnid == 110630093); // "spastic" | ||
74 | |||
75 | for (;;) | ||
76 | { | ||
77 | bool puzzleEmpty = true; | ||
78 | std::array<std::optional<Colour>, kHeightCount> parts; | ||
79 | for (int height = 0; height < static_cast<int>(kHeightCount); height++) { | ||
80 | if (std::bernoulli_distribution(0.4)(rng)) { | ||
81 | int colour = std::uniform_int_distribution<int>(0, static_cast<int>(kColourCount)-1)(rng); | ||
82 | if (filters.count({static_cast<Height>(height), static_cast<Colour>(colour)})) { | ||
83 | parts[static_cast<Height>(height)] = static_cast<Colour>(colour); | ||
84 | puzzleEmpty = false; | ||
85 | } | ||
86 | } | ||
87 | } | ||
88 | |||
89 | if (puzzleEmpty) { | ||
90 | continue; | ||
91 | } | ||
92 | |||
93 | verbly::filter forwardFilter = cleanFilter && (verbly::form::proper == false); | ||
94 | for (int i=0; i<static_cast<int>(kHeightCount); i++) { | ||
95 | Height height = static_cast<Height>(i); | ||
96 | std::optional<Colour>& colour = parts[i]; | ||
97 | if (!colour.has_value()) { | ||
98 | continue; | ||
99 | } | ||
100 | switch (*colour) { | ||
101 | case kWhite: { | ||
102 | switch (height) { | ||
103 | case kBottom: { | ||
104 | forwardFilter &= (verbly::word::synonyms); | ||
105 | break; | ||
106 | } | ||
107 | case kTop: { | ||
108 | forwardFilter &= (verbly::form::pronunciations %= | ||
109 | verbly::filter("homophones", false, | ||
110 | (verbly::pronunciation::forms %= verbly::filter( | ||
111 | verbly::form::id, | ||
112 | verbly::filter::comparison::field_does_not_equal, | ||
113 | verbly::form::id)))); | ||
114 | break; | ||
115 | } | ||
116 | default: break; // Not supposed yet. | ||
117 | } | ||
118 | break; | ||
119 | } | ||
120 | case kBlack: { | ||
121 | switch (height) { | ||
122 | case kBottom: { | ||
123 | forwardFilter &= (verbly::word::antonyms); | ||
124 | break; | ||
125 | } | ||
126 | default: break; // Not supposed yet. | ||
127 | } | ||
128 | break; | ||
129 | } | ||
130 | case kBrown: { | ||
131 | switch (height) { | ||
132 | case kBottom: { | ||
133 | forwardFilter &= (verbly::notion::causes); | ||
134 | break; | ||
135 | } | ||
136 | default: break; // Not supposed yet. | ||
137 | } | ||
138 | break; | ||
139 | } | ||
140 | case kRed: { | ||
141 | switch (height) { | ||
142 | case kBottom: { | ||
143 | forwardFilter &= (verbly::notion::partMeronyms); | ||
144 | break; | ||
145 | } | ||
146 | default: break; // Not supposed yet. | ||
147 | } | ||
148 | break; | ||
149 | } | ||
150 | case kBlue: { | ||
151 | switch (height) { | ||
152 | case kBottom: { | ||
153 | forwardFilter &= (verbly::notion::partHolonyms); | ||
154 | break; | ||
155 | } | ||
156 | default: break; // Not supposed yet. | ||
157 | } | ||
158 | break; | ||
159 | } | ||
160 | case kPurple: { | ||
161 | switch (height) { | ||
162 | case kTop: { | ||
163 | forwardFilter &= (verbly::pronunciation::rhymes); | ||
164 | break; | ||
165 | } | ||
166 | default: break; // Not supposed yet. | ||
167 | } | ||
168 | break; | ||
169 | } | ||
170 | default: break; // Not supposed yet. | ||
171 | } | ||
172 | } | ||
173 | |||
174 | verbly::word solution = database.words(forwardFilter).first(); | ||
175 | |||
176 | for (int i=0; i<static_cast<int>(kHeightCount); i++) { | ||
177 | Height height = static_cast<Height>(i); | ||
178 | std::optional<Colour>& colour = parts[i]; | ||
179 | if (colour.has_value()) { | ||
180 | verbly::filter questionFilter; | ||
181 | switch (*colour) { | ||
182 | case kWhite: { | ||
183 | switch (height) { | ||
184 | case kBottom: { | ||
185 | questionFilter = (verbly::word::synonyms %= solution); | ||
186 | break; | ||
187 | } | ||
188 | case kTop: { | ||
189 | questionFilter = (verbly::form::pronunciations %= | ||
190 | verbly::filter("homophones", false, | ||
191 | (verbly::pronunciation::forms %= ((verbly::filter)solution && verbly::filter( | ||
192 | verbly::form::id, | ||
193 | verbly::filter::comparison::field_does_not_equal, | ||
194 | verbly::form::id))))); | ||
195 | break; | ||
196 | } | ||
197 | default: break; // Not supposed yet. | ||
198 | } | ||
199 | break; | ||
200 | } | ||
201 | case kBlack: { | ||
202 | switch (height) { | ||
203 | case kBottom: { | ||
204 | questionFilter = (verbly::word::antonyms %= solution); | ||
205 | break; | ||
206 | } | ||
207 | default: break; // Not supposed yet. | ||
208 | } | ||
209 | break; | ||
210 | } | ||
211 | case kBrown: { | ||
212 | switch (height) { | ||
213 | case kBottom: { | ||
214 | questionFilter = (verbly::notion::effects %= solution); | ||
215 | break; | ||
216 | } | ||
217 | default: break; // Not supposed yet. | ||
218 | } | ||
219 | break; | ||
220 | } | ||
221 | case kBlue: { | ||
222 | switch (height) { | ||
223 | case kBottom: { | ||
224 | /*questionFilter = ((verbly::notion::fullMemberHolonyms %= solution) | ||
225 | || (verbly::notion::fullPartHolonyms %= solution) | ||
226 | || (verbly::notion::fullSubstanceHolonyms %= solution));*/ | ||
227 | //questionFilter &= !(verbly::notion::words %= solution); | ||
228 | questionFilter = (verbly::notion::partMeronyms %= solution); | ||
229 | break; | ||
230 | } | ||
231 | default: break; // Not supposed yet. | ||
232 | } | ||
233 | break; | ||
234 | } | ||
235 | case kRed: { | ||
236 | switch (height) { | ||
237 | case kBottom: { | ||
238 | /*questionFilter = ((verbly::notion::fullMemberMeronyms %= solution) | ||
239 | || (verbly::notion::fullPartMeronyms %= solution) | ||
240 | || (verbly::notion::fullSubstanceMeronyms %= solution));*/ | ||
241 | questionFilter = (verbly::notion::partHolonyms %= solution); | ||
242 | //questionFilter &= !(verbly::notion::words %= solution); | ||
243 | break; | ||
244 | } | ||
245 | default: break; // Not supposed yet. | ||
246 | } | ||
247 | break; | ||
248 | } | ||
249 | case kPurple: { | ||
250 | switch (height) { | ||
251 | case kTop: { | ||
252 | questionFilter = (verbly::pronunciation::rhymes %= solution); | ||
253 | break; | ||
254 | } | ||
255 | default: break; // Not supposed yet. | ||
256 | } | ||
257 | break; | ||
258 | } | ||
259 | default: break; // Not supposed yet. | ||
260 | } | ||
261 | verbly::word questionPart = database.words(questionFilter && cleanFilter && (verbly::form::proper == false)).first(); | ||
262 | std::cout << COLOUR_EMOJIS[*colour] << " " << questionPart.getBaseForm().getText() << std::endl; | ||
263 | } else { | ||
264 | std::cout << "▪️" << std::endl; | ||
265 | } | ||
266 | } | ||
267 | std::cout << "(" << solution.getBaseForm().getText().size() << ")" << std::endl << std::endl << solution.getBaseForm().getText() << std::endl; | ||
268 | |||
269 | |||
270 | // We can poll the timeline at most once every five minutes. | ||
271 | std::this_thread::sleep_for(std::chrono::hours(3)); | ||
272 | } | ||
273 | } | ||