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