Compare commits

...

18 Commits

@ -1 +0,0 @@
undefined

@ -1,27 +1,15 @@
# 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
# 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):
for account_type, credentials in _ACCOUNTS.items():
if credentials.get(username) == password:
return account_type
return None

@ -1,66 +1,29 @@
# 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")
# file_handler.py
import os
from datetime import datetime
_BASE_DATA_DIR = "quiz_data"
def load_existing_questions(username):
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:
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):
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)

@ -1,121 +1,109 @@
# 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()
# 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, 5)
current_value = random.randint(1, 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, min(10, 100))
current_value *= next_operand
elif op == '-':
next_operand = random.randint(1, min(current_value, 100))
current_value -= next_operand
elif op == '/':
valid_divisors = [f for f in factors if f != current_value and f != 1 and f <= 100]
if not valid_divisors:
op = '-'
next_operand = random.randint(1, min(current_value, 100))
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]):
target_num = min(int(target_num_str), 10)
replacement = f"{target_num} ** 2"
expression = expression.replace(target_num_str, str(target_num), 1)
else:
n = random.randint(1, 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 if 'target_num' in locals() else 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)
target_num = min(int(target_num_str), 90)
trig_func = random.choice(['sin', 'cos', 'tan'])
replacement = f"{trig_func}({target_num})"
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("无效的账户类型")

@ -1,94 +1,64 @@
# 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.py
import auth
import file_handler
from generator import get_generator
VALID_TYPES = {"小学", "初中", "高中"}
def session_loop(username, account_type):
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()

@ -0,0 +1,30 @@
1. (((56 * 10) * 4) / 280) - 2
2. 53 * 8
3. 53 - 19
4. (((48 - 41) * 5) - 34) * 9
5. (((28 / 14) * 5) + 13) + 84
6. ((63 + 64) - 126) * 4
7. (97 + 84) - 164
8. (((70 - 5) / 5) - 12) * 6
9. (52 / 26) - 1
10. ((84 * 2) + 56) + 95
11. (((26 * 9) + 40) + 2) / 4
12. (79 * 4) - 172
13. ((37 * 8) / 74) * 3
14. (91 + 26) - 12
15. (59 - 29) - 25

@ -0,0 +1,60 @@
1. (63 - 10) + 78
2. 85 * 8
3. ((((60 * 9) * 5) / 30) * 3) / 90
4. ((((75 + 1) + 90) - 71) + 50) - 82
5. ((((59 - 48) + 95) * 9) / 53) / 9
6. (((32 - 17) - 12) * 9) - 6
7. (((86 + 70) + 1) + 36) + 22
8. (((73 * 7) / 73) * 8) - 23
9. (88 + 36) + 96
10. 63 + 19
11. 43 - 30
12. ((97 + 100) + 34) / 7
13. ((((12 / 2) / 3) * 10) + 45) + 24
14. (64 * 4) - 48
15. 9 / 3
16. ((3 - 1) + 72) + 15
17. (((29 - 17) / 6) + 73) - 70
18. ((10 - 9) + 26) / 9
19. ((((96 * 2) / 12) / 2) + 87) * 5
20. ((19 + 34) + 72) + 47
21. ((((48 + 57) - 3) * 7) / 21) + 80
22. 2 * 9
23. 66 / 33
24. (((62 / 2) - 29) - 2) + 42
25. (((26 + 25) / 17) - 1) - 2
26. (((7 + 16) * 10) * 4) * 9
27. (57 / 3) - 7
28. ((36 - 12) - 3) * 9
29. ((2 - 2) + 24) + 100
30. (((65 + 1) + 21) / 29) + 24

@ -0,0 +1,20 @@
1. ((67 + 78) + 4) - 3
2. (((52 - 11) - 28) + 74) * 10
3. ((53 * 1) + 28) * 1
4. 21 - 10
5. ((62 - 51) * 2) - 1
6. (16 + 60) / 2
7. 78 / 39
8. ((((6 - 1) + 77) * 6) - 36) + 76
9. ((31 + 77) * 1) / 36
10. ((((50 / 5) + 69) - 61) + 72) - 82

