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.

82 lines
2.6 KiB

"""
概率计算工具
根据积分计算随机点名概率
积分越高,被点到的概率越低
"""
import random
from typing import List, Optional
from sqlalchemy.orm import Session
from backend.models import Student
def calculate_probability_weights(students: List[Student]) -> List[float]:
"""
计算每个学生的权重(积分越低,权重越高)
算法:使用反比例函数,权重 = 1 / (积分 + 1)
这样可以确保:
1. 积分为0的学生权重最高
2. 积分越高,权重越低
3. 所有学生都有被点到的可能
"""
weights = []
for student in students:
# 使用反比例函数,+1避免除零
weight = 1.0 / (student.total_score + 1.0)
weights.append(weight)
return weights
def weighted_random_select(students: List[Student], weights: List[float]) -> Student:
"""
根据权重随机选择一个学生
"""
if not students:
raise ValueError("学生列表为空")
if len(students) != len(weights):
raise ValueError("学生列表和权重列表长度不匹配")
# 使用random.choices进行加权随机选择
selected = random.choices(students, weights=weights, k=1)[0]
return selected
def get_random_student(db: Session) -> Student:
"""
从数据库中随机选择一个学生(考虑积分权重)
"""
students = db.query(Student).all()
if not students:
raise ValueError("数据库中没有学生")
weights = calculate_probability_weights(students)
selected = weighted_random_select(students, weights)
return selected
def get_next_order_student(db: Session, current_student_id: Optional[int] = None) -> Student:
"""
按学号顺序获取下一个学生
"""
if current_student_id is None:
# 获取第一个学生(按学号排序)
student = db.query(Student).order_by(Student.student_id).first()
else:
# 获取当前学生的下一个学生
current_student = db.query(Student).filter(Student.id == current_student_id).first()
if current_student:
student = (
db.query(Student)
.filter(Student.student_id > current_student.student_id)
.order_by(Student.student_id)
.first()
)
# 如果没有下一个,返回第一个(循环)
if not student:
student = db.query(Student).order_by(Student.student_id).first()
else:
student = db.query(Student).order_by(Student.student_id).first()
if not student:
raise ValueError("数据库中没有学生")
return student