You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Mathlearn/src/question_generator.py

520 lines
16 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#!/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': '高中'
}