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 | } |
