Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 44 additions & 2 deletions src/commands/beginner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,50 @@ void cmd::beginnerCommand(dpp::cluster& bot, const dpp::slashcommand_t& event)
{
const dpp::embed embed = dpp::embed()
.set_color(globals::color::defaultColor)
.add_field("👋 New to C++? Start here!", "If you're learning C++, we recommend these resources:\n\n📘 **Learn C++ (Best beginner tutorial)**\n- https://www.learncpp.com/\n\n📖 **CPP Reference (Language & Standard library reference)**\n- https://en.cppreference.com/\n\n🛠️ **Practice**\n1. Build small projects\n2. Read and write lots of code\n\n**Common advice:**\n* ✅ Learn modern C++, not C with classes\n* ✅ Avoid outdated books, videos, and random blog posts that teach old C++ practices\n* ❌ Don't ask ChatGPT or other AI to write your code\n\nIf you're stuck on something specific, ask in the help channels: <#1130494190615265342>.\nBe sure to include your code, any error messages, what you've tried already, and what you expected to happen.");
.set_title("👋 New to C++? Start here!")
.set_url("https://www.learncpp.com/")
.set_description("Essential resources for C++ beginners")
.add_field("📘 **Best Beginner Tutorial**",
"LearnCpp.com is widely considered the best free resource:\nhttps://www.learncpp.com/", false)
.add_field("📖 **CPP Reference**",
"The definitive C++ language reference:\nhttps://en.cppreference.com/", false)
.add_field("🛠️ **Practice**",
"Start with small projects:\n"
"- Calculator\n"
"- Guess game\n"
"- Dice game", false)
.add_field("✅ **Do this**",
"- Learn Modern C++\n"
"- Use a great IDE\n"
"- Practice what you learn\n"
"- Learn OOP basics\n"
"- Write clean, readable code", true)
.add_field("❌ **Dont do this**",
"- Don't learn from outdated C++ resources\n"
"- Don't let AI write code for you\n"
"- Don't use `using namespace std;` (it's bad practice)\n"
"- Don't ignore compiler warnings", true)
.set_footer(dpp::embed_footer()
.set_text("Need help? Ask in <#" + std::to_string(globals::channels::HELP_CHANNEL_ID) + ">"))
.set_timestamp(dpp::utility::time_f());

const dpp::message message(event.command.channel_id, embed);
dpp::message message(event.command.channel_id, embed);
message.add_component(
dpp::component()
.add_component(
dpp::component()
.set_type(dpp::cot_button)
.set_label("Learn C++")
.set_url("https://www.learncpp.com/")
.set_style(dpp::cos_link)
)
.add_component(
dpp::component()
.set_type(dpp::cot_button)
.set_label("CPP Reference")
.set_url("https://en.cppreference.com/")
.set_style(dpp::cos_link)
)
);
event.reply(message);
}
97 changes: 89 additions & 8 deletions src/commands/coding_cmd.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,96 @@
#include "commands.h"
#include "../globals/globals.h"
#include <fstream>
#include <random>
#include <algorithm>
#include <map>
#include <vector>
#include <string>

namespace cmd
{
namespace coding
{
const std::map<std::string, std::string> difficultyFiles = {
{"Beginner", "src/res/coding/beginner.txt"},
{"Intermediate", "src/res/coding/intermediate.txt"},
{"Advanced", "src/res/coding/advanced.txt"},
{"Expert", "src/res/coding/expert.txt"},
{"Master", "src/res/coding/master.txt"}
};

std::map<std::string, std::vector<std::string>> questionCache;
bool loaded = false;

void loadQuestions() {
if (loaded) return;

for (const auto& [difficulty, filepath] : difficultyFiles) {
std::ifstream file(filepath);

if (!file.is_open()) {
std::cerr << "Failed to open: " << filepath << std::endl;
continue;
}

std::vector<std::string> questions;
std::string line;

while (std::getline(file, line)) {
if (!line.empty()) {
questions.push_back(line);
}
}
file.close();

std::random_device rd;
std::mt19937 gen(rd());
std::shuffle(questions.begin(), questions.end(), gen);

questionCache[difficulty] = questions;
}
loaded = true;
}

std::string getRandomQuestion(const std::string& difficulty) {
auto it = questionCache.find(difficulty);
if (it == questionCache.end() || it->second.empty()) {
return "No questions available for " + difficulty + " difficulty.";
}

static std::map<std::string, int> indices;
int& index = indices[difficulty];
const std::vector<std::string>& questions = it->second;

std::string question = questions[index % questions.size()];
index++;

return question;
}
}
}

