|
|
#!/usr/bin/env python3
|
|
|
# -*- coding: utf-8 -*-
|
|
|
"""
|
|
|
数学题目生成器
|
|
|
生成小学、初中、高中的数学选择题
|
|
|
"""
|
|
|
|
|
|
import random
|
|
|
import math
|
|
|
|
|
|
class QuestionGenerator:
|
|
|
"""数学题目生成器"""
|
|
|
|
|
|
def __init__(self):
|
|
|
self.generated_questions = set() # 用于避免重复题目
|
|
|
|
|
|
def generate_questions(self, level, count):
|
|
|
"""生成指定数量和难度的题目"""
|
|
|
questions = []
|
|
|
self.generated_questions.clear()
|
|
|
|
|
|
for _ in range(count):
|
|
|
question = self._generate_single_question(level)
|
|
|
# 确保题目不重复
|
|
|
while str(question) in self.generated_questions:
|
|
|
question = self._generate_single_question(level)
|
|
|
|
|
|
self.generated_questions.add(str(question))
|
|
|
questions.append(question)
|
|
|
|
|
|
return questions
|
|
|
|
|
|
def _generate_single_question(self, level):
|
|
|
"""生成单个题目"""
|
|
|
if level == "小学":
|
|
|
return self._generate_primary_question()
|
|
|
elif level == "初中":
|
|
|
return self._generate_middle_question()
|
|
|
elif level == "高中":
|
|
|
return self._generate_high_question()
|
|
|
else:
|
|
|
raise ValueError("不支持的学段")
|
|
|
|
|
|
def _generate_primary_question(self):
|
|
|
"""生成小学题目"""
|
|
|
question_types = [
|
|
|
self._basic_arithmetic,
|
|
|
self._fraction_question,
|
|
|
self._decimal_question,
|
|
|
self._geometry_question,
|
|
|
self._word_problem
|
|
|
]
|
|
|
|
|
|
return random.choice(question_types)()
|
|
|
|
|
|
def _generate_middle_question(self):
|
|
|
"""生成初中题目"""
|
|
|
question_types = [
|
|
|
self._algebra_question,
|
|
|
self._geometry_advanced,
|
|
|
self._function_question,
|
|
|
self._equation_question,
|
|
|
self._statistics_question
|
|
|
]
|
|
|
|
|
|
return random.choice(question_types)()
|
|
|
|
|
|
def _generate_high_question(self):
|
|
|
"""生成高中题目"""
|
|
|
question_types = [
|
|
|
self._trigonometry_question,
|
|
|
self._calculus_question,
|
|
|
self._complex_number_question,
|
|
|
self._sequence_question,
|
|
|
self._probability_question
|
|
|
]
|
|
|
|
|
|
return random.choice(question_types)()
|
|
|
|
|
|
def _basic_arithmetic(self):
|
|
|
"""基础四则运算"""
|
|
|
operations = ['+', '-', '*', '/']
|
|
|
op = random.choice(operations)
|
|
|
|
|
|
if op == '+':
|
|
|
a, b = random.randint(1, 100), random.randint(1, 100)
|
|
|
answer = a + b
|
|
|
question = f"{a} + {b} = ?"
|
|
|
elif op == '-':
|
|
|
a, b = random.randint(50, 100), random.randint(1, 50)
|
|
|
answer = a - b
|
|
|
question = f"{a} - {b} = ?"
|
|
|
elif op == '*':
|
|
|
a, b = random.randint(1, 12), random.randint(1, 12)
|
|
|
answer = a * b
|
|
|
question = f"{a} × {b} = ?"
|
|
|
else: # division
|
|
|
b = random.randint(2, 12)
|
|
|
answer = random.randint(1, 12)
|
|
|
a = b * answer
|
|
|
question = f"{a} ÷ {b} = ?"
|
|
|
|
|
|
# 生成错误选项
|
|
|
options = [answer]
|
|
|
while len(options) < 4:
|
|
|
wrong = answer + random.randint(-10, 10)
|
|
|
if wrong != answer and wrong > 0 and wrong not in options:
|
|
|
options.append(wrong)
|
|
|
|
|
|
random.shuffle(options)
|
|
|
correct_index = options.index(answer)
|
|
|
|
|
|
return {
|
|
|
'question': question,
|
|
|
'options': options,
|
|
|
'correct_answer': correct_index,
|
|
|
'level': '小学'
|
|
|
}
|
|
|
|
|
|
def _fraction_question(self):
|
|
|
"""分数题目"""
|
|
|
# 简单的分数加法
|
|
|
a1, b1 = random.randint(1, 5), random.randint(2, 8)
|
|
|
a2, b2 = random.randint(1, 5), random.randint(2, 8)
|
|
|
|
|
|
# 确保分母相同
|
|
|
b1 = b2 = random.randint(2, 8)
|
|
|
|
|
|
question = f"{a1}/{b1} + {a2}/{b2} = ?"
|
|
|
|
|
|
# 计算答案
|
|
|
numerator = a1 + a2
|
|
|
denominator = b1
|
|
|
|
|
|
# 简化分数
|
|
|
gcd_val = math.gcd(numerator, denominator)
|
|
|
answer_num = numerator // gcd_val
|
|
|
answer_den = denominator // gcd_val
|
|
|
|
|
|
if answer_den == 1:
|
|
|
answer = answer_num
|
|
|
else:
|
|
|
answer = f"{answer_num}/{answer_den}"
|
|
|
|
|
|
# 生成选项
|
|
|
options = [answer]
|
|
|
while len(options) < 4:
|
|
|
if isinstance(answer, int):
|
|
|
wrong = answer + random.randint(-2, 2)
|
|
|
if wrong != answer and wrong > 0:
|
|
|
options.append(wrong)
|
|
|
else:
|
|
|
wrong_num = answer_num + random.randint(-2, 2)
|
|
|
wrong_den = answer_den + random.randint(-1, 1)
|
|
|
if wrong_den <= 0:
|
|
|
wrong_den = answer_den
|
|
|
if wrong_num > 0:
|
|
|
options.append(f"{wrong_num}/{wrong_den}")
|
|
|
|
|
|
random.shuffle(options)
|
|
|
correct_index = options.index(answer)
|
|
|
|
|
|
return {
|
|
|
'question': question,
|
|
|
'options': options,
|
|
|
'correct_answer': correct_index,
|
|
|
'level': '小学'
|
|
|
}
|
|
|
|
|
|
def _decimal_question(self):
|
|
|
"""小数题目"""
|
|
|
a = round(random.uniform(1, 10), 1)
|
|
|
b = round(random.uniform(1, 10), 1)
|
|
|
|
|
|
question = f"{a} + {b} = ?"
|
|
|
answer = round(a + b, 1)
|
|
|
|
|
|
options = [answer]
|
|
|
while len(options) < 4:
|
|
|
wrong = round(answer + random.uniform(-2, 2), 1)
|
|
|
if wrong != answer and wrong > 0 and wrong not in options:
|
|
|
options.append(wrong)
|
|
|
|
|
|
random.shuffle(options)
|
|
|
correct_index = options.index(answer)
|
|
|
|
|
|
return {
|
|
|
'question': question,
|
|
|
'options': options,
|
|
|
'correct_answer': correct_index,
|
|
|
'level': '小学'
|
|
|
}
|
|
|
|
|
|
def _geometry_question(self):
|
|
|
"""几何题目"""
|
|
|
shapes = ['正方形', '长方形', '圆形', '三角形']
|
|
|
shape = random.choice(shapes)
|
|
|
|
|
|
if shape == '正方形':
|
|
|
side = random.randint(2, 10)
|
|
|
question = f"边长为{side}的正方形的面积是?"
|
|
|
answer = side * side
|
|
|
elif shape == '长方形':
|
|
|
length = random.randint(3, 10)
|
|
|
width = random.randint(2, 8)
|
|
|
question = f"长为{length},宽为{width}的长方形的面积是?"
|
|
|
answer = length * width
|
|
|
elif shape == '圆形':
|
|
|
radius = random.randint(2, 8)
|
|
|
question = f"半径为{radius}的圆的面积是?(π取3.14)"
|
|
|
answer = round(3.14 * radius * radius, 2)
|
|
|
else: # 三角形
|
|
|
base = random.randint(3, 10)
|
|
|
height = random.randint(2, 8)
|
|
|
question = f"底为{base},高为{height}的三角形的面积是?"
|
|
|
answer = base * height // 2
|
|
|
|
|
|
options = [answer]
|
|
|
while len(options) < 4:
|
|
|
wrong = answer + random.randint(-5, 5)
|
|
|
if wrong != answer and wrong > 0 and wrong not in options:
|
|
|
options.append(wrong)
|
|
|
|
|
|
random.shuffle(options)
|
|
|
correct_index = options.index(answer)
|
|
|
|
|
|
return {
|
|
|
'question': question,
|
|
|
'options': options,
|
|
|
'correct_answer': correct_index,
|
|
|
'level': '小学'
|
|
|
}
|
|
|
|
|
|
def _word_problem(self):
|
|
|
"""应用题"""
|
|
|
problems = [
|
|
|
("小明有{}个苹果,吃了{}个,还剩多少个?", lambda x, y: x - y),
|
|
|
("小红有{}元钱,买书花了{}元,还剩多少元?", lambda x, y: x - y),
|
|
|
("班级有{}个学生,又来了{}个新同学,现在有多少个学生?", lambda x, y: x + y),
|
|
|
("一盒铅笔有{}支,{}盒铅笔一共有多少支?", lambda x, y: x * y)
|
|
|
]
|
|
|
|
|
|
problem, func = random.choice(problems)
|
|
|
a = random.randint(1, 20)
|
|
|
b = random.randint(1, 10)
|
|
|
|
|
|
question = problem.format(a, b)
|
|
|
answer = func(a, b)
|
|
|
|
|
|
options = [answer]
|
|
|
while len(options) < 4:
|
|
|
wrong = answer + random.randint(-3, 3)
|
|
|
if wrong != answer and wrong > 0 and wrong not in options:
|
|
|
options.append(wrong)
|
|
|
|
|
|
random.shuffle(options)
|
|
|
correct_index = options.index(answer)
|
|
|
|
|
|
return {
|
|
|
'question': question,
|
|
|
'options': options,
|
|
|
'correct_answer': correct_index,
|
|
|
'level': '小学'
|
|
|
}
|
|
|
|
|
|
def _algebra_question(self):
|
|
|
"""代数题目"""
|
|
|
x = random.randint(1, 10)
|
|
|
a = random.randint(2, 10)
|
|
|
b = random.randint(1, 20)
|
|
|
|
|
|
question = f"解方程:{a}x + {b} = {a*x + b}"
|
|
|
answer = x
|
|
|
|
|
|
options = [answer]
|
|
|
while len(options) < 4:
|
|
|
wrong = answer + random.randint(-3, 3)
|
|
|
if wrong != answer and wrong > 0 and wrong not in options:
|
|
|
options.append(wrong)
|
|
|
|
|
|
random.shuffle(options)
|
|
|
correct_index = options.index(answer)
|
|
|
|
|
|
return {
|
|
|
'question': question,
|
|
|
'options': options,
|
|
|
'correct_answer': correct_index,
|
|
|
'level': '初中'
|
|
|
}
|
|
|
|
|
|
def _geometry_advanced(self):
|
|
|
"""高级几何题目"""
|
|
|
# 勾股定理
|
|
|
a = random.randint(3, 8)
|
|
|
b = random.randint(3, 8)
|
|
|
c = round(math.sqrt(a*a + b*b), 2)
|
|
|
|
|
|
question = f"直角三角形的两条直角边分别为{a}和{b},斜边长为?"
|
|
|
answer = c
|
|
|
|
|
|
options = [answer]
|
|
|
while len(options) < 4:
|
|
|
wrong = round(c + random.uniform(-2, 2), 2)
|
|
|
if wrong != answer and wrong > 0 and wrong not in options:
|
|
|
options.append(wrong)
|
|
|
|
|
|
random.shuffle(options)
|
|
|
correct_index = options.index(answer)
|
|
|
|
|
|
return {
|
|
|
'question': question,
|
|
|
'options': options,
|
|
|
'correct_answer': correct_index,
|
|
|
'level': '初中'
|
|
|
}
|
|
|
|
|
|
def _function_question(self):
|
|
|
"""函数题目"""
|
|
|
a = random.randint(1, 5)
|
|
|
b = random.randint(1, 10)
|
|
|
x = random.randint(1, 10)
|
|
|
|
|
|
question = f"函数f(x) = {a}x + {b},求f({x})的值"
|
|
|
answer = a * x + b
|
|
|
|
|
|
options = [answer]
|
|
|
while len(options) < 4:
|
|
|
wrong = answer + random.randint(-5, 5)
|
|
|
if wrong != answer and wrong not in options:
|
|
|
options.append(wrong)
|
|
|
|
|
|
random.shuffle(options)
|
|
|
correct_index = options.index(answer)
|
|
|
|
|
|
return {
|
|
|
'question': question,
|
|
|
'options': options,
|
|
|
'correct_answer': correct_index,
|
|
|
'level': '初中'
|
|
|
}
|
|
|
|
|
|
def _equation_question(self):
|
|
|
"""方程题目"""
|
|
|
x = random.randint(1, 10)
|
|
|
a = random.randint(2, 5)
|
|
|
b = random.randint(1, 10)
|
|
|
|
|
|
question = f"解方程:{a}x - {b} = {a*x - b}"
|
|
|
answer = x
|
|
|
|
|
|
options = [answer]
|
|
|
while len(options) < 4:
|
|
|
wrong = answer + random.randint(-3, 3)
|
|
|
if wrong != answer and wrong not in options:
|
|
|
options.append(wrong)
|
|
|
|
|
|
random.shuffle(options)
|
|
|
correct_index = options.index(answer)
|
|
|
|
|
|
return {
|
|
|
'question': question,
|
|
|
'options': options,
|
|
|
'correct_answer': correct_index,
|
|
|
'level': '初中'
|
|
|
}
|
|
|
|
|
|
def _statistics_question(self):
|
|
|
"""统计题目"""
|
|
|
numbers = [random.randint(1, 20) for _ in range(5)]
|
|
|
question = f"数据{numbers}的中位数是?"
|
|
|
|
|
|
sorted_nums = sorted(numbers)
|
|
|
answer = sorted_nums[2] # 中位数
|
|
|
|
|
|
options = [answer]
|
|
|
while len(options) < 4:
|
|
|
wrong = answer + random.randint(-3, 3)
|
|
|
if wrong != answer and wrong > 0 and wrong not in options:
|
|
|
options.append(wrong)
|
|
|
|
|
|
random.shuffle(options)
|
|
|
correct_index = options.index(answer)
|
|
|
|
|
|
return {
|
|
|
'question': question,
|
|
|
'options': options,
|
|
|
'correct_answer': correct_index,
|
|
|
'level': '初中'
|
|
|
}
|
|
|
|
|
|
def _trigonometry_question(self):
|
|
|
"""三角函数题目"""
|
|
|
angle = random.choice([30, 45, 60])
|
|
|
question = f"sin({angle}°) = ?"
|
|
|
|
|
|
if angle == 30:
|
|
|
answer = "1/2"
|
|
|
elif angle == 45:
|
|
|
answer = "√2/2"
|
|
|
else: # 60
|
|
|
answer = "√3/2"
|
|
|
|
|
|
options = [answer, "1/2", "√2/2", "√3/2"]
|
|
|
options = list(set(options)) # 去重
|
|
|
|
|
|
while len(options) < 4:
|
|
|
options.append(f"{random.randint(1,3)}/{random.randint(2,4)}")
|
|
|
|
|
|
random.shuffle(options)
|
|
|
correct_index = options.index(answer)
|
|
|
|
|
|
return {
|
|
|
'question': question,
|
|
|
'options': options,
|
|
|
'correct_answer': correct_index,
|
|
|
'level': '高中'
|
|
|
}
|
|
|
|
|
|
def _calculus_question(self):
|
|
|
"""微积分题目"""
|
|
|
# 简单的导数
|
|
|
a = random.randint(1, 5)
|
|
|
b = random.randint(1, 10)
|
|
|
|
|
|
question = f"函数f(x) = {a}x² + {b}x的导数是?"
|
|
|
answer = f"{2*a}x + {b}"
|
|
|
|
|
|
options = [answer]
|
|
|
while len(options) < 4:
|
|
|
wrong_a = random.randint(1, 5)
|
|
|
wrong_b = random.randint(1, 10)
|
|
|
if f"{wrong_a}x + {wrong_b}" != answer:
|
|
|
options.append(f"{wrong_a}x + {wrong_b}")
|
|
|
|
|
|
random.shuffle(options)
|
|
|
correct_index = options.index(answer)
|
|
|
|
|
|
return {
|
|
|
'question': question,
|
|
|
'options': options,
|
|
|
'correct_answer': correct_index,
|
|
|
'level': '高中'
|
|
|
}
|
|
|
|
|
|
def _complex_number_question(self):
|
|
|
"""复数题目"""
|
|
|
a = random.randint(1, 5)
|
|
|
b = random.randint(1, 5)
|
|
|
|
|
|
question = f"复数{a} + {b}i的模长是?"
|
|
|
answer = round(math.sqrt(a*a + b*b), 2)
|
|
|
|
|
|
options = [answer]
|
|
|
while len(options) < 4:
|
|
|
wrong = round(answer + random.uniform(-2, 2), 2)
|
|
|
if wrong != answer and wrong > 0 and wrong not in options:
|
|
|
options.append(wrong)
|
|
|
|
|
|
random.shuffle(options)
|
|
|
correct_index = options.index(answer)
|
|
|
|
|
|
return {
|
|
|
'question': question,
|
|
|
'options': options,
|
|
|
'correct_answer': correct_index,
|
|
|
'level': '高中'
|
|
|
}
|
|
|
|
|
|
def _sequence_question(self):
|
|
|
"""数列题目"""
|
|
|
a1 = random.randint(1, 10)
|
|
|
d = random.randint(1, 5)
|
|
|
n = random.randint(3, 8)
|
|
|
|
|
|
question = f"等差数列首项为{a1},公差为{d},第{n}项是?"
|
|
|
answer = a1 + (n-1) * d
|
|
|
|
|
|
options = [answer]
|
|
|
while len(options) < 4:
|
|
|
wrong = answer + random.randint(-5, 5)
|
|
|
if wrong != answer and wrong not in options:
|
|
|
options.append(wrong)
|
|
|
|
|
|
random.shuffle(options)
|
|
|
correct_index = options.index(answer)
|
|
|
|
|
|
return {
|
|
|
'question': question,
|
|
|
'options': options,
|
|
|
'correct_answer': correct_index,
|
|
|
'level': '高中'
|
|
|
}
|
|
|
|
|
|
def _probability_question(self):
|
|
|
"""概率题目"""
|
|
|
# 简单的概率计算
|
|
|
total = random.randint(10, 20)
|
|
|
favorable = random.randint(1, total-1)
|
|
|
|
|
|
question = f"袋子里有{total}个球,其中{favorable}个是红球,随机取出一个球是红球的概率是?"
|
|
|
answer = f"{favorable}/{total}"
|
|
|
|
|
|
options = [answer]
|
|
|
while len(options) < 4:
|
|
|
wrong_total = random.randint(5, 25)
|
|
|
wrong_favorable = random.randint(1, wrong_total-1)
|
|
|
wrong_answer = f"{wrong_favorable}/{wrong_total}"
|
|
|
if wrong_answer != answer and wrong_answer not in options:
|
|
|
options.append(wrong_answer)
|
|
|
|
|
|
random.shuffle(options)
|
|
|
correct_index = options.index(answer)
|
|
|
|
|
|
return {
|
|
|
'question': question,
|
|
|
'options': options,
|
|
|
'correct_answer': correct_index,
|
|
|
'level': '高中'
|
|
|
}
|