hebing #1

Merged
hnu202326010322 merged 4 commits from develop into main 5 months ago

@ -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

@ -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()

@ -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

@ -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)
Loading…
Cancel
Save