void cmd::codingCommand(dpp::cluster& bot, const dpp::slashcommand_t& event)
{
static int index;
const std::string question = cmd::utils::readFileLine("res/coding.txt", index);
{
coding::loadQuestions();
std::string difficulty = "Beginner";
try {
auto param = event.get_parameter("difficulty");
if (!std::holds_alternative<std::monostate>(param)) {
difficulty = std::get<std::string>(param);
}
}
catch (...) {}

const dpp::embed embed = dpp::embed()
std::string question = coding::getRandomQuestion(difficulty);
dpp::embed embed = dpp::embed()
.set_color(globals::color::defaultColor)
.add_field(question, "");
.set_title("Coding Challenge - " + difficulty)
.set_description(question)
.add_field("Difficulty", difficulty, true)
.add_field("Need help?", "Ask in <#" + std::to_string(globals::channels::HELP_CHANNEL_ID) + ">", true)
.set_footer(dpp::embed_footer().set_text("Good luck! Share your solution in #code-review"))
.set_timestamp(time(0));

const dpp::message message(event.command.channel_id, embed);
event.reply(message);
}
event.reply(embed);
}
18 changes: 9 additions & 9 deletions src/commands/commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
#include <dpp/dispatcher.h>

namespace cmd
{
{
/**
* @brief Replies with a question in the chat to change the topic
* @param bot cluster
* @brief Replies with a question in the chat to change the topic
* @param bot cluster
* @param event slash command event
*/
void topicCommand(dpp::cluster& bot, const dpp::slashcommand_t& event);
Expand Down Expand Up @@ -63,7 +63,7 @@ namespace cmd
* @param event slash command event
*/
void ruleCommand(dpp::cluster& bot, const dpp::slashcommand_t& event);

/**
* @brief Replies with a beginner's guide to C++
* @param bot cluster
Expand All @@ -72,27 +72,27 @@ namespace cmd
void beginnerCommand(dpp::cluster& bot, const dpp::slashcommand_t& event);

namespace utils
{
{
/**
* @brief Read next line of file, jump to beginning if no next line
* @param path to the file
* @param index
* @return content of next line
*/
std::string readFileLine(const std::string& path, int& index);
}
}
}

struct cmdStruct
{
{
std::string name;
std::string desc;

typedef std::function<void(dpp::cluster&, dpp::slashcommand_t)> cmdFunc;
cmdFunc function;

std::list<dpp::command_option> args;
std::vector<dpp::command_option> args;
dpp::permissions permissions;
};
};

#endif // COMMANDS_H
5 changes: 5 additions & 0 deletions src/globals/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ namespace globals
static constexpr int defaultColor = 0x004482;
}

namespace channels
{
constexpr dpp::snowflake HELP_CHANNEL_ID = 1130466207431135394ULL;
}

