diff options
-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; |