From a419bf5aa4ac9aa3b242ac6881c41de18039d0e3 Mon Sep 17 00:00:00 2001 From: Star Rauchenberger Date: Thu, 8 Dec 2022 16:03:35 -0500 Subject: Made it a Discord bot --- CMakeLists.txt | 8 +- lingo.cpp | 413 +++++++++++++++++++++++++++++++-------------------------- 2 files changed, 232 insertions(+), 189 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f09bbd..38883b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,21 +5,21 @@ set(CMAKE_BUILD_TYPE Debug) find_package(PkgConfig) pkg_check_modules(yaml-cpp yaml-cpp REQUIRED) -pkg_check_modules(mastodonpp mastodonpp REQUIRED) +pkg_check_modules(dpp dpp REQUIRED) add_subdirectory(vendor/verbly) include_directories( - ${mastodonpp_INCLUDE_DIRS} + ${dpp_INCLUDE_DIRS} vendor/verbly/lib ${yaml-cpp_INCLUDE_DIRS} vendor/json) link_directories( - ${mastodonpp_LIBRARY_DIRS} + ${dpp_LIBRARY_DIRS} ${yaml-cpp_LIBRARY_DIRS}) add_executable(lingo lingo.cpp) set_property(TARGET lingo PROPERTY CXX_STANDARD 17) set_property(TARGET lingo PROPERTY CXX_STANDARD_REQUIRED ON) -target_link_libraries(lingo verbly ${mastodonpp_LIBRARIES} ${yaml-cpp_LIBRARIES}) +target_link_libraries(lingo verbly ${dpp_LIBRARIES} ${yaml-cpp_LIBRARIES}) diff --git a/lingo.cpp b/lingo.cpp index b549804..b417ffb 100644 --- a/lingo.cpp +++ b/lingo.cpp @@ -1,8 +1,9 @@ -#include +#include #include #include #include #include +#include #include #include #include @@ -54,12 +55,34 @@ int main(int argc, char** argv) std::string configfile(argv[1]); YAML::Node config = YAML::LoadFile(configfile); - verbly::database database(config["verbly_datafile"].as()); + std::map answer_by_message; + std::mutex answers_mutex; + + dpp::cluster bot(config["discord_token"].as()); + bot.on_message_create([&bot, &answers_mutex, &answer_by_message](const dpp::message_create_t& event) { + std::lock_guard answer_lock(answers_mutex); + if (answer_by_message.count(event.msg.message_reference.message_id)) + { + std::string canonical_answer = hatkirby::lowercase(answer_by_message[event.msg.message_reference.message_id]); + std::string canonical_attempt = hatkirby::lowercase(event.msg.content); + while (canonical_attempt.find("||") != std::string::npos) + { + canonical_attempt.erase(canonical_attempt.find("||"), 2); + } + + if (canonical_attempt == canonical_answer) + { + bot.message_add_reaction(event.msg.id, event.msg.channel_id, "✅"); + } else { + bot.message_add_reaction(event.msg.id, event.msg.channel_id, "❌"); + } + } + }); + bot.start(); - /*mastodonpp::Instance instance{ - config["mastodon_instance"].as(), - config["mastodon_token"].as()}; - mastodonpp::Connection connection{instance};*/ + dpp::snowflake channel(config["discord_channel"].as()); + + verbly::database database(config["verbly_datafile"].as()); std::set> filters = { {kTop, kPurple}, @@ -85,161 +108,42 @@ int main(int argc, char** argv) for (;;) { - bool puzzleEmpty = true; - std::array, kHeightCount> parts; - for (int height = 0; height < static_cast(kHeightCount); height++) { - if (std::bernoulli_distribution(0.5)(rng)) { - int colour = std::uniform_int_distribution(0, static_cast(kColourCount)-1)(rng); - if (filters.count({static_cast(height), static_cast(colour)})) { - parts[static_cast(height)] = static_cast(colour); - puzzleEmpty = false; + try + { + int hints = 0; + std::array, kHeightCount> parts; + for (int height = 0; height < static_cast(kHeightCount); height++) { + if (std::bernoulli_distribution(0.5)(rng)) { + int colour = std::uniform_int_distribution(0, static_cast(kColourCount)-1)(rng); + if (filters.count({static_cast(height), static_cast(colour)})) { + parts[static_cast(height)] = static_cast(colour); + hints++; + } } } - } - if (puzzleEmpty) { - continue; - } - - verbly::filter forwardFilter = cleanFilter && (verbly::form::proper == false); - for (int i=0; i(kHeightCount); i++) { - Height height = static_cast(i); - std::optional& colour = parts[i]; - if (!colour.has_value()) { + if (hints < 2) { continue; } - switch (*colour) { - case kWhite: { - switch (height) { - case kBottom: { - forwardFilter &= (verbly::word::synonyms %= wordFilter); - break; - } - case kTop: { - forwardFilter &= (verbly::form::pronunciations %= - verbly::filter("homophones", false, - (verbly::pronunciation::forms %= (wordFilter && verbly::filter( - verbly::form::id, - verbly::filter::comparison::field_does_not_equal, - verbly::form::id))))); - break; - } - default: break; // Not supposed yet. - } - break; - } - case kBlack: { - switch (height) { - case kBottom: { - forwardFilter &= (verbly::word::antonyms %= wordFilter); - break; - } - default: break; // Not supposed yet. - } - break; - } - case kBrown: { - switch (height) { - case kBottom: { - forwardFilter &= (verbly::notion::causes %= wordFilter); - break; - } - default: break; // Not supposed yet. - } - break; - } - case kRed: { - switch (height) { - case kTop: { - forwardFilter &= (verbly::pronunciation::holophones %= wordFilter); - break; - } - case kMiddle: { - forwardFilter &= (verbly::form::holographs %= wordFilter); - break; - } - case kBottom: { - forwardFilter &= (verbly::notion::partMeronyms %= wordFilter); - break; - } - default: break; // Not supposed yet. - } - break; - } - case kBlue: { - switch (height) { - case kTop: { - forwardFilter &= (verbly::pronunciation::merophones %= wordFilter); - break; - } - case kMiddle: { - forwardFilter &= (verbly::form::merographs %= wordFilter); - break; - } - case kBottom: { - forwardFilter &= (verbly::notion::partHolonyms %= wordFilter); - break; - } - default: break; // Not supposed yet. - } - break; - } - case kPurple: { - switch (height) { - case kMiddle: { - forwardFilter &= (verbly::form::merographs %= (verbly::form::length >= 4 && (verbly::form::holographs %= wordFilter))); - break; - } - case kTop: { - forwardFilter &= (verbly::pronunciation::rhymes %= wordFilter); - break; - } - default: break; // Not supposed yet. - } - break; - } - case kYellow: { - switch (height) { - case kTop: { - forwardFilter &= (verbly::pronunciation::anaphones %= (wordFilter && verbly::filter( - verbly::pronunciation::id, - verbly::filter::comparison::field_does_not_equal, - verbly::pronunciation::id))); - break; - } - case kMiddle: { - forwardFilter &= (verbly::form::anagrams %= (wordFilter && verbly::filter( - verbly::form::id, - verbly::filter::comparison::field_does_not_equal, - verbly::form::id))); - break; - } - default: break; // Not supposed yet. - } - break; - } - default: break; // Not supposed yet. - } - } - verbly::form solution = database.forms(forwardFilter).first(); - - for (int i=0; i(kHeightCount); i++) { - Height height = static_cast(i); - std::optional& colour = parts[i]; - if (colour.has_value()) { - verbly::filter questionFilter; + verbly::filter forwardFilter = cleanFilter && (verbly::form::proper == false); + for (int i=0; i(kHeightCount); i++) { + Height height = static_cast(i); + std::optional& colour = parts[i]; + if (!colour.has_value()) { + continue; + } switch (*colour) { case kWhite: { switch (height) { case kBottom: { - questionFilter = (verbly::word::synonyms %= solution); + forwardFilter &= (verbly::word::synonyms %= wordFilter); break; } case kTop: { - questionFilter = (verbly::form::pronunciations %= + forwardFilter &= (verbly::form::pronunciations %= verbly::filter("homophones", false, - (verbly::pronunciation::forms %= ((verbly::filter)solution && verbly::filter( + (verbly::pronunciation::forms %= (wordFilter && verbly::filter( verbly::form::id, verbly::filter::comparison::field_does_not_equal, verbly::form::id))))); @@ -252,7 +156,7 @@ int main(int argc, char** argv) case kBlack: { switch (height) { case kBottom: { - questionFilter = (verbly::word::antonyms %= solution); + forwardFilter &= (verbly::word::antonyms %= wordFilter); break; } default: break; // Not supposed yet. @@ -262,51 +166,43 @@ int main(int argc, char** argv) case kBrown: { switch (height) { case kBottom: { - questionFilter = (verbly::notion::effects %= solution); + forwardFilter &= (verbly::notion::causes %= wordFilter); break; } default: break; // Not supposed yet. } break; } - case kBlue: { + case kRed: { switch (height) { case kTop: { - questionFilter = (verbly::pronunciation::holophones %= solution); + forwardFilter &= (verbly::pronunciation::holophones %= wordFilter); break; } case kMiddle: { - questionFilter = (verbly::form::holographs %= solution); + forwardFilter &= (verbly::form::holographs %= wordFilter); break; } case kBottom: { - /*questionFilter = ((verbly::notion::fullMemberHolonyms %= solution) - || (verbly::notion::fullPartHolonyms %= solution) - || (verbly::notion::fullSubstanceHolonyms %= solution));*/ - //questionFilter &= !(verbly::notion::words %= solution); - questionFilter = (verbly::notion::partMeronyms %= solution); + forwardFilter &= (verbly::notion::partMeronyms %= wordFilter); break; } default: break; // Not supposed yet. } break; } - case kRed: { + case kBlue: { switch (height) { case kTop: { - questionFilter = (verbly::pronunciation::merophones %= solution); + forwardFilter &= (verbly::pronunciation::merophones %= wordFilter); break; } case kMiddle: { - questionFilter = (verbly::form::merographs %= solution); + forwardFilter &= (verbly::form::merographs %= wordFilter); break; } case kBottom: { - /*questionFilter = ((verbly::notion::fullMemberMeronyms %= solution) - || (verbly::notion::fullPartMeronyms %= solution) - || (verbly::notion::fullSubstanceMeronyms %= solution));*/ - questionFilter = (verbly::notion::partHolonyms %= solution); - //questionFilter &= !(verbly::notion::words %= solution); + forwardFilter &= (verbly::notion::partHolonyms %= wordFilter); break; } default: break; // Not supposed yet. @@ -315,12 +211,12 @@ int main(int argc, char** argv) } case kPurple: { switch (height) { - case kTop: { - questionFilter = (verbly::pronunciation::rhymes %= solution); + case kMiddle: { + forwardFilter &= (verbly::form::merographs %= (verbly::form::length >= 4 && (verbly::form::holographs %= wordFilter))); break; } - case kMiddle: { - questionFilter = (verbly::form::merographs %= (verbly::form::length >= 4 && (verbly::form::holographs %= solution))); + case kTop: { + forwardFilter &= (verbly::pronunciation::rhymes %= wordFilter); break; } default: break; // Not supposed yet. @@ -330,17 +226,17 @@ int main(int argc, char** argv) case kYellow: { switch (height) { case kTop: { - questionFilter = (verbly::pronunciation::anaphones %= ((verbly::filter)solution && verbly::filter( - verbly::pronunciation::id, - verbly::filter::comparison::field_does_not_equal, - verbly::pronunciation::id))); + forwardFilter &= (verbly::pronunciation::anaphones %= (wordFilter && verbly::filter( + verbly::pronunciation::id, + verbly::filter::comparison::field_does_not_equal, + verbly::pronunciation::id))); break; } case kMiddle: { - questionFilter = (verbly::form::anagrams %= ((verbly::filter)solution && verbly::filter( - verbly::form::id, - verbly::filter::comparison::field_does_not_equal, - verbly::form::id))); + forwardFilter &= (verbly::form::anagrams %= (wordFilter && verbly::filter( + verbly::form::id, + verbly::filter::comparison::field_does_not_equal, + verbly::form::id))); break; } default: break; // Not supposed yet. @@ -349,16 +245,163 @@ int main(int argc, char** argv) } default: break; // Not supposed yet. } - verbly::form questionPart = database.forms(questionFilter && cleanFilter).first(); - std::cout << COLOUR_EMOJIS[*colour] << " " << questionPart.getText() << std::endl; - } else { - std::cout << "▪️" << std::endl; } - } - std::cout << "(" << solution.getText().size() << ")" << std::endl << std::endl << solution.getText() << std::endl; + verbly::form solution = database.forms(forwardFilter).first(); + + std::ostringstream msg_stream; + for (int i=0; i(kHeightCount); i++) { + Height height = static_cast(i); + std::optional& colour = parts[i]; + if (colour.has_value()) { + verbly::filter questionFilter; + switch (*colour) { + case kWhite: { + switch (height) { + case kBottom: { + questionFilter = (verbly::word::synonyms %= solution); + break; + } + case kTop: { + questionFilter = (verbly::form::pronunciations %= + verbly::filter("homophones", false, + (verbly::pronunciation::forms %= ((verbly::filter)solution && verbly::filter( + verbly::form::id, + verbly::filter::comparison::field_does_not_equal, + verbly::form::id))))); + break; + } + default: break; // Not supposed yet. + } + break; + } + case kBlack: { + switch (height) { + case kBottom: { + questionFilter = (verbly::word::antonyms %= solution); + break; + } + default: break; // Not supposed yet. + } + break; + } + case kBrown: { + switch (height) { + case kBottom: { + questionFilter = (verbly::notion::effects %= solution); + break; + } + default: break; // Not supposed yet. + } + break; + } + case kBlue: { + switch (height) { + case kTop: { + questionFilter = (verbly::pronunciation::holophones %= solution); + break; + } + case kMiddle: { + questionFilter = (verbly::form::holographs %= solution); + break; + } + case kBottom: { + /*questionFilter = ((verbly::notion::fullMemberHolonyms %= solution) + || (verbly::notion::fullPartHolonyms %= solution) + || (verbly::notion::fullSubstanceHolonyms %= solution));*/ + //questionFilter &= !(verbly::notion::words %= solution); + questionFilter = (verbly::notion::partMeronyms %= solution); + break; + } + default: break; // Not supposed yet. + } + break; + } + case kRed: { + switch (height) { + case kTop: { + questionFilter = (verbly::pronunciation::merophones %= solution); + break; + } + case kMiddle: { + questionFilter = (verbly::form::merographs %= solution); + break; + } + case kBottom: { + /*questionFilter = ((verbly::notion::fullMemberMeronyms %= solution) + || (verbly::notion::fullPartMeronyms %= solution) + || (verbly::notion::fullSubstanceMeronyms %= solution));*/ + questionFilter = (verbly::notion::partHolonyms %= solution); + //questionFilter &= !(verbly::notion::words %= solution); + break; + } + default: break; // Not supposed yet. + } + break; + } + case kPurple: { + switch (height) { + case kTop: { + questionFilter = (verbly::pronunciation::rhymes %= solution); + break; + } + case kMiddle: { + questionFilter = (verbly::form::merographs %= (verbly::form::length >= 4 && (verbly::form::holographs %= solution))); + break; + } + default: break; // Not supposed yet. + } + break; + } + case kYellow: { + switch (height) { + case kTop: { + questionFilter = (verbly::pronunciation::anaphones %= ((verbly::filter)solution && verbly::filter( + verbly::pronunciation::id, + verbly::filter::comparison::field_does_not_equal, + verbly::pronunciation::id))); + break; + } + case kMiddle: { + questionFilter = (verbly::form::anagrams %= ((verbly::filter)solution && verbly::filter( + verbly::form::id, + verbly::filter::comparison::field_does_not_equal, + verbly::form::id))); + break; + } + default: break; // Not supposed yet. + } + break; + } + default: break; // Not supposed yet. + } + verbly::form questionPart = database.forms(questionFilter && cleanFilter).first(); + msg_stream << COLOUR_EMOJIS[*colour] << " " << questionPart.getText() << std::endl; + } else { + msg_stream << "▪️" << std::endl; + } + } + msg_stream << "(" << solution.getText().size() << ")"; + + std::string message_text = msg_stream.str(); + std::cout << message_text << std::endl << std::endl << solution.getText() << std::endl; + + dpp::message message(channel, message_text); + bot.message_create(message, [&answers_mutex, &answer_by_message, &solution](const dpp::confirmation_callback_t& userdata) { + const auto& posted_msg = std::get(userdata.value); + std::lock_guard answer_lock(answers_mutex); + if (answer_by_message.size() > 3000) + { + answer_by_message.clear(); + } + answer_by_message[posted_msg.id] = solution.getText(); + }); + + std::this_thread::sleep_for(std::chrono::hours(3)); + } catch (const std::exception& ex) { + std::cout << ex.what() << std::endl; + } - // We can poll the timeline at most once every five minutes. - std::this_thread::sleep_for(std::chrono::hours(3)); + std::this_thread::sleep_for(std::chrono::minutes(1)); } } -- cgit 1.4.1