@ -0,0 +1,60 @@
1. (10 ** 2 / 5) + 70
2. ((((54 ** 2 - 42) - 4) * 10) * 7) + 99
3. 8 ** 2 / 2
4. ((((58 * 2) / 29) * 4) + 10 ** 2) / 31
5. ((62 * 9 ** 2) * 6) * 4
6. ((((2 - 2) + 59) + 46) / 7 ** 2) + 76
7. ((48 + 15) + 57) + 10 ** 2
8. ((10 ** 2 * 10) - 87) - 76
9. ((49 * 5) + 48) + 10 ** 2
10. ((((31 * 5) * 4) - 10 ** 2) - 88) - 30
11. ((8 * 6) - 10) / 2 ** 2
12. ((((34 + 39) - 10 ** 2) - 8) / 5) + 18
13. (10 ** 2 * 2) / 13
14. (59 - 16) / 3
15. (10 ** 2 + 54) + 19
16. (50 * 4) * 4
17. ((((52 * 8) / 4) - 24) + 69) + 10 ** 2
18. (36 - 31) - 8
19. ((((83 + 73) + 50) - 4) + 66) / 29
20. (10 ** 2 * 3) - 3
21. (39 + 29) + 10 ** 2
22. ((((100 - 34) * 2) - 5) - 4) - 98
23. 15 + 10 ** 2
24. (((2 * 5) * 3) * 9) - 81
25. (((38 + 50) / 8) - 7 ** 2) + 5
26. ((10 ** 2 - 64) - 2) * 8
27. 10 ** 2 - 30
28. ((((27 + 24) / 17) * 1) + 10 ** 2) * 4
29. (36 / 4) + 36
30. (((84 * 7 ** 2) - 76) + 84) - 47

@ -0,0 +1,60 @@
1. tan(100) - 99 ** 2
2. (((54 / cos(18)) - 3) + 13) - 7 ** 2
3. (93 / cos(4)) * 1
4. (tan(46) - 3) * 9
5. ((86 - 43) + 83) * 10 ** tan(2)
6. (((25 * 6) + 60) + 70) / cos(116)
7. tan(46) * 3 ** 2
8. (((65 - tan(2)6) - 30 ** 2) * 4) * 1
9. tan(53) ** 2 - 37
10. (((56 - sin(33)) * 8) + 34 ** 2) - 33
11. (((sin(60) - 44) - 14) + 25) + 31
12. ((cos(49) * 10) - 304) - 177
13. ((51 + 100) - 30 ** 2) * cos(8)
14. ((46 / 64) * 5) / sin(2)
15. (((59 * 6) - tan(306) ** 2) + 14) * 3
16. (((tan(57) - 29) + 4) * 2) * 7
17. ((tan(71) + 87) + 59) - 74 ** 2
18. 43 * sqrt(8tan(1))1
19. (((98 ** sin(2) + 32) - 127) - 2) + 81
20. ((cos(25) + 17) + 25) + 59
21. sin(2)7 ** 2 / 9
22. (83 + 67 ** sin(2)) / 5
23. 81 * cos(4) ** 2
24. (3cos(6) - 73) - 6
25. (((sin(36) + 82 ** 2) + 4) + 70) / 4
26. cos(80) - 64
27. (5cos(2) ** 2 + 54) / 2
28. (((sin(93) - 75 ** 2) + 10) * 5) * 6
29. 62 ** 2 * tan(7)
30. ((tan(58) * 9) * 2) - 589

@ -0,0 +1,60 @@
1. (((68 / 2 ** 2) / 2) + tan(57)) - 40
2. ((34 - 81) / 3) - tan(2)
3. (cos(72) * 3) + 4 ** 2
4. (sin(81) + 61) - 77
5. ((((84 + 48) / 12) * 10) * 9) * tan(81)
6. (((sin(32) * 9) - 62) + 25) * 8
7. ((10 ** 2 * cos(3)) * 9) - 61
8. (((sin(81) * 9) * 4) * 2) - 77
9. ((((40 / 4) + 17) * cos(9) ** 2) + 67) / 10
10. (((tan(6) + 81) * 10) - 48) - 61
11. (((36 / 10) - sin(5)) * 3) * 8
12. ((cos(65) - 61) - 2 ** 2) - 2
13. 2 + cos(9)
14. ((((2 ** tan(20) / 2) * 7) / 2) - 31) * 1
15. (10 ** 2 * cos(8)) / 41
16. 1 / sin(9)
17. ((((7 * 2) * tan(6)) - 10 ** 2) + 75) * 10
18. (cos(15) * 1) + 10 ** 2
19. ((((17 * sin(9)) - 49) - 59) * 8) * 7
20. ((10 ** 2 - tan(15)) + 55) - 42
21. ((100 - sin(24)) * 7) * 7
22. (((16 * 10) - 41) / 16) - cos(5)
23. ((((1 / 3) + 39) * 8) + 37) + tan(40)
24. ((10 ** tan(2) * 2) * 7) - 96
25. (tan(63) - 16) - 36
26. 49 + cos(11)
27. (25 + 83) + sin(10) ** 2
28. (((cos(10) ** 2 - 81) + 80) + 41) - 41
29. (((78 + tan(38)) / 4) + 93) / 16
30. (sin(10) ** 2 + 37) + 41
Loading…
Cancel
Save