diff --git a/doc/README.md b/doc/README.md index 3e00ed9..df7e1c0 100644 --- a/doc/README.md +++ b/doc/README.md @@ -56,7 +56,7 @@ make #### 手动编译 ```bash cd src -g++ -std=c++17 -Wall -Wextra -O2 -o math_exam_generator main.cpp +g++ -std=c++17 -Wall -Wextra -O2 -o math_exam_generator main.cc app.cc auth.cc exam.cc login.cc utils.cc ``` ### 运行程序 @@ -100,14 +100,14 @@ cd src │ └── README_root.md # 根目录的README └── src/ # 源代码目录 ├── Makefile # 编译配置文件 - ├── app.cpp # 应用逻辑 - ├── auth.cpp # 用户认证模块 - ├── exam.cpp # 试卷生成模块 + ├── app.cc # 应用逻辑 + ├── auth.cc # 用户认证模块 + ├── exam.cc # 试卷生成模块 ├── include/ # 头文件目录 - ├── login.cpp # 登录逻辑 - ├── main.cpp # 主程序入口 + ├── login.cc # 登录逻辑 + ├── main.cc # 主程序入口 ├── math_exam_generator.exe # 编译后的可执行文件 - └── utils.cpp # 工具函数 + └── utils.cc # 工具函数 ``` *注:程序运行时,会在`src`目录下自动生成`paper`文件夹,用于存放用户生成的试卷。* @@ -144,10 +144,12 @@ src/ ## 技术特点 - **面向对象设计**:使用类封装功能模块 -- **STL容器**:使用 vector、map、set 等容器管理数据 -- **文件系统操作**:使用 C++17 filesystem 库进行文件管理 -- **随机数生成**:使用现代C++随机数生成器 -- **异常处理**:对用户输入进行验证和异常处理 +- **STL 容器**:使用 vector、map、set 等容器管理数据 +- **文件系统操作**:使用 C++17 `` 进行文件管理 +- **随机数生成**:使用现代 C++ 随机数生成器 +- **显式输入校验**:对用户输入进行验证,避免使用异常进行控制流 +- **统一命名与常量**:函数采用 UpperCamelCase,常量统一 `k` 前缀 +- **头文件守卫**:统一为 `MEG_*_H_` 形式,保持一致性 ## 开发环境 diff --git a/src/Makefile b/src/Makefile index e961a40..e606f23 100644 --- a/src/Makefile +++ b/src/Makefile @@ -11,8 +11,8 @@ else endif TARGET := math_exam_generator -SRCS := main.cpp app.cpp auth.cpp exam.cpp login.cpp utils.cpp -OBJS := $(SRCS:.cpp=.o) +SRCS := main.cc app.cc auth.cc exam.cc login.cc utils.cc +OBJS := $(SRCS:.cc=.o) all: $(TARGET) @@ -20,7 +20,7 @@ $(TARGET): $(OBJS) $(CXX) $(CXXFLAGS) -o $@ $^ -$(RM) $(OBJS) -%.o: %.cpp +%.o: %.cc $(CXX) $(CXXFLAGS) -c $< -o $@ .PHONY: clean diff --git a/src/app.cc b/src/app.cc new file mode 100644 index 0000000..1d63ea4 --- /dev/null +++ b/src/app.cc @@ -0,0 +1,103 @@ +#include "include/app.h" +#include "include/utils.h" + +#include +#include +#include +#include +#include + +namespace fs = std::filesystem; + +namespace meg { + +// 应用程序构造函数: +// 初始化题目生成器的具体实现(通过抽象接口进行多态管理) +App::App() { + exam_ = std::make_unique(); +} + +// 处理登录后交互流程: +// - 支持用户通过命令切换题目难度(小学/初中/高中) +// - 显式校验数字输入并生成试卷,避免使用异常进行控制流 +void App::handle_logged_in() { + if (!current_user_) return; + current_level_ = current_user_->level; + + while (true) { + std::wcout << L"准备生成" << LevelToChinese(current_level_) << L"数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):"; + std::wcout.flush(); + std::wstring line; + if (!std::getline(std::wcin, line)) return; // EOF + line = Trim(line); + if (line.empty()) continue; + + if (line == L"-1") { + std::wcout << L"已退出登录。" << '\n'; + current_user_.reset(); + return; + } + + // 支持命令:切换为小学/初中/高中 + if (StartsWith(line, L"切换为")) { + std::wstring t = line.substr(3); + t = Trim(t); + if (t == L"小学") current_level_ = Level::Primary; + else if (t == L"初中") current_level_ = Level::Middle; + else if (t == L"高中") current_level_ = Level::High; + else { + std::wcout << L"不支持的类型:" << t << '\n'; + continue; + } + std::wcout << L"已切换为" << LevelToChinese(current_level_) << L"。" << '\n'; + continue; + } + + // 显式校验输入为数字,避免异常 + std::string ascii(line.begin(), line.end()); + bool all_digits = !ascii.empty() && std::all_of(ascii.begin(), ascii.end(), [](unsigned char c){ return std::isdigit(c); }); + if (!all_digits) { + std::wcout << L"请输入正确的数字,或使用指令如:切换为初中。" << '\n'; + continue; + } + int n = std::stoi(ascii); + if (n < 10 || n > 30) { + std::wcout << L"请输入 10-30 之间的数字。" << '\n'; + continue; + } + + fs::path base = fs::path("paper") / current_user_->username; + fs::create_directories(base); + auto history_path = base / ".history.txt"; + auto history = exam_->load_history(history_path); + auto questions = exam_->GenerateUnique(current_level_, n, history); + // 保存试卷 + std::string ts = NowTimestampStr(); + fs::path outfile = base / (ts + ".txt"); + std::ofstream fout(outfile); + for (size_t i = 0; i < questions.size(); ++i) { + fout << (i + 1) << ". " << questions[i] << "\n\n"; + } + fout.close(); + exam_->append_history(history_path, questions); + + std::wcout << L"已生成试卷:" << outfile.wstring() << '\n'; + } +} + +void App::run() { + InitConsoleLocale(); + std::wcout << L"中小学数学卷子自动生成程序" << '\n'; + while (true) { + if (!current_user_) { + auto u = login_.prompt_login(); + if (!u) return; // EOF 退出 + current_user_ = u; + current_level_ = current_user_->level; + } else { + handle_logged_in(); + } + } +} + +} // namespace meg \ No newline at end of file diff --git a/src/app.cpp b/src/app.cpp deleted file mode 100644 index 258b77d..0000000 --- a/src/app.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include "include/app.hpp" -#include "include/utils.hpp" - -#include -#include -#include - -namespace fs = std::filesystem; - -namespace meg { - -App::App() {} - -void App::handle_logged_in() { - if (!current_user_) return; - current_level_ = current_user_->level; - - while (true) { - std::wcout << L"准备生成" << level_to_chinese(current_level_) << L"数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):"; - std::wcout.flush(); - std::wstring line; - if (!std::getline(std::wcin, line)) return; // EOF - line = trim(line); - if (line.empty()) continue; - - if (line == L"-1") { - std::wcout << L"已退出登录。" << std::endl; - current_user_.reset(); - return; - } - - // 支持命令:切换为小学/初中/高中 - if (starts_with(line, L"切换为")) { - std::wstring t = line.substr(3); - t = trim(t); - if (t == L"小学") current_level_ = Level::Primary; - else if (t == L"初中") current_level_ = Level::Middle; - else if (t == L"高中") current_level_ = Level::High; - else { - std::wcout << L"不支持的类型:" << t << std::endl; - continue; - } - std::wcout << L"已切换为" << level_to_chinese(current_level_) << L"。" << std::endl; - continue; - } - - // 尝试解析数量 - try { - int n = std::stoi(std::string(line.begin(), line.end())); - if (n < 10 || n > 30) { - std::wcout << L"请输入 10-30 之间的数字。" << std::endl; - continue; - } - - fs::path base = fs::path("paper") / current_user_->username; - fs::create_directories(base); - auto history_path = base / ".history.txt"; - auto history = exam_.load_history(history_path); - auto questions = exam_.generate_unique(current_level_, n, history); - // 保存试卷 - std::string ts = now_timestamp_str(); - fs::path outfile = base / (ts + ".txt"); - std::ofstream fout(outfile); - for (size_t i = 0; i < questions.size(); ++i) { - fout << (i + 1) << ". " << questions[i] << "\n\n"; - } - fout.close(); - exam_.append_history(history_path, questions); - - std::wcout << L"已生成试卷:" << outfile.wstring() << std::endl; - } catch (...) { - std::wcout << L"请输入正确的数字,或使用指令如:切换为初中。" << std::endl; - } - } -} - -void App::run() { - init_console_locale(); - std::wcout << L"中小学数学卷子自动生成程序" << std::endl; - while (true) { - if (!current_user_) { - auto u = login_.prompt_login(); - if (!u) return; // EOF 退出 - current_user_ = u; - current_level_ = current_user_->level; - } else { - handle_logged_in(); - } - } -} - -} // namespace meg \ No newline at end of file diff --git a/src/auth.cpp b/src/auth.cc similarity index 94% rename from src/auth.cpp rename to src/auth.cc index 02774e9..38750b2 100644 --- a/src/auth.cpp +++ b/src/auth.cc @@ -1,4 +1,4 @@ -#include "include/auth.hpp" +#include "include/auth.h" namespace meg { diff --git a/src/exam.cpp b/src/exam.cc similarity index 62% rename from src/exam.cpp rename to src/exam.cc index d22a57f..da51e79 100644 --- a/src/exam.cpp +++ b/src/exam.cc @@ -1,4 +1,4 @@ -#include "include/exam.hpp" +#include "include/exam.h" #include #include @@ -33,14 +33,15 @@ void ExamGenerator::append_history(const std::filesystem::path& history_path, co } } -std::vector ExamGenerator::generate_unique(Level level, int count, std::unordered_set& history) { +// 生成不重复题目:按难度生成并去重,限制尝试次数避免极端情况 +std::vector ExamGenerator::GenerateUnique(Level level, int count, std::unordered_set& history) { std::vector out; int attempts = 0; while ((int)out.size() < count && attempts < count * 50) { std::string q; - if (level == Level::Primary) q = gen_primary(); - else if (level == Level::Middle) q = gen_middle(); - else q = gen_high(); + if (level == Level::Primary) q = GenPrimary(); + else if (level == Level::Middle) q = GenMiddle(); + else q = GenHigh(); if (history.insert(q).second) { out.push_back(q); @@ -50,7 +51,8 @@ std::vector ExamGenerator::generate_unique(Level level, int count, return out; } -static std::string join_ops(const std::vector& nums, const std::vector& ops) { +// 将数字与运算符拼接为表达式字符串 +static std::string JoinOps(const std::vector& nums, const std::vector& ops) { std::string s; for (size_t i = 0; i < nums.size(); ++i) { s += std::to_string(nums[i]); @@ -63,37 +65,45 @@ static std::string join_ops(const std::vector& nums, const std::vector 1-2个操作符 std::vector nums; for (int i = 0; i < n_ops + 1; ++i) nums.push_back(rand_int(rng_, 1, 50)); - static const char all_ops[] = {'+', '-', '*', '/'}; + static const char kAllOps[] = {'+', '-', '*', '/'}; std::vector ops; - for (int i = 0; i < n_ops; ++i) ops.push_back(all_ops[rand_int(rng_, 0, 3)]); - std::string expr = join_ops(nums, ops); - // 适度加括号 - if (nums.size() >= 3 && rand_int(rng_, 0, 1)) { - size_t pos = expr.find(' '); - if (pos != std::string::npos) { - expr = "(" + expr.substr(0, pos) + ")" + expr.substr(pos); + for (int i = 0; i < n_ops; ++i) ops.push_back(kAllOps[rand_int(rng_, 0, 3)]); + std::string s; + if (n_ops == 1) { + // 两个操作数:不加括号 + s = std::to_string(nums[0]) + " " + std::string(1, ops[0]) + " " + std::to_string(nums[1]); + } else { + // 三个操作数:随机选择包裹首或末二元表达式 + bool wrap_first = (rand_int(rng_, 0, 1) == 1); + if (wrap_first) { + s = "(" + std::to_string(nums[0]) + " " + std::string(1, ops[0]) + " " + std::to_string(nums[1]) + ")"; + s += " " + std::string(1, ops[1]) + " " + std::to_string(nums[2]); + } else { + s = std::to_string(nums[0]) + " " + std::string(1, ops[0]) + " "; + s += "(" + std::to_string(nums[1]) + " " + std::string(1, ops[1]) + " " + std::to_string(nums[2]) + ")"; } } - return expr + " = ?"; + return s + " = ?"; } -std::string ExamGenerator::gen_middle() { +// 生成初中题目:包含平方或开方的表达式 +std::string ExamGenerator::GenMiddle() { int n_ops = rand_int(rng_, 2, 3); // 3-4 操作数 std::vector nums; for (int i = 0; i < n_ops + 1; ++i) nums.push_back(rand_int(rng_, 1, 100)); - static const char all_ops[] = {'+', '-', '*', '/'}; + static const char kAllOps[] = {'+', '-', '*', '/'}; std::vector ops; - for (int i = 0; i < n_ops; ++i) ops.push_back(all_ops[rand_int(rng_, 0, 3)]); - + for (int i = 0; i < n_ops; ++i) ops.push_back(kAllOps[rand_int(rng_, 0, 3)]); // 随机把一个数变成平方或开方 int idx = rand_int(rng_, 0, (int)nums.size() - 1); bool use_sqrt = rand_int(rng_, 0, 1) == 1; - std::string expr = join_ops(nums, ops); - + std::string expr = JoinOps(nums, ops); // 找到替换位置(简单方式:直接重新拼接) std::string s; for (size_t i = 0; i < nums.size(); ++i) { @@ -110,26 +120,24 @@ std::string ExamGenerator::gen_middle() { return s + " = ?"; } -std::string ExamGenerator::gen_high() { +// 生成高中题目:带三角函数项并可能平方或开方 +std::string ExamGenerator::GenHigh() { int n_ops = rand_int(rng_, 3, 4); // 4-5 操作数 std::vector nums; for (int i = 0; i < n_ops + 1; ++i) nums.push_back(rand_int(rng_, 1, 100)); - static const char all_ops[] = {'+', '-', '*', '/'}; + static const char kAllOps[] = {'+', '-', '*', '/'}; std::vector ops; - for (int i = 0; i < n_ops; ++i) ops.push_back(all_ops[rand_int(rng_, 0, 3)]); - + for (int i = 0; i < n_ops; ++i) ops.push_back(kAllOps[rand_int(rng_, 0, 3)]); // 先基础表达式 std::string base; for (size_t i = 0; i < nums.size(); ++i) { base += std::to_string(nums[i]); if (i < ops.size()) { base += ' '; base += ops[i]; base += ' '; } } - // 至少一个三角函数,角度用 30/45/60/90 之一,使用 "deg" 标识角度 static const char* funcs[] = {"sin", "cos", "tan"}; - static const int angles[] = {30, 45, 60, 90}; - std::string tri = std::string(funcs[rand_int(rng_, 0, 2)]) + "(" + std::to_string(angles[rand_int(rng_, 0, 3)]) + "deg)"; - + static const int kAngles[] = {30, 45, 60, 90}; + std::string tri = std::string(funcs[rand_int(rng_, 0, 2)]) + "(" + std::to_string(kAngles[rand_int(rng_, 0, 3)]) + "deg)"; // 随机把一个数替换为三角项 size_t replace_pos = rand_int(rng_, 0, (int)nums.size() - 1); // 重建字符串并替换 @@ -139,7 +147,6 @@ std::string ExamGenerator::gen_high() { s += term; if (i < ops.size()) { s += ' '; s += ops[i]; s += ' '; } } - // 同时可能再加平方或开方 if (rand_int(rng_, 0, 1)) { s = "(" + s + ")^2"; diff --git a/src/include/app.hpp b/src/include/app.h similarity index 54% rename from src/include/app.hpp rename to src/include/app.h index 4aca3dd..beb40be 100644 --- a/src/include/app.hpp +++ b/src/include/app.h @@ -1,11 +1,12 @@ -#ifndef MEG_APP_HPP -#define MEG_APP_HPP +#ifndef MEG_APP_H_ +#define MEG_APP_H_ #include +#include #include -#include "auth.hpp" -#include "login.hpp" -#include "exam.hpp" +#include "auth.h" +#include "login.h" +#include "exam.h" namespace meg { @@ -17,7 +18,8 @@ public: private: Auth auth_; LoginManager login_{auth_}; - ExamGenerator exam_; + // 使用多态:题目生成器接口指针,便于后续替换实现 + std::unique_ptr exam_; std::optional current_user_; Level current_level_ = Level::Primary; @@ -27,4 +29,4 @@ private: } // namespace meg -#endif // MEG_APP_HPP \ No newline at end of file +#endif // MEG_APP_H_ \ No newline at end of file diff --git a/src/include/auth.hpp b/src/include/auth.h similarity index 82% rename from src/include/auth.hpp rename to src/include/auth.h index 3a2f4a9..41ab59e 100644 --- a/src/include/auth.hpp +++ b/src/include/auth.h @@ -1,10 +1,10 @@ -#ifndef MEG_AUTH_HPP -#define MEG_AUTH_HPP +#ifndef MEG_AUTH_H_ +#define MEG_AUTH_H_ #include #include #include -#include "utils.hpp" +#include "utils.h" namespace meg { @@ -24,4 +24,4 @@ private: } // namespace meg -#endif // MEG_AUTH_HPP \ No newline at end of file +#endif // MEG_AUTH_H_ \ No newline at end of file diff --git a/src/include/exam.h b/src/include/exam.h new file mode 100644 index 0000000..2b0b2c3 --- /dev/null +++ b/src/include/exam.h @@ -0,0 +1,50 @@ +#ifndef MEG_EXAM_H_ +#define MEG_EXAM_H_ + +#include +#include +#include +#include +#include +#include "utils.h" + +namespace meg { + +// 抽象题目生成器接口:定义题目生成与历史管理的统一协议 +class IExamGenerator { +public: + virtual ~IExamGenerator() = default; + // 加载历史:用于避免重复题目 + virtual std::unordered_set load_history(const std::filesystem::path& history_path) = 0; + // 追加历史:将本次生成写入历史库 + virtual void append_history(const std::filesystem::path& history_path, const std::vector& qs) = 0; + // 生成不重复题目:按难度与数量生成题目,排除历史 + virtual std::vector GenerateUnique(Level level, int count, std::unordered_set& history) = 0; +}; + +// 具体题目生成器实现:使用随机数生成不同难度的题目 +class ExamGenerator : public IExamGenerator { +public: + ExamGenerator(); + // 加载历史:从文件读取每行题目为历史集合 + std::unordered_set load_history(const std::filesystem::path& history_path) override; + // 追加历史:将题目列表逐行追加到文件末尾 + void append_history(const std::filesystem::path& history_path, const std::vector& qs) override; + + // 生成不重复题目:依据难度选择生成函数并去重 + std::vector GenerateUnique(Level level, int count, std::unordered_set& history) override; + +private: + std::mt19937 rng_; + + // 生成小学难度题目 + std::string GenPrimary(); + // 生成初中难度题目 + std::string GenMiddle(); + // 生成高中难度题目 + std::string GenHigh(); +}; + +} // namespace meg + +#endif // MEG_EXAM_H_ \ No newline at end of file diff --git a/src/include/exam.hpp b/src/include/exam.hpp deleted file mode 100644 index 1e1cb60..0000000 --- a/src/include/exam.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef MEG_EXAM_HPP -#define MEG_EXAM_HPP - -#include -#include -#include -#include -#include -#include "utils.hpp" - -namespace meg { - -class ExamGenerator { -public: - ExamGenerator(); - // 加载/保存历史,防止同教师重复题目 - std::unordered_set load_history(const std::filesystem::path& history_path); - void append_history(const std::filesystem::path& history_path, const std::vector& qs); - - // 生成不重复题目 - std::vector generate_unique(Level level, int count, std::unordered_set& history); - -private: - std::mt19937 rng_; - - std::string gen_primary(); - std::string gen_middle(); - std::string gen_high(); -}; - -} // namespace meg - -#endif // MEG_EXAM_HPP \ No newline at end of file diff --git a/src/include/login.hpp b/src/include/login.h similarity index 73% rename from src/include/login.hpp rename to src/include/login.h index e6551e6..8630f73 100644 --- a/src/include/login.hpp +++ b/src/include/login.h @@ -1,9 +1,9 @@ -#ifndef MEG_LOGIN_HPP -#define MEG_LOGIN_HPP +#ifndef MEG_LOGIN_H_ +#define MEG_LOGIN_H_ #include #include -#include "auth.hpp" +#include "auth.h" namespace meg { @@ -17,4 +17,4 @@ private: } // namespace meg -#endif // MEG_LOGIN_HPP \ No newline at end of file +#endif // MEG_LOGIN_H_ \ No newline at end of file diff --git a/src/include/utils.h b/src/include/utils.h new file mode 100644 index 0000000..1717a30 --- /dev/null +++ b/src/include/utils.h @@ -0,0 +1,29 @@ +#ifndef MEG_UTILS_H_ +#define MEG_UTILS_H_ + +#include +#include + +namespace meg { + +enum class Level { Primary, Middle, High }; + +// 将难度枚举转换为中文 +std::wstring LevelToChinese(Level level); + +// 初始化控制台本地化,解决中文输入/输出问题 +// 初始化控制台本地化,解决中文输入/输出问题 +void InitConsoleLocale(); + +// 生成时间戳:YYYY-MM-DD-HH-MM-SS +// 生成时间戳:YYYY-MM-DD-HH-MM-SS +std::string NowTimestampStr(); + +// 字符串工具 +// 字符串工具:判断前缀与去除首尾空白 +bool StartsWith(const std::wstring& s, const std::wstring& prefix); +std::wstring Trim(const std::wstring& s); + +} // namespace meg + +#endif // MEG_UTILS_H_ \ No newline at end of file diff --git a/src/include/utils.hpp b/src/include/utils.hpp deleted file mode 100644 index 48269e0..0000000 --- a/src/include/utils.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef MEG_UTILS_HPP -#define MEG_UTILS_HPP - -#include -#include - -namespace meg { - -enum class Level { Primary, Middle, High }; - -std::wstring level_to_chinese(Level level); - -// 初始化控制台本地化,解决中文输入/输出问题 -void init_console_locale(); - -// 生成时间戳:YYYY-MM-DD-HH-MM-SS -std::string now_timestamp_str(); - -// 字符串工具 -bool starts_with(const std::wstring& s, const std::wstring& prefix); -std::wstring trim(const std::wstring& s); - -} // namespace meg - -#endif // MEG_UTILS_HPP \ No newline at end of file diff --git a/src/libgcc_s_seh-1.dll b/src/libgcc_s_seh-1.dll new file mode 100644 index 0000000..3feb9c1 Binary files /dev/null and b/src/libgcc_s_seh-1.dll differ diff --git a/src/libstdc++-6.dll b/src/libstdc++-6.dll new file mode 100644 index 0000000..d1b0432 Binary files /dev/null and b/src/libstdc++-6.dll differ diff --git a/src/libwinpthread-1.dll b/src/libwinpthread-1.dll new file mode 100644 index 0000000..e2a3fcc Binary files /dev/null and b/src/libwinpthread-1.dll differ diff --git a/src/login.cpp b/src/login.cc similarity index 79% rename from src/login.cpp rename to src/login.cc index 729632e..6413b1b 100644 --- a/src/login.cpp +++ b/src/login.cc @@ -1,11 +1,12 @@ -#include "include/login.hpp" -#include "include/utils.hpp" +#include "include/login.h" +#include "include/utils.h" #include #include namespace meg { +// 登录交互:读取“用户名 密码”,验证成功返回用户,EOF 返回空 std::optional LoginManager::prompt_login() { while (true) { std::wcout << L"请输入用户名和密码(用空格隔开): "; @@ -14,7 +15,7 @@ std::optional LoginManager::prompt_login() { if (!std::getline(std::wcin, line)) { return std::nullopt; } - line = trim(line); + line = Trim(line); if (line.empty()) continue; // 拆分为两段:用户名 密码 @@ -22,15 +23,15 @@ std::optional LoginManager::prompt_login() { std::wstring u, p; iss >> u >> p; if (u.empty() || p.empty()) { - std::wcout << L"输入格式不正确,请重新输入。" << std::endl; + std::wcout << L"输入格式不正确,请重新输入。" << '\n'; continue; } auto user = auth_.authenticate(u, p); if (user) { - std::wcout << L"登录成功,欢迎您," << u << L"!" << std::endl; + std::wcout << L"登录成功,欢迎您," << u << L"!" << '\n'; return user; } else { - std::wcout << L"用户名或密码错误,请重试。" << std::endl; + std::wcout << L"用户名或密码错误,请重试。" << '\n'; } } } diff --git a/src/main.cpp b/src/main.cc similarity index 68% rename from src/main.cpp rename to src/main.cc index 2bd9c39..7755e7c 100644 --- a/src/main.cpp +++ b/src/main.cc @@ -1,4 +1,4 @@ -#include "include/app.hpp" +#include "include/app.h" int main() { meg::App app; diff --git a/src/math_exam_generator.exe b/src/math_exam_generator.exe index e86f2d6..1da77dd 100644 Binary files a/src/math_exam_generator.exe and b/src/math_exam_generator.exe differ diff --git a/src/paper/张三1/.history.txt b/src/paper/张三1/.history.txt index f83fd24..b43dcc0 100644 --- a/src/paper/张三1/.history.txt +++ b/src/paper/张三1/.history.txt @@ -1,30 +1,30 @@ -40 + 31 * 38 = ? -46 * 6 = ? -(8) - 32 / 31 = ? -36 + 20 + 17 = ? -(7) + 14 / 39 = ? -(19) - 24 * 20 = ? -(13) - 27 * 43 = ? -43 / 17 - 39 = ? -17 - 43 = ? -9 / 30 = ? -48 / 31 = ? -17 - 24 = ? -(3) - 23 * 30 = ? -26 / 38 = ? -(48) / 46 * 33 = ? -11 * 7 = ? -(47) / 17 * 31 = ? -36 * 10 / 14 = ? -47 * 23 / 32 = ? -(29) - 14 * 33 = ? -33 * 46 + 38 = ? -(4) * 11 * 9 = ? -(39) / 36 - 36 = ? -25 - 4 = ? -12 - 8 = ? -39 - 32 = ? -13 / 25 = ? -40 - 43 = ? -(48) + 44 + 28 = ? -(12) / 9 + 44 = ? +7 + 2 = ? +(16 * 15) + 25 = ? +(35 - 33) + 38 = ? +3 - (32 * 47) = ? +(15 + 4) + 26 = ? +36 / 30 = ? +50 / (6 - 11) = ? +(3 + 25) + 3 = ? +14 / 12 = ? +26 + 1 = ? +43 * (15 + 8) = ? +30 * 10 = ? +41 / 37 = ? +38 + (30 / 28) = ? +(38 * 27) * 45 = ? +5 / 8 = ? +43 - 35 = ? +(6 / 39) + 44 = ? +(47 / 6) * 40 = ? +5 - 43 = ? +(11 - 44) - 1 = ? +30 - 36 = ? +(44 + 43) / 38 = ? +11 - 29 = ? +2 - (18 - 17) = ? +14 * (33 - 10) = ? +46 - 27 = ? +11 - 15 = ? +39 / 4 = ? +10 + (41 / 45) = ? diff --git a/src/paper/张三1/2025-09-27-16-21-44.txt b/src/paper/张三1/2025-09-27-16-21-44.txt deleted file mode 100644 index 48699e3..0000000 --- a/src/paper/张三1/2025-09-27-16-21-44.txt +++ /dev/null @@ -1,60 +0,0 @@ -1. 40 + 31 * 38 = ? - -2. 46 * 6 = ? - -3. (8) - 32 / 31 = ? - -4. 36 + 20 + 17 = ? - -5. (7) + 14 / 39 = ? - -6. (19) - 24 * 20 = ? - -7. (13) - 27 * 43 = ? - -8. 43 / 17 - 39 = ? - -9. 17 - 43 = ? - -10. 9 / 30 = ? - -11. 48 / 31 = ? - -12. 17 - 24 = ? - -13. (3) - 23 * 30 = ? - -14. 26 / 38 = ? - -15. (48) / 46 * 33 = ? - -16. 11 * 7 = ? - -17. (47) / 17 * 31 = ? - -18. 36 * 10 / 14 = ? - -19. 47 * 23 / 32 = ? - -20. (29) - 14 * 33 = ? - -21. 33 * 46 + 38 = ? - -22. (4) * 11 * 9 = ? - -23. (39) / 36 - 36 = ? - -24. 25 - 4 = ? - -25. 12 - 8 = ? - -26. 39 - 32 = ? - -27. 13 / 25 = ? - -28. 40 - 43 = ? - -29. (48) + 44 + 28 = ? - -30. (12) / 9 + 44 = ? - diff --git a/src/paper/张三1/2025-09-27-21-10-01.txt b/src/paper/张三1/2025-09-27-21-10-01.txt new file mode 100644 index 0000000..55e1ff3 --- /dev/null +++ b/src/paper/张三1/2025-09-27-21-10-01.txt @@ -0,0 +1,60 @@ +1. 7 + 2 = ? + +2. (16 * 15) + 25 = ? + +3. (35 - 33) + 38 = ? + +4. 3 - (32 * 47) = ? + +5. (15 + 4) + 26 = ? + +6. 36 / 30 = ? + +7. 50 / (6 - 11) = ? + +8. (3 + 25) + 3 = ? + +9. 14 / 12 = ? + +10. 26 + 1 = ? + +11. 43 * (15 + 8) = ? + +12. 30 * 10 = ? + +13. 41 / 37 = ? + +14. 38 + (30 / 28) = ? + +15. (38 * 27) * 45 = ? + +16. 5 / 8 = ? + +17. 43 - 35 = ? + +18. (6 / 39) + 44 = ? + +19. (47 / 6) * 40 = ? + +20. 5 - 43 = ? + +21. (11 - 44) - 1 = ? + +22. 30 - 36 = ? + +23. (44 + 43) / 38 = ? + +24. 11 - 29 = ? + +25. 2 - (18 - 17) = ? + +26. 14 * (33 - 10) = ? + +27. 46 - 27 = ? + +28. 11 - 15 = ? + +29. 39 / 4 = ? + +30. 10 + (41 / 45) = ? + diff --git a/src/utils.cpp b/src/utils.cc similarity index 68% rename from src/utils.cpp rename to src/utils.cc index fd10f3b..fd270ea 100644 --- a/src/utils.cpp +++ b/src/utils.cc @@ -1,10 +1,11 @@ -#include "include/utils.hpp" +#include "include/utils.h" #include #include #include #include #include +#include #ifdef _WIN32 # include @@ -13,7 +14,8 @@ namespace meg { -std::wstring level_to_chinese(Level level) { +// 将难度枚举转换为中文 +std::wstring LevelToChinese(Level level) { switch (level) { case Level::Primary: return L"小学"; case Level::Middle: return L"初中"; @@ -22,7 +24,8 @@ std::wstring level_to_chinese(Level level) { return L"小学"; } -void init_console_locale() { +// 初始化控制台本地化,解决中文输入/输出问题 +void InitConsoleLocale() { #ifdef _WIN32 _setmode(_fileno(stdout), _O_U16TEXT); _setmode(_fileno(stdin), _O_U16TEXT); @@ -40,7 +43,8 @@ void init_console_locale() { #endif } -std::string now_timestamp_str() { +// 生成时间戳:YYYY-MM-DD-HH-MM-SS +std::string NowTimestampStr() { using namespace std::chrono; auto now = system_clock::now(); std::time_t t = system_clock::to_time_t(now); @@ -55,19 +59,21 @@ std::string now_timestamp_str() { return oss.str(); } -bool starts_with(const std::wstring& s, const std::wstring& prefix) { +// 判断字符串是否以指定前缀开头 +bool StartsWith(const std::wstring& s, const std::wstring& prefix) { if (prefix.size() > s.size()) return false; return std::equal(prefix.begin(), prefix.end(), s.begin()); } -static inline bool is_space(wchar_t c) { +static inline bool IsSpace(wchar_t c) { return c == L' ' || c == L'\t' || c == L'\n' || c == L'\r' || c == L'\f' || c == L'\v'; } -std::wstring trim(const std::wstring& s) { +// 去除字符串首尾空白字符 +std::wstring Trim(const std::wstring& s) { size_t b = 0, e = s.size(); - while (b < e && is_space(s[b])) ++b; - while (e > b && is_space(s[e-1])) --e; + while (b < e && IsSpace(s[b])) ++b; + while (e > b && IsSpace(s[e-1])) --e; return s.substr(b, e - b); }