summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorStar Rauchenberger <fefferburbia@gmail.com>2022-12-12 15:37:04 -0500
committerStar Rauchenberger <fefferburbia@gmail.com>2022-12-12 15:37:04 -0500
commit66e12680ceeaf61e96704f574070ca5eaeebf1ac (patch)
tree67631495e04d725fd3dd18c6fab0aaf48af6663b
parent0772bdace4d579e581f40846c85bf07c1ac12e83 (diff)
downloadlingo-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
-rw-r--r--lingo.cpp133
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
429private: 429private:
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;