diff options
author | Star Rauchenberger <fefferburbia@gmail.com> | 2022-12-12 15:37:04 -0500 |
---|---|---|
committer | Star Rauchenberger <fefferburbia@gmail.com> | 2022-12-12 15:37:04 -0500 |
commit | 66e12680ceeaf61e96704f574070ca5eaeebf1ac (patch) | |
tree | 67631495e04d725fd3dd18c6fab0aaf48af6663b /lingo.cpp | |
parent | 0772bdace4d579e581f40846c85bf07c1ac12e83 (diff) | |
download | lingo-66e12680ceeaf61e96704f574070ca5eaeebf1ac.tar.gz lingo-66e12680ceeaf61e96704f574070ca5eaeebf1ac.tar.bz2 lingo-66e12680ceeaf61e96704f574070ca5eaeebf1ac.zip |
Added triviality checking
Uniqueness checking also now only checks for answers that are the correct number of letters, which lets us reject fewer puzzles. Additionally, it now attempts to generate clues for a solution 10 times before rejecting it. refs #10, #3
Diffstat (limited to 'lingo.cpp')
-rw-r--r-- | lingo.cpp | 133 |
1 files changed, 86 insertions, 47 deletions
diff --git a/lingo.cpp b/lingo.cpp index cd68814..077bc3c 100644 --- a/lingo.cpp +++ b/lingo.cpp | |||
@@ -428,6 +428,22 @@ public: | |||
428 | 428 | ||
429 | private: | 429 | private: |
430 | 430 | ||
431 | bool isClueTrivial(Height height, Colour colour, const verbly::form& clue, const verbly::form& solution) const | ||
432 | { | ||
433 | if (height == kTop && colour == kWhite) | ||
434 | { | ||
435 | return !database_->forms((verbly::filter)clue && (verbly::word::synonyms %= solution)).all().empty(); | ||
436 | } else if (height == kBottom && colour == kWhite) | ||
437 | { | ||
438 | return !database_->forms((verbly::filter)clue && (verbly::form::pronunciations %= solution)).all().empty(); | ||
439 | } else if (height == kBottom && colour == kBlack) | ||
440 | { | ||
441 | return !database_->forms((verbly::filter)clue && (verbly::form::merographs %= solution)).all().empty() | ||
442 | || !database_->forms((verbly::filter)clue && (verbly::form::holographs %= solution)).all().empty(); | ||
443 | } | ||
444 | return false; | ||
445 | } | ||
446 | |||
431 | void generatePuzzle() | 447 | void generatePuzzle() |
432 | { | 448 | { |
433 | std::cout << "Generating puzzle..." << std::endl; | 449 | std::cout << "Generating puzzle..." << std::endl; |
@@ -568,70 +584,93 @@ private: | |||
568 | } | 584 | } |
569 | 585 | ||
570 | verbly::form solution = database_->forms(forwardFilter).first(); | 586 | verbly::form solution = database_->forms(forwardFilter).first(); |
571 | verbly::filter admissible = cleanFilter && (verbly::form::proper == false); | ||
572 | 587 | ||
573 | std::cout << "Solution decided: " << solution.getText() << std::endl; | 588 | std::cout << "Solution decided: " << solution.getText() << std::endl; |
574 | 589 | ||
575 | std::ostringstream msg_stream; | 590 | bool made_puzzle = false; |
576 | for (int i=0; i<static_cast<int>(kHeightCount); i++) { | 591 | for (int i=0; i<10; i++) |
577 | Height height = static_cast<Height>(i); | 592 | { |
578 | std::optional<Colour>& colour = parts[i]; | 593 | verbly::filter admissible = cleanFilter && (verbly::form::proper == false) && (verbly::form::length == static_cast<int>(solution.getText().size())); |
579 | if (colour.has_value()) { | 594 | std::ostringstream msg_stream; |
580 | if (*colour == kOrange) | 595 | bool trivial = false; |
581 | { | 596 | for (int i=0; i<static_cast<int>(kHeightCount); i++) { |
582 | msg_stream << COLOUR_EMOTES[*colour] << " " << orange_clue << std::endl; | 597 | Height height = static_cast<Height>(i); |
583 | admissible &= (verbly::form::text == orange_solution); | 598 | std::optional<Colour>& colour = parts[i]; |
599 | if (colour.has_value()) { | ||
600 | if (*colour == kOrange) | ||
601 | { | ||
602 | msg_stream << COLOUR_EMOTES[*colour] << " " << orange_clue << std::endl; | ||
603 | admissible &= (verbly::form::text == orange_solution); | ||
604 | } else { | ||
605 | verbly::filter questionFilter = makeHintFilter(solution, height, *colour, kTowardQuestion); | ||
606 | verbly::form questionPart = database_->forms(questionFilter && cleanFilter && wordFilter).first(); | ||
607 | msg_stream << COLOUR_EMOTES[*colour] << " " << questionPart.getText() << std::endl; | ||
608 | |||
609 | if (isClueTrivial(height, *colour, questionPart, solution)) | ||
610 | { | ||
611 | trivial = true; | ||
612 | break; | ||
613 | } | ||
614 | |||
615 | admissible &= makeHintFilter(questionPart, height, *colour, kTowardSolution); | ||
616 | } | ||
584 | } else { | 617 | } else { |
585 | verbly::filter questionFilter = makeHintFilter(solution, height, *colour, kTowardQuestion); | 618 | msg_stream << NONE_EMOTE << std::endl; |
586 | verbly::form questionPart = database_->forms(questionFilter && cleanFilter && wordFilter).first(); | ||
587 | msg_stream << COLOUR_EMOTES[*colour] << " " << questionPart.getText() << std::endl; | ||
588 | |||
589 | admissible &= makeHintFilter(questionPart, height, *colour, kTowardSolution); | ||
590 | } | 619 | } |
591 | } else { | ||
592 | msg_stream << NONE_EMOTE << std::endl; | ||
593 | } | 620 | } |
594 | } | ||
595 | auto byspace = hatkirby::split<std::list<std::string>>(solution.getText(), " "); | ||
596 | std::list<std::string> lens; | ||
597 | for (const std::string& wordpart : byspace) | ||
598 | { | ||
599 | lens.push_back(std::to_string(wordpart.size())); | ||
600 | } | ||
601 | 621 | ||
602 | msg_stream << "(" << hatkirby::implode(std::begin(lens), std::end(lens), " ") << ")"; | 622 | if (trivial) |
603 | 623 | { | |
604 | std::string message_text = msg_stream.str(); | 624 | std::cout << "Puzzle is trivial." << std::endl; |
605 | std::cout << message_text << std::endl << std::endl << solution.getText() << std::endl; | 625 | continue; |
626 | } | ||
606 | 627 | ||
607 | std::vector<verbly::form> admissibleResults = database_->forms(admissible, {}, 10).all(); | 628 | auto byspace = hatkirby::split<std::list<std::string>>(solution.getText(), " "); |
608 | if (green_uses > 0 || (admissibleResults.size() <= (hints == 1 ? 2 : 5))) | 629 | std::list<std::string> lens; |
609 | { | 630 | for (const std::string& wordpart : byspace) |
610 | genpuzzle = std::make_unique<puzzle>(); | ||
611 | genpuzzle->message = message_text; | ||
612 | genpuzzle->solution = hatkirby::lowercase(solution.getText()); | ||
613 | while (genpuzzle->solution.find(" ") != std::string::npos) | ||
614 | { | 631 | { |
615 | genpuzzle->solution.erase(genpuzzle->solution.find(" "), 1); | 632 | lens.push_back(std::to_string(wordpart.size())); |
616 | } | 633 | } |
617 | 634 | ||
618 | if (green_uses > 0) | 635 | msg_stream << "(" << hatkirby::implode(std::begin(lens), std::end(lens), " ") << ")"; |
636 | |||
637 | std::string message_text = msg_stream.str(); | ||
638 | std::cout << message_text << std::endl << std::endl << solution.getText() << std::endl; | ||
639 | |||
640 | std::vector<verbly::form> admissibleResults = database_->forms(admissible, {}, 10).all(); | ||
641 | if (green_uses > 0 || (admissibleResults.size() <= (hints == 1 ? 2 : 5))) | ||
619 | { | 642 | { |
620 | verbly::notion notion = database_->notions( | 643 | genpuzzle = std::make_unique<puzzle>(); |
621 | (verbly::notion::numOfImages > 1) && solution).first(); | 644 | genpuzzle->message = message_text; |
622 | auto [image, extension] = imagenet_->getImageForNotion(notion.getId(), rng_); | 645 | genpuzzle->solution = hatkirby::lowercase(solution.getText()); |
623 | if (image.empty()) | 646 | while (genpuzzle->solution.find(" ") != std::string::npos) |
624 | { | 647 | { |
625 | throw std::runtime_error("Could not find image for green hint."); | 648 | genpuzzle->solution.erase(genpuzzle->solution.find(" "), 1); |
626 | } | 649 | } |
627 | 650 | ||
628 | genpuzzle->attachment_name = std::string("SPOILER_image.") + extension; | 651 | if (green_uses > 0) |
629 | genpuzzle->attachment_content = std::move(image); | 652 | { |
630 | } | 653 | verbly::notion notion = database_->notions( |
654 | (verbly::notion::numOfImages > 1) && solution).first(); | ||
655 | auto [image, extension] = imagenet_->getImageForNotion(notion.getId(), rng_); | ||
656 | if (image.empty()) | ||
657 | { | ||
658 | throw std::runtime_error("Could not find image for green hint."); | ||
659 | } | ||
631 | 660 | ||
661 | genpuzzle->attachment_name = std::string("SPOILER_image.") + extension; | ||
662 | genpuzzle->attachment_content = std::move(image); | ||
663 | } | ||
664 | |||
665 | made_puzzle = true; | ||
666 | break; | ||
667 | } else { | ||
668 | std::cout << "Too many (" << admissibleResults.size() << ") results." << std::endl; | ||
669 | } | ||
670 | } | ||
671 | if (made_puzzle) | ||
672 | { | ||
632 | break; | 673 | break; |
633 | } else { | ||
634 | std::cout << "Too many (" << admissibleResults.size() << ") results." << std::endl; | ||
635 | } | 674 | } |
636 | } catch (const std::exception& ex) { | 675 | } catch (const std::exception& ex) { |
637 | std::cout << ex.what() << std::endl; | 676 | std::cout << ex.what() << std::endl; |