新增错题记录功能,错题出现的频率会更高
This commit is contained in:
parent
b37063d4f0
commit
2985fb833e
1
.gitignore
vendored
1
.gitignore
vendored
@ -160,3 +160,4 @@ cython_debug/
|
|||||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
#.idea/
|
#.idea/
|
||||||
|
/*.dat
|
||||||
|
6
Config.py
Normal file
6
Config.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# 配置考卷
|
||||||
|
quest_config = {
|
||||||
|
'A': {'num': 30, 'time': 40, 'pass': 25},
|
||||||
|
'B': {'num': 50, 'time': 60, 'pass': 40},
|
||||||
|
'C': {'num': 80, 'time': 90, 'pass': 60}
|
||||||
|
}
|
65
Generator.py
Normal file
65
Generator.py
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import json
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
import Config
|
||||||
|
|
||||||
|
class Quest:
|
||||||
|
def __init__(self, json_obj):
|
||||||
|
self.index = json_obj['index']
|
||||||
|
self.question = json_obj['Q']
|
||||||
|
self.code = json_obj['I']
|
||||||
|
self.correct = json_obj['A']
|
||||||
|
self.options = [json_obj['A'], json_obj['B'], json_obj['C'], json_obj['D']]
|
||||||
|
self.random_options = random.sample(self.options, len(self.options))
|
||||||
|
|
||||||
|
weight_path = 'weight.dat'
|
||||||
|
|
||||||
|
def enhance_weight(quest: Quest):
|
||||||
|
with open(weight_path, 'r') as f:
|
||||||
|
weight = json.load(f)
|
||||||
|
if quest.code in weight:
|
||||||
|
weight[quest.code] += 10
|
||||||
|
else:
|
||||||
|
weight[quest.code] = 10
|
||||||
|
with open(weight_path, 'w') as f:
|
||||||
|
json.dump(weight, f, ensure_ascii=False, indent=4)
|
||||||
|
pass
|
||||||
|
|
||||||
|
def reduce_weight(quest: Quest):
|
||||||
|
with open(weight_path, 'r') as f:
|
||||||
|
weight = json.load(f)
|
||||||
|
if quest.code in weight:
|
||||||
|
weight[quest.code] -= 1
|
||||||
|
else:
|
||||||
|
weight[quest.code] = -1
|
||||||
|
with open(weight_path, 'w') as f:
|
||||||
|
json.dump(weight, f, ensure_ascii=False, indent=4)
|
||||||
|
pass
|
||||||
|
|
||||||
|
# 模拟加载题目
|
||||||
|
def generate_quests(type_str):
|
||||||
|
# 模拟从JSON文件加载题目
|
||||||
|
with open(f'quests/quests_{type_str}.json', 'r', encoding='utf-8') as f:
|
||||||
|
json_content = json.load(f)
|
||||||
|
list_quest = [Quest(obj) for obj in json_content]
|
||||||
|
# load weight
|
||||||
|
weights = {}
|
||||||
|
if not os.path.exists(weight_path):
|
||||||
|
with open(weight_path, 'w') as f:
|
||||||
|
json.dump({}, f)
|
||||||
|
else:
|
||||||
|
with open(weight_path, 'r') as f:
|
||||||
|
weights = json.load(f)
|
||||||
|
# 将 list_quest 分为有权重和无权重的两部分
|
||||||
|
list_quest_weighted = [quest for quest in list_quest if quest.code in weights]
|
||||||
|
list_quest_unweighted = [quest for quest in list_quest if quest.code not in weights]
|
||||||
|
# 有权中的按权重排序
|
||||||
|
list_quest_weighted.sort(key=lambda x: weights[x.code], reverse=True)
|
||||||
|
list_quest = list_quest_unweighted + list_quest_weighted
|
||||||
|
# 根据权重随机选取题目 80% 的题目来自权重前 40% 的题目 20% 的题目来自权重后 60% 的题目
|
||||||
|
num = Config.quest_config[type_str]['num'] # 要生成的题目数量
|
||||||
|
top = int(num * 0.8)
|
||||||
|
quests = random.sample(list_quest[:top], top) + random.sample(list_quest[top:], num - top)
|
||||||
|
# 对 quests 中的题目再次随机排序
|
||||||
|
random.shuffle(quests)
|
||||||
|
return quests
|
59
Quest.py
59
Quest.py
@ -3,41 +3,13 @@ Quest.py
|
|||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
import random
|
import Generator
|
||||||
import json
|
import Config
|
||||||
import time
|
|
||||||
|
|
||||||
# 配置考卷
|
|
||||||
quest_config = {
|
|
||||||
'A': {'num': 30, 'time': 40, 'pass': 25},
|
|
||||||
'B': {'num': 50, 'time': 60, 'pass': 40},
|
|
||||||
'C': {'num': 80, 'time': 90, 'pass': 60}
|
|
||||||
}
|
|
||||||
|
|
||||||
font = ('Microsoft YaHei', 13)
|
font = ('Microsoft YaHei', 13)
|
||||||
|
|
||||||
|
|
||||||
# 模拟加载题目
|
|
||||||
def generate_quests(type_str):
|
|
||||||
# 模拟从JSON文件加载题目
|
|
||||||
with open(f'quests/quests_{type_str}.json', 'r', encoding='utf-8') as f:
|
|
||||||
json_content = json.load(f)
|
|
||||||
list_quest = []
|
|
||||||
for obj in json_content:
|
|
||||||
list_quest.append(Quest(obj))
|
|
||||||
return random.sample(list_quest, quest_config[type_str]['num'])
|
|
||||||
|
|
||||||
|
|
||||||
class Quest:
|
|
||||||
def __init__(self, json_obj):
|
|
||||||
self.index = json_obj['index']
|
|
||||||
self.question = json_obj['Q']
|
|
||||||
self.code = json_obj['I']
|
|
||||||
self.correct = json_obj['A']
|
|
||||||
self.options = [json_obj['A'], json_obj['B'], json_obj['C'], json_obj['D']]
|
|
||||||
self.random_options = random.sample(self.options, len(self.options))
|
|
||||||
|
|
||||||
|
|
||||||
class ExamApp:
|
class ExamApp:
|
||||||
def __init__(self, root):
|
def __init__(self, root):
|
||||||
self.next_btn = None
|
self.next_btn = None
|
||||||
@ -70,8 +42,8 @@ class ExamApp:
|
|||||||
|
|
||||||
def start_exam(self, level):
|
def start_exam(self, level):
|
||||||
self.level = level
|
self.level = level
|
||||||
self.time_left = quest_config[level]['time'] * 60 # 转换为秒
|
self.time_left = Config.quest_config[level]['time'] * 60 # 转换为秒
|
||||||
self.quests = generate_quests(level)
|
self.quests = Generator.generate_quests(level)
|
||||||
self.current_quest_index = 0
|
self.current_quest_index = 0
|
||||||
self.selected_answers = {i: None for i in range(len(self.quests))}
|
self.selected_answers = {i: None for i in range(len(self.quests))}
|
||||||
self.is_submitted = False
|
self.is_submitted = False
|
||||||
@ -151,6 +123,7 @@ class ExamApp:
|
|||||||
else:
|
else:
|
||||||
# 显示正确答案
|
# 显示正确答案
|
||||||
self.correct_answer_label.config(text=f"正确答案: \n{quest.correct}")
|
self.correct_answer_label.config(text=f"正确答案: \n{quest.correct}")
|
||||||
|
self.update_nav_buttons()
|
||||||
|
|
||||||
if self.current_quest_index == 0:
|
if self.current_quest_index == 0:
|
||||||
self.prev_btn.config(state=tk.DISABLED)
|
self.prev_btn.config(state=tk.DISABLED)
|
||||||
@ -167,13 +140,23 @@ class ExamApp:
|
|||||||
if not self.is_submitted:
|
if not self.is_submitted:
|
||||||
for i in range(len(self.quests)):
|
for i in range(len(self.quests)):
|
||||||
color = "yellow" if self.selected_answers[i] else "white"
|
color = "yellow" if self.selected_answers[i] else "white"
|
||||||
|
if self.current_quest_index == i:
|
||||||
|
color = "gray"
|
||||||
btn = tk.Button(self.ques_nav_frame, text=f"{i + 1}", bg=color,
|
btn = tk.Button(self.ques_nav_frame, text=f"{i + 1}", bg=color,
|
||||||
command=lambda idx=i: self.jump_to_question(idx))
|
command=lambda idx=i: self.jump_to_question(idx))
|
||||||
btn.grid(row=i // 8, column=i % 8, sticky="nsew")
|
btn.grid(row=i // 8, column=i % 8, sticky="nsew")
|
||||||
else:
|
else:
|
||||||
for i in range(len(self.quests)):
|
for i in range(len(self.quests)):
|
||||||
quest = self.quests[i]
|
quest = self.quests[i]
|
||||||
color = "green" if self.selected_answers[i] == quest.correct else "red"
|
# color = "green" if self.selected_answers[i] == quest.correct else "red"
|
||||||
|
color = "green"
|
||||||
|
if self.selected_answers[i] != quest.correct:
|
||||||
|
color = "red"
|
||||||
|
if self.current_quest_index == i:
|
||||||
|
if color == "green":
|
||||||
|
color = "dark green"
|
||||||
|
else:
|
||||||
|
color = "dark red"
|
||||||
btn = tk.Button(self.ques_nav_frame, text=f"{i + 1}", bg=color,
|
btn = tk.Button(self.ques_nav_frame, text=f"{i + 1}", bg=color,
|
||||||
command=lambda idx=i: self.jump_to_question(idx))
|
command=lambda idx=i: self.jump_to_question(idx))
|
||||||
btn.grid(row=i // 8, column=i % 8, sticky="nsew")
|
btn.grid(row=i // 8, column=i % 8, sticky="nsew")
|
||||||
@ -190,9 +173,15 @@ class ExamApp:
|
|||||||
self.is_submitted = True
|
self.is_submitted = True
|
||||||
self.update_question()
|
self.update_question()
|
||||||
self.update_nav_buttons()
|
self.update_nav_buttons()
|
||||||
correct_count = sum(1 for i, quest in enumerate(self.quests) if self.selected_answers[i] == quest.correct)
|
correct_count = 0
|
||||||
|
for i, quest in enumerate(self.quests):
|
||||||
|
if self.selected_answers[i] == quest.correct:
|
||||||
|
correct_count += 1
|
||||||
|
Generator.reduce_weight(quest)
|
||||||
|
else:
|
||||||
|
Generator.enhance_weight(quest)
|
||||||
|
|
||||||
pass_score = quest_config[self.level]['pass']
|
pass_score = Config.quest_config[self.level]['pass']
|
||||||
result_text = "通过" if correct_count >= pass_score else "未通过"
|
result_text = "通过" if correct_count >= pass_score else "未通过"
|
||||||
|
|
||||||
self.timer_score_label.config(text=f"得分: {correct_count}/{len(self.quests)} - {result_text}")
|
self.timer_score_label.config(text=f"得分: {correct_count}/{len(self.quests)} - {result_text}")
|
||||||
|
Loading…
Reference in New Issue
Block a user