121 lines
3.8 KiB
Python
121 lines
3.8 KiB
Python
import random
|
|
|
|
|
|
class Puzzle:
|
|
pass
|
|
|
|
|
|
class BlankPuzzle(Puzzle):
|
|
"""填空题谜题生成器
|
|
|
|
Args:
|
|
text: 原始字符串(需要 "/" 分割句子, 末尾应有 "/")
|
|
min_denominator: 最小概率倒数(如占所有可生成填空数的 1/7 中的 7, 若期望值小于 1, 则取 1)
|
|
"""
|
|
|
|
def __init__(self, text: str, min_denominator: int):
|
|
self.text = text
|
|
self.min_denominator = min_denominator
|
|
self.wording = "填空题 - 尚未刷新谜题"
|
|
self.answer = ["填空题 - 尚未刷新谜题"]
|
|
|
|
def refresh(self): # 刷新谜题
|
|
placeholder = "___SLASH___"
|
|
tmp_text = self.text.replace("/", placeholder)
|
|
words = tmp_text.split(placeholder)
|
|
if not words:
|
|
return
|
|
words = [word for word in words if word]
|
|
num_blanks = min(max(1, len(words) // self.min_denominator), len(words))
|
|
indices_to_blank = random.sample(range(len(words)), num_blanks)
|
|
indices_to_blank.sort()
|
|
blanked_words = list(words)
|
|
answer = list()
|
|
for index in indices_to_blank:
|
|
blanked_words[index] = "__" * len(words[index])
|
|
answer.append(words[index])
|
|
self.answer = answer
|
|
self.wording = "".join(blanked_words)
|
|
|
|
def __str__(self):
|
|
return f"{self.wording}\n{str(self.answer)}"
|
|
|
|
|
|
class SelectionPuzzle(Puzzle):
|
|
"""选择题谜题生成器
|
|
|
|
Args:
|
|
mapping: 正确选项映射 {问题: 答案}
|
|
jammer: 干扰项列表
|
|
max_riddles_num: 最大生成谜题数 (默认2个)
|
|
prefix: 问题前缀
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
mapping: dict,
|
|
jammer: list,
|
|
max_riddles_num: int = 2,
|
|
prefix: str = ""
|
|
):
|
|
self.prefix = prefix
|
|
self.mapping = mapping
|
|
self.jammer = list(set(jammer + list(mapping.values())))
|
|
while len(self.jammer) < 4:
|
|
self.jammer.append(" ")
|
|
self.max_riddles_num = max(1, min(max_riddles_num, 5))
|
|
self.wording = "选择题 - 尚未刷新谜题"
|
|
self.answer = ["选择题 - 尚未刷新谜题"]
|
|
self.options = []
|
|
|
|
def refresh(self):
|
|
"""刷新谜题,根据题目数量生成适当数量的谜题"""
|
|
if not self.mapping:
|
|
self.wording = "无可用题目"
|
|
self.answer = ["无答案"]
|
|
self.options = []
|
|
return
|
|
|
|
num_questions = min(self.max_riddles_num, len(self.mapping))
|
|
questions = random.sample(list(self.mapping.items()), num_questions)
|
|
puzzles = []
|
|
answers = []
|
|
all_options = []
|
|
|
|
for question, correct_answer in questions:
|
|
options = [correct_answer]
|
|
available_jammers = [
|
|
j for j in self.jammer if j != correct_answer
|
|
]
|
|
if len(available_jammers) >= 3:
|
|
selected_jammers = random.sample(available_jammers, 3)
|
|
else:
|
|
selected_jammers = random.choices(available_jammers, k=3)
|
|
options.extend(selected_jammers)
|
|
random.shuffle(options)
|
|
puzzles.append(question)
|
|
answers.append(correct_answer)
|
|
all_options.append(options)
|
|
|
|
question_texts = []
|
|
for i, puzzle in enumerate(puzzles):
|
|
question_texts.append(f"{self.prefix}:\n {i+1}. {puzzle}")
|
|
|
|
self.wording = question_texts
|
|
self.answer = answers
|
|
self.options = all_options
|
|
|
|
def __str__(self):
|
|
return f"{self.wording}\n正确答案: {', '.join(self.answer)}"
|
|
|
|
if __name__ == "__main__":
|
|
puz = SelectionPuzzle(
|
|
{"1+1": "2", "1+2": "3", "1+3": "4"},
|
|
["2", "5", "0"],
|
|
3,
|
|
'求值: '
|
|
)
|
|
puz.refresh()
|
|
print(puz.wording)
|
|
print(puz.answer)
|
|
print(puz.options) |