summary refs log tree commit diff stats
path: root/generator.cpp
diff options
context:
space:
mode:
authorStar Rauchenberger <fefferburbia@gmail.com>2023-02-17 09:51:36 -0500
committerStar Rauchenberger <fefferburbia@gmail.com>2023-02-17 09:51:36 -0500
commit26aa11444ca03571a2bf1ea14d54402094b5c15f (patch)
tree2c1d3b7ad2d5608007245d552eac187829aabfef /generator.cpp
parentcebfd065c029788f3d6a8cc33b9401a708052335 (diff)
downloadlingo-randomizer-26aa11444ca03571a2bf1ea14d54402094b5c15f.tar.gz
lingo-randomizer-26aa11444ca03571a2bf1ea14d54402094b5c15f.tar.bz2
lingo-randomizer-26aa11444ca03571a2bf1ea14d54402094b5c15f.zip
many changes (should stop doing this)
max_len_diff is an attempt to make mid blue and mid purple more reasonable. It maybe works for blue, but it is not good enough for purple. what we will need to do is limit on how much of the word can be removed, and that's going to require a change to verbly to allow that kind of query.

copy_hidden was added for the champion's rest colour pairs. The solution to the pair is found at champion's rest, and the corresponding colour pair has a hint that is just question marks.

must_be_broad forces a generated word to be targettable by bottom white/red/blue. this + reusing solution for most bottom white/red/blue puzzles makes those puzzles much more reasonable (though still hard).

an attempt to randomise cross tower was made, but I'm not happy with it.

hyphens in obscured hints will no longer be obscured. I think obscured hints tend to be too obscured sometimes though, especially when it comes to the number hunt and uncommon words.

middle red triviality check: middle red two word puzzles should not just remove one of the words

middle yellow triviality check: middle yellow two word puzzles should not just swap the words

top yellow triviality check: top yellow should not be able to swap two phonemes that are identical other than stress and say that it rearranged the word.

the colorful is partially randomised.

champion's rest is as randomsied as it could be (it is likely not reasonable to randomise the red/blue/yellow panels behind the walls.

the fearless is partially randomised (besides the chain puzzles).

