diff --git a/src/base_generator.py b/src/base_generator.py new file mode 100644 index 0000000..1f4d4a7 --- /dev/null +++ b/src/base_generator.py @@ -0,0 +1,9 @@ +from abc import ABC, abstractmethod + +class BaseQuestionGenerator(ABC): + """抽象类:定义题目生成器接口""" + + @abstractmethod + def generate_question(self): + """生成一条题目""" + pass diff --git a/src/exam_generator.py b/src/exam_generator.py new file mode 100644 index 0000000..2037e45 --- /dev/null +++ b/src/exam_generator.py @@ -0,0 +1,161 @@ +import os +from history_manager import HistoryManager +from junior_generator import JuniorQuestionGenerator +from primary_generator import PrimaryQuestionGenerator +from senior_generator import SeniorQuestionGenerator + +#查重功能在_generate_and_save_questions函数中实现 + +class ExamGenerator: + def __init__(self): + self.accounts = { + "小学": [("张三1", "123"), ("张三2", "123"), ("张三3", "123")], + "初中": [("李四1", "123"), ("李四2", "123"), ("李四3", "123")], + "高中": [("王五1", "123"), ("王五2", "123"), ("王五3", "123")] + } + self.level = None + self.username = None + self.folder = None + self.history = set() + self.history_manager = HistoryManager() + + def get_account_type(self, username, password): + """根据用户名和密码获取用户等级(角色)""" + for level, infos in self.accounts.items(): + if (username, password) in infos: + return level + return None + + def get_generator(self, level): + """根据等级获取对应的题目生成器""" + if level == "小学": + return PrimaryQuestionGenerator() + elif level == "初中": + return JuniorQuestionGenerator() + elif level == "高中": + return SeniorQuestionGenerator() + return None + + def run(self): + """ + 程序主入口,控制整体流程。 + """ + print("--- 欢迎使用数学题库生成系统 ---") + while True: + # 1. 处理登录 + if not self._login(): + print("感谢使用,再见!") + break # 退出整个程序 + + # 2. 登录成功后,进入主菜单循环 + self._main_menu() + + # 3. 从主菜单退出后,重置用户状态,准备下一次登录 + self._reset_user_state() + + + def _login(self): + """ + 处理用户登录流程。 + 返回: 如果登录成功返回 True,如果用户选择退出返回 False。 + """ + while True: + login_input = input("请输入用户名和密码(以空格分隔),或输入 -1 退出:").strip() + + if login_input == "-1": + return False + + if " " not in login_input: + print("输入格式错误,请输入用户名和密码,以空格分隔。") + continue + + username, password = login_input.split(" ", 1) + level = self.get_account_type(username, password) + + if level: + self.username = username + self.level = level + self.folder = os.path.join("exams", self.username) + self.history = self.history_manager.load_history(self.folder) + print(f"\n登录成功!当前用户:{self.username},当前等级:{self.level}") + return True + else: + print("用户名或密码错误,请重新输入。") + + + def _main_menu(self): + """ + 登录后的主菜单和命令处理循环。 + """ + while True: + # 根据当前等级获取生成器 + generator = self.get_generator(self.level) + if not generator: + print("无法获取题目生成器,请联系管理员。") + break + + cmd = input(f"\n请输入操作:\n" + f"1. 直接输入数量 10-30(生成 {self.level} 数学题目)\n" + f"2. 直接输入 '切换为小学/初中/高中'(切换等级)\n" + f"3. 直接输入 -1(返回登录界面)\n" + f"请输入您的选择:").strip() + + if cmd == "-1": + print("\n正在退出当前用户...") + break # 退出主菜单循环 + + # 解析并执行命令 + self._process_command(cmd, generator) + + + def _process_command(self, cmd, generator): + """ + 解析并执行用户在主菜单中输入的命令。 + """ + if cmd.startswith("切换为"): + new_level = cmd[3:].strip() + if new_level in ["小学", "初中", "高中"]: + self.level = new_level + print(f"系统提示:已成功切换为 {self.level} 等级。") + else: + print("切换失败,请输入 '切换为小学'、'切换为初中' 或 '切换为高中'。") + + elif cmd.isdigit(): + num = int(cmd) + if 10 <= num <= 30: + self._generate_and_save_questions(num, generator) + else: + print("无效数量,请输入 10 到 30 之间的数字。") + + else: + print("无效的命令,请重新输入。") + +#查重功能 + def _generate_and_save_questions(self, num, generator): + """ + 生成指定数量的不重复题目,并保存到文件和历史记录中。 + """ + print(f"正在为您生成 {num} 道 {self.level} 数学题目...") + questions = [] + while len(questions) < num: + q = generator.generate_question() + # 确保题目既不在历史记录中,也不在本次生成的临时列表中 + if q not in self.history and q not in questions: + questions.append(q) + + # 保存题目 + self.history_manager.save_questions(self.folder, questions) + # 更新内存中的历史记录 + self.history.update(questions) + + print(f"✅ 成功生成并保存 {num} 道 {self.level} 数学题目!") + + + def _reset_user_state(self): + """ + 重置所有与当前用户相关的状态,以便下一个用户登录。 + """ + self.username = None + self.level = None + self.folder = None + self.history = set() \ No newline at end of file diff --git a/src/history_manager.py b/src/history_manager.py new file mode 100644 index 0000000..6dc9daa --- /dev/null +++ b/src/history_manager.py @@ -0,0 +1,22 @@ +import os +from datetime import datetime + +class HistoryManager: + def load_history(self, folder): + history = set() + if not os.path.exists(folder): + os.makedirs(folder) + return history + for file in os.listdir(folder): + if file.endswith(".txt"): + with open(os.path.join(folder, file), "r", encoding="utf-8") as f: + history.update(line.strip() for line in f if line.strip()) + return history + + def save_questions(self, folder, questions): + filename = datetime.now().strftime("%Y-%m-%d-%H-%M-%S.txt") + filepath = os.path.join(folder, filename) + with open(filepath, "w", encoding="utf-8") as f: + for i, q in enumerate(questions, 1): + f.write(f"{i}. {q}\n\n") + print(f"题目已保存到 {filepath}") diff --git a/src/junior_generator.py b/src/junior_generator.py new file mode 100644 index 0000000..ada8f77 --- /dev/null +++ b/src/junior_generator.py @@ -0,0 +1,26 @@ +import random +from base_generator import BaseQuestionGenerator + +class JuniorQuestionGenerator(BaseQuestionGenerator): + def generate_question(self): + ops = ["+", "-", "*", "/"] + num_operands = random.randint(2, 5) + nums = [str(random.randint(1, 50)) for _ in range(num_operands)] + + # 1. 初始化一个列表,将第一个数字作为初始元素 + parts = [nums[0]] + + # 2. 在循环中,将操作符和数字组成的子字符串追加到列表 + for n in nums[1:]: + parts.append(" " + random.choice(ops) + " " + n) + + # 3. 使用 "".join() 将列表中的所有部分一次性拼接成字符串 + expr = "".join(parts) + + # 后续逻辑保持不变 + if random.choice([True, False]): + expr = f"({expr})^2" + else: + expr = f"√({expr})" + + return expr \ No newline at end of file diff --git a/src/main.py b/src/main.py new file mode 100644 index 0000000..be3b276 --- /dev/null +++ b/src/main.py @@ -0,0 +1,5 @@ +from exam_generator import ExamGenerator + +if __name__ == "__main__": + generator = ExamGenerator() + generator.run() diff --git a/src/primary_generator.py b/src/primary_generator.py new file mode 100644 index 0000000..d72956a --- /dev/null +++ b/src/primary_generator.py @@ -0,0 +1,23 @@ +import random +from base_generator import BaseQuestionGenerator + +class PrimaryQuestionGenerator(BaseQuestionGenerator): + def generate_question(self): + ops = ["+", "-", "*"] + while True: + num_operands = random.randint(2, 4) # 控制操作数数量 + nums = [random.randint(1, 20) for _ in range(num_operands)] + chosen_ops = [random.choice(ops) for _ in range(num_operands - 1)] + + # 构造表达式字符串 + expr = str(nums[0]) + for i in range(1, num_operands): + expr += f" {chosen_ops[i-1]} {nums[i]}" + + try: + result = eval(expr) + except ZeroDivisionError: + continue # 避免除零错误 + + if result > 0 and isinstance(result, int): + return expr diff --git a/src/senior_generator.py b/src/senior_generator.py new file mode 100644 index 0000000..69630ae --- /dev/null +++ b/src/senior_generator.py @@ -0,0 +1,15 @@ +import random +from base_generator import BaseQuestionGenerator + +class SeniorQuestionGenerator(BaseQuestionGenerator): + def generate_question(self): + ops = ["+", "-", "*", "/"] + num_operands = random.randint(2, 5) + nums = [str(random.randint(1, 100)) for _ in range(num_operands)] + + func = random.choice(["sin", "cos", "tan"]) + expr = nums[0] + for n in nums[1:]: + expr += " " + random.choice(ops) + " " + n + + return f"{func}({expr})"