From 04f8c7501e9844fa0b3c2ebf70a85c2826173f70 Mon Sep 17 00:00:00 2001 From: hnu202326010322 <1463365450@qq.com> Date: Sat, 27 Sep 2025 14:19:05 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E8=87=B3=20'src'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.py | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 src/main.py diff --git a/src/main.py b/src/main.py new file mode 100644 index 0000000..6416a16 --- /dev/null +++ b/src/main.py @@ -0,0 +1,112 @@ +# main.py +from user_manager import UserManager, AccountType +from file_handler import FileHandler +from question_generator import QuestionGenerator, MathQuestion + + +def split_username_password(input_str: str) -> tuple[str, str]: + """分割用户名和密码(支持用户名含空格)""" + parts = input_str.strip().split() + if len(parts) < 2: + return ("", "") + password = parts[-1] + username = " ".join(parts[:-1]) + return (username, password) + + +def login_process(user_manager: UserManager) -> tuple[str, AccountType]: + """登录流程,循环直到输入正确的用户名密码""" + while True: + input_str = input("请输入用户名和密码(空格分隔):") + username, password = split_username_password(input_str) + account_type = user_manager.verify_user(username, password) + if account_type != AccountType.INVALID: + print(f"登录成功!欢迎{username}") + print(f"当前选择为{user_manager.type_to_str(account_type)}出题") + return (username, account_type) + else: + print("请输入正确的用户名、密码") + + +def main(): + user_manager = UserManager() + question_generator = QuestionGenerator() + + while True: + # 登录流程 + username, current_type = login_process(user_manager) + file_handler = FileHandler(username) + current_type_str = user_manager.type_to_str(current_type) + + # 登录后操作循环 + while True: + print(f"\n当前用户: {username}|当前难度: {current_type_str}") + print("1. 生成题目") + print("2. 切换难度级别") + print("3. 退出当前用户") + print("4. 退出程序") + choice = input("请选择操作(1-4): ").strip() + + if choice == "1": + while True: + count_str = input("请输入生成题目数量(10-30): ").strip() + if count_str.isdigit(): + question_count = int(count_str) + if 10 <= question_count <= 30: + # 生成题目(确保无重复) + print(f"正在生成{current_type_str}数学题目...") + generated_questions = [] + while len(generated_questions) < question_count: + if current_type == AccountType.PRIMARY_SCHOOL: + content = question_generator._generate_primary_question() + elif current_type == AccountType.MIDDLE_SCHOOL: + content = question_generator._generate_middle_question() + else: + content = question_generator._generate_high_question() + new_question = MathQuestion(content, current_type) + if not file_handler.is_duplicate(new_question): + generated_questions.append(new_question) + # 保存题目到文件 + save_success = file_handler.save_questions(generated_questions) + if save_success: + print(f"题目生成成功!共{question_count}题,已保存至{file_handler.user_dir}文件夹") + else: + print("题目保存失败,请重试") + break + else: + print("题目数量无效,请输入10-30之间的整数") + else: + print("请输入有效的整数") + elif choice == "2": + while True: + print("1. 小学(+,-,*,/,括号)") + print("2. 初中(包含平方、开根号)") + print("3. 高中(包含三角函数)") + print("0. 返回主菜单") + level_choice = input("请选择难度级别: ").strip() + if level_choice.isdigit(): + level = int(level_choice) + if level == 0: + break + new_type = user_manager.parse_type_choice(level) + if new_type != AccountType.INVALID: + current_type = new_type + current_type_str = user_manager.type_to_str(current_type) + print(f"已成功切换为{current_type_str}难度") + break + else: + print("请输入有效的选项") + else: + print("请输入有效的整数") + elif choice == "3": + print("退出当前用户") + break + elif choice == "4": + print("退出程序") + return + else: + print("请输入有效的选项(1-4)") + + +if __name__ == "__main__": + main() \ No newline at end of file -- 2.34.1 From 34eee568c8b960ee44d3dff9d03ac124b01038de Mon Sep 17 00:00:00 2001 From: hnu202326010322 <1463365450@qq.com> Date: Sat, 27 Sep 2025 14:19:22 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E8=87=B3=20'src'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/question_generator.py | 107 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 src/question_generator.py diff --git a/src/question_generator.py b/src/question_generator.py new file mode 100644 index 0000000..10e7a86 --- /dev/null +++ b/src/question_generator.py @@ -0,0 +1,107 @@ +import random +from user_manager import AccountType + + +class MathQuestion: + """题目类,包含题目内容和对应的难度类型""" + def __init__(self, content: str, question_type: AccountType): + self.content = content + self.type = question_type + + def __eq__(self, other) -> bool: + """重载==运算符,用于题目查重""" + if not isinstance(other, MathQuestion): + return False + return self.content == other.content and self.type == other.type + + +class QuestionGenerator: + def __init__(self): + random.seed() # 初始化随机种子 + + def generate_questions(self, count: int, question_type: AccountType) -> list[MathQuestion]: + """ + 生成指定数量和难度的题目列表 + :param count: 题目数量 + :param question_type: 题目难度类型 + :return: 题目对象列表 + """ + questions = [] + while len(questions) < count: + if question_type == AccountType.PRIMARY_SCHOOL: + content = self._generate_primary_question() + elif question_type == AccountType.MIDDLE_SCHOOL: + content = self._generate_middle_question() + elif question_type == AccountType.HIGH_SCHOOL: + content = self._generate_high_question() + else: + continue # 无效类型跳过 + # 去重(避免生成完全相同的题目) + new_question = MathQuestion(content, question_type) + if new_question not in questions: + questions.append(new_question) + return questions + + def _generate_random_num(self) -> int: + """生成1-100之间的随机整数""" + return random.randint(1, 100) + + def _generate_expression(self, op_count: int, ops: list[str]) -> str: + """ + 生成包含指定数量操作数和运算符的表达式 + :param op_count: 操作数数量(1-5) + :param ops: 可用运算符列表 + :return: 表达式字符串 + """ + if op_count < 1: + return "" + # 初始化第一个操作数 + expr_parts = [str(self._generate_random_num())] + for _ in range(op_count - 1): + op = random.choice(ops) + # 除法确保除数不为0且能整除,避免小数 + if op == "/": + divisor = self._generate_random_num() + dividend = self._generate_random_num() * divisor + expr_parts.append(op) + expr_parts.append(str(divisor)) + else: + expr_parts.append(op) + expr_parts.append(str(self._generate_random_num())) + return " ".join(expr_parts) + + def _add_parentheses(self, expr: str) -> str: + """30%概率为表达式添加括号""" + if random.random() < 0.3 and len(expr.split()) >= 3: # 至少包含一个运算符才加括号 + return f"({expr})" + return expr + + def _generate_primary_question(self) -> str: + """生成小学题目(仅+、-、*、/和())""" + op_count = random.randint(1, 5) # 1-5个操作数 + ops = ["+", "-", "*", "/"] + expr = self._generate_expression(op_count, ops) + return self._add_parentheses(expr) + + def _generate_middle_question(self) -> str: + """生成初中题目(包含平方或开根号,可含+、-、*、/和())""" + op_count = random.randint(1, 5) + ops = ["+", "-", "*", "/"] + expr = self._generate_expression(op_count, ops) + # 确保包含平方或开根号 + func_choice = random.choice(["square", "sqrt"]) + if func_choice == "square": + expr = self._add_parentheses(expr) + " ^ 2" + else: + expr = f"sqrt({self._add_parentheses(expr)})" + return expr + + def _generate_high_question(self) -> str: + """生成高中题目(包含sin、cos、tan,可含+、-、*、/和())""" + op_count = random.randint(1, 5) + ops = ["+", "-", "*", "/"] + expr = self._generate_expression(op_count, ops) + # 确保包含三角函数 + trig_func = random.choice(["sin", "cos", "tan"]) + expr = f"{trig_func}({self._add_parentheses(expr)})" + return expr \ No newline at end of file -- 2.34.1 From aef0a80317468c19a255e61396ef0a13032e2bcd Mon Sep 17 00:00:00 2001 From: hnu202326010322 <1463365450@qq.com> Date: Sat, 27 Sep 2025 14:19:40 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E8=87=B3=20'src'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/user_manager.py | 64 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 src/user_manager.py diff --git a/src/user_manager.py b/src/user_manager.py new file mode 100644 index 0000000..7aede43 --- /dev/null +++ b/src/user_manager.py @@ -0,0 +1,64 @@ +# user_manager.py +from enum import Enum, auto + + +class AccountType(Enum): + """账户类型枚举类,对应小学、初中、高中三个级别""" + PRIMARY_SCHOOL = auto() + MIDDLE_SCHOOL = auto() + HIGH_SCHOOL = auto() + INVALID = auto() + + +class UserManager: + def __init__(self): + # 初始化预设账户:key为用户名,value为(密码, 账户类型) + self.user_database = { + # 小学账户 + "张三 1": ("123", AccountType.PRIMARY_SCHOOL), + "张三 2": ("123", AccountType.PRIMARY_SCHOOL), + "张三 3": ("123", AccountType.PRIMARY_SCHOOL), + # 初中账户 + "李四 1": ("123", AccountType.MIDDLE_SCHOOL), + "李四 2": ("123", AccountType.MIDDLE_SCHOOL), + "李四 3": ("123", AccountType.MIDDLE_SCHOOL), + # 高中账户 + "王五 1": ("123", AccountType.HIGH_SCHOOL), + "王五 2": ("123", AccountType.HIGH_SCHOOL), + "王五 3": ("123", AccountType.HIGH_SCHOOL), + } + + def verify_user(self, username: str, password: str) -> AccountType: + """ + 验证用户名和密码是否正确 + :param username: 输入的用户名 + :param password: 输入的密码 + :return: 账户类型,无效账户返回INVALID + """ + user_info = self.user_database.get(username) + if user_info and user_info[0] == password: + return user_info[1] + return AccountType.INVALID + + def type_to_str(self, account_type: AccountType) -> str: + """将账户类型转换为中文描述""" + type_map = { + AccountType.PRIMARY_SCHOOL: "小学", + AccountType.MIDDLE_SCHOOL: "初中", + AccountType.HIGH_SCHOOL: "高中", + AccountType.INVALID: "未知" + } + return type_map[account_type] + + def parse_type_choice(self, choice: int) -> AccountType: + """ + 根据输入的序号解析对应的账户类型 + :param choice: 输入的序号(1代表小学,2代表初中,3代表高中) + :return: 对应的账户类型,无效输入返回INVALID + """ + choice_map = { + 1: AccountType.PRIMARY_SCHOOL, + 2: AccountType.MIDDLE_SCHOOL, + 3: AccountType.HIGH_SCHOOL + } + return choice_map.get(choice, AccountType.INVALID) \ No newline at end of file -- 2.34.1 From df62a2713484fdb5f9e02275c1cf33694fe9d8fa Mon Sep 17 00:00:00 2001 From: hnu202326010322 <1463365450@qq.com> Date: Sat, 27 Sep 2025 14:19:56 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E8=87=B3=20'src'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/file_handler.py | 102 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 src/file_handler.py diff --git a/src/file_handler.py b/src/file_handler.py new file mode 100644 index 0000000..f044df6 --- /dev/null +++ b/src/file_handler.py @@ -0,0 +1,102 @@ +import os +import datetime +from user_manager import AccountType +from question_generator import MathQuestion + + +class FileHandler: + def __init__(self, username: str): + """ + 初始化文件处理器 + :param username: 用户名,用于创建专属文件夹 + """ + self.username = username + self.user_dir = f"{username}_questions/" # 用户专属文件夹 + self._create_user_dir() + + def _create_user_dir(self) -> None: + """创建用户专属文件夹(若不存在)""" + if not os.path.exists(self.user_dir): + os.makedirs(self.user_dir) + + @staticmethod + def _get_current_time_str() -> str: + """获取当前时间字符串,格式:年-月-日-时-分-秒""" + return datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S") + + def _read_existing_questions(self) -> list[MathQuestion]: + """读取用户文件夹下所有历史题目,用于查重""" + existing_questions = [] + if not os.path.exists(self.user_dir): + return existing_questions + # 遍历文件夹下所有txt文件 + for filename in os.listdir(self.user_dir): + if not filename.endswith(".txt"): + continue + file_path = os.path.join(self.user_dir, filename) + # 从文件名提取题目类型 + if "小学" in filename: + question_type = AccountType.PRIMARY_SCHOOL + elif "初中" in filename: + question_type = AccountType.MIDDLE_SCHOOL + elif "高中" in filename: + question_type = AccountType.HIGH_SCHOOL + else: + continue + # 读取文件内容 + try: + with open(file_path, "r", encoding="utf-8") as f: + lines = f.readlines() + for line in lines: + line = line.strip() + if not line or not line[0].isdigit(): + continue + # 提取题目内容(去掉题号,如"1. 2 + 3" → "2 + 3") + content_start = line.find(". ") + 2 + if content_start > 1: + content = line[content_start:] + existing_questions.append(MathQuestion(content, question_type)) + except IOError as e: + print(f"读取文件 {file_path} 时发生错误: {e}") + return existing_questions + + def is_duplicate(self, question: MathQuestion) -> bool: + """ + 检查题目是否已存在于历史文件中 + :param question: 待检查的题目对象 + :return: 存在返回True,否则返回False + """ + existing = self._read_existing_questions() + return question in existing + + def save_questions(self, questions: list[MathQuestion]) -> bool: + """ + 将题目保存到文件 + :param questions: 待保存的题目列表 + :return: 保存成功返回True,失败返回False + """ + if not questions: + return False + # 确定题目类型(所有题目类型一致) + question_type = questions[0].type + if question_type == AccountType.PRIMARY_SCHOOL: + type_str = "小学" + elif question_type == AccountType.MIDDLE_SCHOOL: + type_str = "初中" + elif question_type == AccountType.HIGH_SCHOOL: + type_str = "高中" + else: + return False + # 生成文件名 + time_str = self._get_current_time_str() + filename = f"{time_str}_{type_str}.txt" + file_path = os.path.join(self.user_dir, filename) + # 写入文件 + try: + with open(file_path, "w", encoding="utf-8") as f: + for idx, question in enumerate(questions, 1): + f.write(f"{idx}. {question.content}\n\n") # 每题带题号,空行分隔 + return True + except IOError as e: + print(f"保存文件 {file_path} 时发生错误: {e}") + return False \ No newline at end of file -- 2.34.1