the challenge is partially randomised.
Diffstat (limited to 'generator.cpp')
-rw-r--r--generator.cpp106
1 files changed, 104 insertions, 2 deletions
diff --git a/generator.cpp b/generator.cpp index d0ef1a9..c4dd76f 100644 --- a/generator.cpp +++ b/generator.cpp
@@ -1,6 +1,9 @@
1#include "generator.h" 1#include "generator.h"
2#include <algorithm> 2#include <algorithm>
3#include <iostream> 3#include <iostream>
4#include <cstdlib>
5#include <cctype>
6#include <hkutil/string.h>
4 7
5verbly::filter Generator::MakeHintFilter(verbly::filter subfilter, Height height, Colour colour, FilterDirection filter_direction) 8verbly::filter Generator::MakeHintFilter(verbly::filter subfilter, Height height, Colour colour, FilterDirection filter_direction)
6{ 9{
@@ -262,6 +265,11 @@ bool Generator::GenerateSinglePanelImpl(std::string name, Height height, Colour
262 solution = database_->forms(verbly::form::text == word).first(); 265 solution = database_->forms(verbly::form::text == word).first();
263 } else { 266 } else {
264 verbly::filter forward = MakeHintFilter({}, height, colour, kTowardSolution); 267 verbly::filter forward = MakeHintFilter({}, height, colour, kTowardSolution);
268 if (options.must_be_broad) {
269 forward &= MakeHintFilter({}, kBottom, kWhite, kTowardSolution);
270 forward &= MakeHintFilter({}, kBottom, kRed, kTowardSolution);
271 forward &= MakeHintFilter({}, kBottom, kBlue, kTowardSolution);
272 }
265 std::vector<verbly::form> solutions = database_->forms(forward && GetWordFilter(kTowardSolution, options)).all(); 273 std::vector<verbly::form> solutions = database_->forms(forward && GetWordFilter(kTowardSolution, options)).all();
266 solution = solutions.front();//solutions.at(std::uniform_int_distribution<int>(0, solutions.size())(rng_)); 274 solution = solutions.front();//solutions.at(std::uniform_int_distribution<int>(0, solutions.size())(rng_));
267 } 275 }
@@ -282,6 +290,12 @@ bool Generator::GenerateSinglePanelImpl(std::string name, Height height, Colour
282 // Finish early if this is a middle white. 290 // Finish early if this is a middle white.
283 if (height == kMiddle && colour == kWhite) { 291 if (height == kMiddle && colour == kWhite) {
284 SavePanel(name, solution.getText(), solution.getText(), options); 292 SavePanel(name, solution.getText(), solution.getText(), options);
293 if (!options.copy_to.empty()) {
294 SavePanel(options.copy_to, solution.getText(), solution.getText(), options);
295 }
296 if (!options.copy_hidden.empty()) {
297 SavePanel(options.copy_hidden, std::string(solution.getText().size(), '?'), solution.getText(), options);
298 }
285 return true; 299 return true;
286 } 300 }
287 301
@@ -293,6 +307,9 @@ bool Generator::GenerateSinglePanelImpl(std::string name, Height height, Colour
293 if (IsClueTrivial(height, colour, question, solution)) { 307 if (IsClueTrivial(height, colour, question, solution)) {
294 return false; 308 return false;
295 } 309 }
310 if (options.max_len_diff >= 0 && std::abs(static_cast<int>(question.getText().size() - solution.getText().size())) > options.max_len_diff) {
311 return false;
312 }
296 313
297 SavePanel(name, question.getText(), solution.getText(), options); 314 SavePanel(name, question.getText(), solution.getText(), options);
298 if (!options.copy_to.empty()) { 315 if (!options.copy_to.empty()) {
@@ -314,6 +331,11 @@ bool Generator::GenerateDoublePanelImpl(std::string name1, std::string name2, He
314 solution = database_->forms(verbly::form::text == word).first(); 331 solution = database_->forms(verbly::form::text == word).first();
315 } else { 332 } else {
316 verbly::filter forward = MakeHintFilter({}, height, colour, kTowardSolution); 333 verbly::filter forward = MakeHintFilter({}, height, colour, kTowardSolution);
334 if (options.must_be_broad) {
335 forward &= MakeHintFilter({}, kBottom, kWhite, kTowardSolution);
336 forward &= MakeHintFilter({}, kBottom, kRed, kTowardSolution);
337 forward &= MakeHintFilter({}, kBottom, kBlue, kTowardSolution);
338 }
317 std::vector<verbly::form> solutions = database_->forms(forward && GetWordFilter(kTowardSolution, options)).all(); 339 std::vector<verbly::form> solutions = database_->forms(forward && GetWordFilter(kTowardSolution, options)).all();
318 solution = solutions.front();//solutions.at(std::uniform_int_distribution<int>(0, solutions.size())(rng_)); 340 solution = solutions.front();//solutions.at(std::uniform_int_distribution<int>(0, solutions.size())(rng_));
319 } 341 }
@@ -338,6 +360,12 @@ bool Generator::GenerateDoublePanelImpl(std::string name1, std::string name2, He
338 if (IsClueTrivial(height, colour, questions[0], solution) || IsClueTrivial(height, colour, questions[1], solution)) { 360 if (IsClueTrivial(height, colour, questions[0], solution) || IsClueTrivial(height, colour, questions[1], solution)) {
339 return false; 361 return false;
340 } 362 }
363 if (options.max_len_diff >= 0) {
364 if (std::abs(static_cast<int>(questions[0].getText().size() - solution.getText().size())) > options.max_len_diff
365 || std::abs(static_cast<int>(questions[1].getText().size() - solution.getText().size())) > options.max_len_diff) {
366 return false;
367 }
368 }
341 369
342 SavePanel(name1, questions[0].getText(), solution.getText(), options); 370 SavePanel(name1, questions[0].getText(), solution.getText(), options);
343 SavePanel(name2, questions[1].getText(), solution.getText(), options); 371 SavePanel(name2, questions[1].getText(), solution.getText(), options);
@@ -370,6 +398,12 @@ bool Generator::GenerateCohintedPanelsImpl(std::string name1, std::string name2,
370 if (IsClueTrivial(height, colour, question, solutions[0]) || IsClueTrivial(height, colour, question, solutions[1])) { 398 if (IsClueTrivial(height, colour, question, solutions[0]) || IsClueTrivial(height, colour, question, solutions[1])) {
371 return false; 399 return false;
372 } 400 }
401 if (options.max_len_diff >= 0) {
402 if (std::abs(static_cast<int>(question.getText().size() - solutions[0].getText().size())) > options.max_len_diff
403 || std::abs(static_cast<int>(question.getText().size() - solutions[1].getText().size())) > options.max_len_diff) {
404 return false;
405 }
406 }
373 407
374 SavePanel(name1, question.getText(), solutions[0].getText(), options); 408 SavePanel(name1, question.getText(), solutions[0].getText(), options);
375 SavePanel(name2, question.getText(), solutions[1].getText(), options); 409 SavePanel(name2, question.getText(), solutions[1].getText(), options);
@@ -408,6 +442,12 @@ bool Generator::GeneratePairedPanelsImpl(std::string name1, std::string name2, H
408 } 442 }
409 } 443 }
410 444
445 if (options.max_len_diff >= 0) {
446 if (std::abs(static_cast<int>(question.getText().size() - solution.getText().size())) > options.max_len_diff) {
447 return false;
448 }
449 }
450
411 if (height == kMiddle && colour == kWhite) { 451 if (height == kMiddle && colour == kWhite) {
412 SavePanel(name1, question.getText(), question.getText(), options); 452 SavePanel(name1, question.getText(), question.getText(), options);
413 SavePanel(name2, solution.getText(), solution.getText(), options); 453 SavePanel(name2, solution.getText(), solution.getText(), options);
@@ -587,7 +627,30 @@ void Generator::GenerateCrossTower(
587 std::string west_other_name3) 627 std::string west_other_name3)
588{ 628{
589 std::vector<std::vector<std::string>> sets = cross_tower_->GetPuzzleSet(rng_); 629 std::vector<std::vector<std::string>> sets = cross_tower_->GetPuzzleSet(rng_);
590 630
631 SavePanel(north_tower_name, "", sets[0][0]);
632 SavePanel(north_lookout_name, "", sets[0][0]);
633 SavePanel(north_other_name1, sets[0][1], sets[0][1]);
634 SavePanel(north_other_name2, sets[0][2], sets[0][2]);
635 SavePanel(north_other_name3, sets[0][3], sets[0][3]);
636
637 SavePanel(south_tower_name, "", sets[1][0]);
638 SavePanel(south_lookout_name, "", sets[1][0]);
639 SavePanel(south_other_name1, sets[1][1], sets[1][1]);
640 SavePanel(south_other_name2, sets[1][2], sets[1][2]);
641 SavePanel(south_other_name3, sets[1][3], sets[1][3]);
642
643 SavePanel(east_tower_name, "", sets[2][0]);
644 SavePanel(east_lookout_name, "", sets[2][0]);
645 SavePanel(east_other_name1, sets[2][1], sets[2][1]);
646 SavePanel(east_other_name2, sets[2][2], sets[2][2]);
647 SavePanel(east_other_name3, sets[2][3], sets[2][3]);
648
649 SavePanel(west_tower_name, "", sets[3][0]);
650 SavePanel(west_lookout_name, "", sets[3][0]);
651 SavePanel(west_other_name1, sets[3][1], sets[3][1]);
652 SavePanel(west_other_name2, sets[3][2], sets[3][2]);
653 SavePanel(west_other_name3, sets[3][3], sets[3][3]);
591} 654}
592 655
593void Generator::SavePanel(std::string name, std::string question, std::string answer, GenerateOptions options) { 656void Generator::SavePanel(std::string name, std::string question, std::string answer, GenerateOptions options) {
@@ -606,7 +669,7 @@ void Generator::SavePanel(std::string name, std::string question, std::string an
606 std::shuffle(indicies.begin(), indicies.end(), rng_); 669 std::shuffle(indicies.begin(), indicies.end(), rng_);
607 670
608 for (int i=0; i<numToObscure; i++) { 671 for (int i=0; i<numToObscure; i++) {
609 if (question[indicies[i]] != ' ') { 672 if (question[indicies[i]] != ' ' && question[indicies[i]] != '-') {
610 question[indicies[i]] = '?'; 673 question[indicies[i]] = '?';
611 } 674 }
612 } 675 }
@@ -653,6 +716,10 @@ verbly::filter Generator::GetWordFilter(FilterDirection dir, GenerateOptions opt
653 return wordFilter; 716 return wordFilter;
654} 717}
655 718
719bool isDigitWrapper(unsigned char ch) {
720 return std::isdigit(ch);
721}
722
656bool Generator::IsClueTrivial(Height height, Colour colour, const verbly::form& clue, const verbly::form& solution) const 723bool Generator::IsClueTrivial(Height height, Colour colour, const verbly::form& clue, const verbly::form& solution) const
657{ 724{
658 if (height == kTop && colour == kWhite) 725 if (height == kTop && colour == kWhite)
@@ -670,6 +737,41 @@ bool Generator::IsClueTrivial(Height height, Colour colour, const verbly::form&
670 return (clue.getId() == solution.getId()) 737 return (clue.getId() == solution.getId())
671 || !database_->forms((verbly::filter)clue && (verbly::form::merographs %= solution)).all().empty() 738 || !database_->forms((verbly::filter)clue && (verbly::form::merographs %= solution)).all().empty()
672 || !database_->forms((verbly::filter)clue && (verbly::form::holographs %= solution)).all().empty(); 739 || !database_->forms((verbly::filter)clue && (verbly::form::holographs %= solution)).all().empty();
740 } else if (height == kMiddle && colour == kRed) {
741 if (clue.getComplexity() == 2 && solution.getComplexity() == 1) {
742 auto words = hatkirby::split<std::vector<std::string>>(clue.getText(), " ");
743 for (const auto& word : words) {
744 if (word == solution.getText()) {
745 return true;
746 }
747 }
748 }
749 } else if (height == kMiddle && colour == kYellow) {
750 if (clue.getComplexity() == solution.getComplexity()) {
751 auto clueWords = hatkirby::split<std::vector<std::string>>(clue.getText(), " ");
752 auto solutionWords = hatkirby::split<std::vector<std::string>>(solution.getText(), " ");
753 std::sort(clueWords.begin(), clueWords.end());
754 std::sort(solutionWords.begin(), solutionWords.end());
755 if (clueWords == solutionWords) {
756 return true;
757 }
758 }
759 } else if (height == kTop && colour == kYellow) {
760 std::set<std::string> hint_stressless;
761 for (const verbly::pronunciation& pronunciation : clue.getPronunciations()) {
762 std::string stressed = hatkirby::implode(pronunciation.getPhonemes(), " ");
763 std::string stressless;
764 std::remove_copy_if(stressed.begin(), stressed.end(), std::back_inserter(stressless), &isDigitWrapper);
765 hint_stressless.insert(stressless);
766 }
767 for (const verbly::pronunciation& pronunciation : solution.getPronunciations()) {
768 std::string stressed = hatkirby::implode(pronunciation.getPhonemes(), " ");
769 std::string stressless;
770 std::remove_copy_if(stressed.begin(), stressed.end(), std::back_inserter(stressless), &isDigitWrapper);
771 if (hint_stressless.count(stressless)) {
772 return true;
773 }
774 }
673 } 775 }
674 return false; 776 return false;
675} 777}