# Copyright (c) 2025 Jeffrey Hsu - JITToolBox # # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import random from typing import Optional, Tuple, NoReturn from openpyxl.reader.excel import load_workbook class Question: def __init__(self, no: str, topic: str): self._no: str = no self._topic: str = topic self._count: int = 0 def __str__(self): return f"Question" def __repr__(self): return self.__str__() @staticmethod def load_from_csv(path: Optional[str] = None) -> list['Question']: questions = [] with open(path if path else '../files/questions.csv', encoding='gbk') as f: for line in f.readlines(): questions.append(Question(*line.strip('\n').split(','))) return questions @staticmethod def load_from_xls(path: str) -> list['Question']: questions = [] wb = load_workbook(path, read_only=True) ws = wb.active for row in ws.iter_rows(min_col=2, max_col=3, min_row=2, values_only=True): if row[0] is None and row[1] is None: break questions.append(Question(*row)) wb.close() return questions @property def no(self) -> str: return self._no @property def topic(self) -> str: return self._topic def increase_count(self) -> None: self._count += 1 def can_pick(self, max_count: int) -> bool: return self._count <= max_count class Student: def __init__(self, no: str, so: str, name: str, major: str, class_name: str): self._no: str = no self._so: str = so self._name: str = name self._major: str = major self._class_name: str = class_name self._picked_questions: list[Question] = [] def __str__(self): return f"Student" def __repr__(self): return self.__str__() @staticmethod def load_from_xls(path: str) -> list['Student'] | NoReturn: wb = load_workbook(path, read_only=True) ws = wb.active students = [] if ws.title == 'Sheet1': for row in ws.iter_rows(min_row=6, max_col=5, values_only=True): students.append(Student(*row)) elif ws.title == '初始录入': for row in ws.iter_rows(min_row=13, max_col=5, values_only=True): students.append(Student(*row)) else: raise Exception("无法解析学生名单") wb.close() return [x for x in students if x.valid] @property def valid(self) -> bool: return bool(self._no and self._so and self._name and self._major and self._class_name) @property def picked_questions(self) -> list[Question]: return self._picked_questions @property def no(self) -> str: return self._no @property def so(self) -> str: return self._so @property def name(self) -> str: return self._name @property def major(self) -> str: return self._major @property def class_name(self) -> str: return self._class_name def pick_question(self, questions: list[Question], num: int = 3, max_count: int = 3) -> None: available_questions = [q for q in questions if q.can_pick(max_count)] if len(available_questions) < num: raise ValueError("Not enough questions with count <= max_count") self._picked_questions = random.sample(available_questions, num) for q in self._picked_questions: q.increase_count() class Course: def __init__(self, name: str): self._name = name def __str__(self): return f"Course" def __repr__(self): return self.__str__() @staticmethod def load_from_xls(path: str) -> 'Course' | NoReturn: wb = load_workbook(path, read_only=True) ws = wb.active if ws.title == 'Sheet1': name: str = ws['E3'].value[5:] elif ws.title == '初始录入': name: str = ws['D5'].value else: raise Exception("无法解析课程名") wb.close() return Course(name) @property def name(self) -> str: return self._name class Performance: def __init__(self, scores: Tuple[float, float, float], rates: Tuple[float, float, float], achievement: float): self.scores = scores # (平时平均分, 大作业平均分, 试卷平均分) self.rates = rates # (平时得分率, 大作业得分率, 试卷得分率) self.achievement = achievement # 达成度 def __str__(self): return f"Performance(scores={self.scores}, rates={self.rates}, achievement={self.achievement})" if __name__ == '__main__': ...