pull/2/head
何文迪 7 months ago
parent ac50b2596f
commit 327cd60bcc

@ -0,0 +1,27 @@
# auth.py
"""用户认证模块,负责处理用户登录验证。"""
# 预设账户信息,实际应用中可以考虑从数据库或配置文件中读取
_ACCOUNTS = {
"小学": {"张三1": "123", "张三2": "123", "张三3": "123"},
"初中": {"李四1": "123", "李四2": "123", "李四3": "123"},
"高中": {"王五1": "123", "王五2": "123", "王五3": "123"},
}
def validate_user(username, password):
"""
验证用户凭据
Args:
username (str): 用户名
password (str): 密码
Returns:
str | None: 如果凭据有效则返回账户类型 "小学"否则返回 None
"""
for account_type, credentials in _ACCOUNTS.items():
if credentials.get(username) == password:
return account_type
return None

@ -0,0 +1,66 @@
# file_handler.py
"""文件处理模块,负责加载、保存和查重。"""
import os
from datetime import datetime
# 定义存储用户数据的基础目录
_BASE_DATA_DIR = "quiz_data"
def load_existing_questions(username):
"""
加载指定用户所有历史题目用于查重
Args:
username (str): 用户名
Returns:
set: 包含该用户所有历史题目的集合
"""
user_dir = os.path.join(_BASE_DATA_DIR, username)
existing_questions = set()
if not os.path.exists(user_dir):
return existing_questions
for filename in os.listdir(user_dir):
if filename.endswith(".txt"):
filepath = os.path.join(user_dir, filename)
with open(filepath, 'r', encoding='utf-8') as f:
for line in f:
# 题目格式为 "1. 题目内容",我们只取题目内容
if ". " in line:
question = line.split(". ", 1)[1].strip()
if question:
existing_questions.add(question)
return existing_questions
def save_quiz_to_file(username, questions):
"""
将生成的试卷保存到用户专属的文件夹中
文件以 '年-月-日-时-分-秒.txt' 格式命名
Args:
username (str): 用户名
questions (list): 包含题目字符串的列表
Returns:
str: 保存成功后的文件绝对路径
"""
user_dir = os.path.join(_BASE_DATA_DIR, username)
os.makedirs(user_dir, exist_ok=True)
timestamp = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
filename = f"{timestamp}.txt"
filepath = os.path.join(user_dir, filename)
with open(filepath, 'w', encoding='utf-8') as f:
for i, question in enumerate(questions, 1):
f.write(f"{i}. {question}\n\n")
return os.path.abspath(filepath)

