diff options
Diffstat (limited to 'generator.cpp')
-rw-r--r-- | generator.cpp | 106 |
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 | ||
5 | verbly::filter Generator::MakeHintFilter(verbly::filter subfilter, Height height, Colour colour, FilterDirection filter_direction) | 8 | verbly::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 | ||
593 | void Generator::SavePanel(std::string name, std::string question, std::string answer, GenerateOptions options) { | 656 | void 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 | ||
719 | bool isDigitWrapper(unsigned char ch) { | ||
720 | return std::isdigit(ch); | ||
721 | } | ||
722 | |||
656 | bool Generator::IsClueTrivial(Height height, Colour colour, const verbly::form& clue, const verbly::form& solution) const | 723 | bool 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 | } |