/**
* @brief Load configured IDs used by the bot.
* @param config Parsed config JSON object.
Expand Down
45 changes: 27 additions & 18 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,34 @@ using json = nlohmann::json;
std::vector<cmdStruct> cmdList = {
{ "topic", "Get a topic question", cmd::topicCommand },
{ "beginner", "Get a beginner's guide to C++", cmd::beginnerCommand },
{ "coding", "Get a coding question", cmd::codingCommand },
{ "coding", "Get a coding question", cmd::codingCommand,
{
dpp::command_option(dpp::co_string, "difficulty", "Select difficulty", false)
.add_choice(dpp::command_option_choice("Beginner", "Beginner"))
.add_choice(dpp::command_option_choice("Intermediate", "Intermediate"))
.add_choice(dpp::command_option_choice("Advanced", "Advanced"))
.add_choice(dpp::command_option_choice("Expert", "Expert"))
.add_choice(dpp::command_option_choice("Master", "Master"))
}
},
{ "close", "Close a ticket or forum post", cmd::closeCommand },
{ "ticket", "Open a ticket", cmd::ticketCommand, { dpp::command_option(dpp::command_option_type::co_user, "participant", "Add participant", false) }},
{ "code", "Formatting code on Discord", cmd::codeCommand },
{ "project", "Get a project idea", cmd::projectCommand },
{ "rule", "Get the server rules", cmd::ruleCommand, { dpp::command_option(dpp::command_option_type::co_integer, "number", "Rule to mention", false) }}
};
};

int main()
{
{
std::ifstream configFile("config.json");
json config = json::parse(configFile);

std::string globalsConfigError;
if (!globals::loadFromConfig(config, globalsConfigError))
{
{
std::cerr << "[!] Invalid configuration: " << globalsConfigError << std::endl;
return 1;
}
}

dpp::cluster bot(config["token"], dpp::i_default_intents | dpp::i_message_content);
ModerationService moderationService(bot);
Expand All @@ -41,10 +50,10 @@ int main()
bot.set_presence(dpp::presence(dpp::presence_status::ps_online, dpp::activity_type::at_watching, "cppdiscord.com"));

if (dpp::run_once<struct bulkRegister>())
{
{
std::vector<dpp::slashcommand> slashcommands;
for (const auto& item : cmdList)
{
{
dpp::slashcommand slashCommand;
slashCommand.set_name(item.name);
slashCommand.set_description(item.desc);
Expand All @@ -57,21 +66,21 @@ int main()
slashCommand.set_default_permissions(dpp::permission(item.permissions));

slashcommands.push_back(slashCommand);
}
}
bot.global_bulk_command_create(slashcommands);
}
});
}
});

bot.on_slashcommand([&bot](const dpp::slashcommand_t& event) {
for (const auto& item : cmdList)
{
if (item.name == event.command.get_command_name())
{
if (item.name == event.command.get_command_name())
{
item.function(bot, event);
return;
}
}
}
});
});

bot.on_message_create([&bot, &moderationService](const dpp::message_create_t& event) {
if (moderationService.handleMessage(event))
Expand All @@ -81,7 +90,7 @@ int main()

if (channel && channel->name == "suggestions")
utils::suggestion::createSuggestion(bot, event);
});
});

bot.on_button_click([&bot](const dpp::button_click_t& event) {
if (event.custom_id == "delSuggestion")
Expand All @@ -90,13 +99,13 @@ int main()
utils::suggestion::editSuggestion(bot, event);
else if (event.custom_id.starts_with("hint_button_"))
cmd::handleProjectHintButton(bot, event);
});
});

bot.on_form_submit([&bot](const dpp::form_submit_t& event) {
if (event.custom_id == "editModal")
utils::suggestion::showSuggestionEditModal(bot, event);
});
});

bot.start(dpp::st_wait);
return 0;
}
}
60 changes: 60 additions & 0 deletions src/res/coding/advanced.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
What is the difference between std::list and std::vector?
What is the difference between std::endl and '\n'?
How does the static keyword affect a class member?
What is the purpose of the decltype keyword?
What is move semantics in C++?
What is perfect forwarding?
What are variadic templates?
What is SFINAE?
What is the difference between lvalue and rvalue?
What are smart pointers and why use them?
What is the rule of three/five/zero?
What is CRTP (Curiously Recurring Template Pattern)?
What is type erasure in C++?
What is the difference between std::function and a function pointer?
What is the difference between std::shared_ptr and std::unique_ptr?
What is the difference between std::weak_ptr and std::shared_ptr?
What is the difference between std::move and std::forward?
What is the difference between std::vector and std::deque?
What is the difference between std::map and std::unordered_map?
What is the difference between std::set and std::unordered_set?
What is the difference between std::multiset and std::set?
What is the difference between std::multimap and std::map?
What is the difference between std::array and std::vector?
What is the difference between std::string and std::string_view?
What is the difference between std::tuple and std::pair?
What is the difference between std::variant and std::any?
What is the difference between std::optional and std::variant?
What is the difference between std::async and std::thread?
What is the difference between std::mutex and std::recursive_mutex?
What is the difference between std::lock_guard and std::unique_lock?
What is the difference between std::atomic and std::mutex?
What is the difference between std::condition_variable and std::atomic?
What is the difference between std::future and std::promise?
What is the difference between std::packaged_task and std::async?
What is the difference between std::chrono::system_clock and std::chrono::steady_clock?
What is the difference between std::istream and std::ostream?
What is the difference between std::ifstream and std::ofstream?
What is the difference between std::stringstream and std::fstream?
What is the difference between std::ios::in and std::ios::out?
What is the difference between std::ios::app and std::ios::ate?
What is the difference between std::ios::binary and std::ios::text?
What is the difference between std::exception and std::logic_error?
What is the difference between std::runtime_error and std::logic_error?
What is the difference between std::bad_alloc and std::bad_cast?
What is the difference between std::bad_typeid and std::bad_exception?
What is the difference between std::uncaught_exception and std::uncaught_exceptions?
What is the difference between std::terminate and std::abort?
What is the difference between std::set_terminate and std::set_unexpected?
What is the difference between std::nothrow and std::terminate?
What is the difference between std::make_shared and std::shared_ptr?
What is the difference between std::make_unique and std::unique_ptr?
What is the difference between std::allocator and std::pmr::polymorphic_allocator?
What is the difference between std::vector<bool> and std::vector<char>?
What is the difference between std::initializer_list and std::array?
What is the difference between std::span and std::array_view?
What is the difference between std::byte and char?
What is the difference between std::error_code and std::error_condition?
What is the difference between std::system_error and std::logic_error?
What is the difference between std::filesystem::path and std::string?
What is the difference between std::filesystem::directory_iterator and std::filesystem::recursive_directory_iterator?
Loading