@ -0,0 +1,121 @@
# generator.py
import random
import re
from abc import ABC, abstractmethod
class QuestionGenerator(ABC):
def generate_bunch(self, count, existing_questions):
new_questions = []
all_questions = existing_questions.copy()
while len(new_questions) < count:
question = self._create_expression()
if question not in all_questions:
new_questions.append(question)
all_questions.add(question)
return new_questions
@abstractmethod
def _create_expression(self):
pass
def _get_random_operands(self, num_operands):
return [random.randint(1, 100) for _ in range(num_operands)]
class PrimarySchoolGenerator(QuestionGenerator):
def _get_factors(self, n):
if n == 0:
return []
factors = set()
for i in range(1, int(n**0.5) + 1):
if n % i == 0:
factors.add(i)
factors.add(n // i)
return list(factors)
def _create_expression(self):
num_operations = random.randint(1, 4)
current_value = random.randint(20, 100)
expression_str = str(current_value)
for _ in range(num_operations):
possible_ops = ['+', '*']
if current_value > 1:
possible_ops.append('-')
factors = self._get_factors(current_value)
if len(factors) > 2:
possible_ops.append('/')
op = random.choice(possible_ops)
if op == '+':
next_operand = random.randint(1, 100)
current_value += next_operand
elif op == '*':
next_operand = random.randint(1, 10)
current_value *= next_operand
elif op == '-':
next_operand = random.randint(1, current_value)
current_value -= next_operand
elif op == '/':
valid_divisors = [f for f in factors if f != current_value and f != 1]
if not valid_divisors:
op = '-'
next_operand = random.randint(1, current_value)
current_value -= next_operand
else:
next_operand = random.choice(valid_divisors)
current_value //= next_operand
expression_str = f"({expression_str} {op} {next_operand})"
return expression_str[1:-1]
class MiddleSchoolGenerator(QuestionGenerator):
def _create_expression(self):
base_gen = PrimarySchoolGenerator()
expression = base_gen._create_expression()
parts = re.findall(r'\d+', expression)
if not parts:
return self._create_expression()
target_num_str = random.choice(parts)
if random.choice([True, False]):
replacement = f"{target_num_str} ** 2"
else:
n = random.randint(2, 10)
original_num = n * n
replacement = f"sqrt({original_num})"
expression = expression.replace(target_num_str, str(original_num), 1)
return expression.replace(str(target_num_str), replacement, 1)
class HighSchoolGenerator(QuestionGenerator):
def _create_expression(self):
base_gen = MiddleSchoolGenerator()
expression = base_gen._create_expression()
parts = re.findall(r'\d+', expression)
if not parts:
return self._create_expression()
target_num_str = random.choice(parts)
trig_func = random.choice(['sin', 'cos', 'tan'])
replacement = f"{trig_func}({target_num_str})"
return expression.replace(target_num_str, replacement, 1)
def get_generator(account_type):
generators = {
"小学": PrimarySchoolGenerator,
"初中": MiddleSchoolGenerator,
"高中": HighSchoolGenerator,
}
generator_class = generators.get(account_type)
if generator_class:
return generator_class()
raise ValueError("无效的账户类型")

@ -0,0 +1,94 @@
# main.py
"""
程序主入口
负责处理用户登录命令解析和调用其他模块完成核心功能
"""
import auth
import file_handler
from generator import get_generator
VALID_TYPES = {"小学", "初中", "高中"}
def session_loop(username, account_type):
"""
用户登录后的主会话循环
处理生成题目切换难度和退出登录的逻辑
Args:
username (str): 当前登录的用户名
account_type (str): 当前用户的账户类型
"""
print(f"\n--- 欢迎, {username}!当前选择为 {account_type} 出题 ---")
current_type = account_type
while True:
prompt = (
f"准备生成 {current_type} 数学题目, "
"请输入生成题目数量 (10-30, 输入-1将退出当前用户): "
)
user_input = input(prompt).strip()
if user_input == "-1":
print(f"用户 {username} 已退出。")
break
if user_input.startswith("切换为"):
parts = user_input.split()
if len(parts) == 2 and parts[1] in VALID_TYPES:
current_type = parts[1]
print(f"--- 已成功切换为 {current_type} 出题 ---")
continue
else:
print("无效的切换命令, 请输入 '切换为' + '小学'/'初中'/'高中' 中的一个。")
continue
try:
num_questions = int(user_input)
if not 10 <= num_questions <= 30:
print("输入错误, 题目数量必须在 10 到 30 之间。")
continue
print("正在生成题目, 请稍候...")
generator = get_generator(current_type)
existing_questions = file_handler.load_existing_questions(username)
new_questions = generator.generate_bunch(
num_questions, existing_questions
)
saved_path = file_handler.save_quiz_to_file(username, new_questions)
print("\n题目生成成功!试卷内容如下:")
for i, q in enumerate(new_questions, 1):
print(f"{i}. {q}")
print(f"\n试卷已保存至: {saved_path}")
except ValueError:
print("输入无效, 请输入一个有效的数字或命令。")
except Exception as e:
print(f"发生未知错误: {e}")
def main():
"""程序主函数,包含顶层登录循环。"""
print("--- 中小学数学卷子自动生成程序 ---")
while True:
credentials = input("请输入用户名和密码 (用空格隔开): ").strip().split()
if len(credentials) != 2:
print("输入格式错误, 请确保用户名和密码之间有且仅有一个空格。")
continue
username, password = credentials
account_type = auth.validate_user(username, password)
if account_type:
session_loop(username, account_type)
else:
print("用户名或密码错误, 请重新输入。")
if __name__ == "__main__":
main()
Loading…
Cancel
Save