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.

410 lines
17 KiB

import sys
import random
import pygame
import pandas as pd
# 学生类,表示学生的信息
class Student:
def __init__(self, id: str, count=0, score=0, consecutive_correct=0):
self.id = id
self.count = count
self.score = score
self.consecutive_correct = consecutive_correct # 连续正确次数
def __repr__(self):
return f"{self.id}, Count: {self.count}, Score: {self.score}, Consecutive Correct: {self.consecutive_correct}"
class RandomNamePicker:
def __init__(self):
pygame.init()
self.screen_width = 1238
self.screen_height = 720
self.screen = pygame.display.set_mode((self.screen_width, self.screen_height))
pygame.display.set_caption("随机点名程序")
self.background = pygame.image.load("./assets/01.png").convert()
self.background = pygame.transform.scale(self.background, (self.screen_width, self.screen_height))
self.previous_background = None # 用于保存之前的背景图
self.students = self.load_students()
self.current_student = None
self.state = "initial"
self.first_pick = True
self.is_first_pick = True
# 设置按钮(圆形按钮)
self.settings_button = ("设置", pygame.Rect(20, 20, 50, 50), self.open_settings)
# 帮助按钮(圆形按钮)
self.help_button = ("帮助", pygame.Rect(self.screen_width - 120, 20, 50, 50), self.open_help)
# 关闭设置和帮助界面按钮
self.close_settings_button = ("X", pygame.Rect(self.screen_width - 60, 20, 40, 40), self.close_settings)
# 音乐和音效的状态
self.music_on = True
self.sound_on = True
# 音乐控制
self.music_files = [f"./assets/{i}.mp3" for i in range(1, 10)]
pygame.mixer.init()
self.play_music()
# 加载按钮音效
self.button_sound = pygame.mixer.Sound("./assets/按钮音效.mp3")
# 设置界面按钮
self.settings_menu_buttons = [
("关闭音乐", pygame.Rect(self.screen_width // 2 - 100, self.screen_height // 2 - 90, 200, 50),
self.toggle_music),
("关闭音效", pygame.Rect(self.screen_width // 2 - 100, self.screen_height // 2 - 30, 200, 50),
self.toggle_sound)
]
# 初始按钮
self.initial_buttons = [
("开始点名", pygame.Rect(self.screen_width // 2 - 100, 50, 200, 50), self.start_picking),
("退出点名", pygame.Rect(self.screen_width // 2 - 100, 120, 200, 50), sys.exit)
]
self.confirm_buttons = [
("", pygame.Rect(self.screen_width // 2 - 100, self.screen_height // 2 - 90, 200, 50),
self.student_present),
("没到", pygame.Rect(self.screen_width // 2 - 100, self.screen_height // 2 - 30, 200, 50),
self.student_absent)
]
self.accuracy_buttons = [
("能准确重复", pygame.Rect(self.screen_width // 2 - 100, self.screen_height // 2 - 90, 200, 50),
self.accurate_repeat),
("不能重复", pygame.Rect(self.screen_width // 2 - 100, self.screen_height // 2 - 30, 200, 50),
self.inaccurate_repeat)
]
self.picking_buttons = [
("完全正确", pygame.Rect(self.screen_width // 2 - 100, self.screen_height // 2 - 120, 200, 50),
lambda: self.update_score(3, "完全正确")),
("部分正确", pygame.Rect(self.screen_width // 2 - 100, self.screen_height // 2 - 60, 200, 50),
lambda: self.update_score(1.5, "部分正确")),
("勉强正确", pygame.Rect(self.screen_width // 2 - 100, self.screen_height // 2, 200, 50),
lambda: self.update_score(0.5, "勉强正确")),
("错误", pygame.Rect(self.screen_width // 2 - 100, self.screen_height // 2 + 60, 200, 50),
lambda: self.update_score(-1, "错误"))
]
self.font = pygame.font.Font("C:\Windows\Fonts\simhei.ttf", 20)
self.result_label = ""
self.message_label = ""
self.pick_message = ""
self.temp_result_label = ""
self.temp_message_label = ""
def play_music(self):
if self.music_on:
self.current_music_index = random.randint(0, len(self.music_files) - 1)
pygame.mixer.music.load(self.music_files[self.current_music_index])
pygame.mixer.music.set_volume(0.1)
pygame.mixer.music.play(-1)
def toggle_music(self):
if self.music_on:
pygame.mixer.music.stop()
self.music_on = False
self.settings_menu_buttons[0] = ("打开音乐", self.settings_menu_buttons[0][1], self.toggle_music)
else:
self.play_music()
self.music_on = True
self.settings_menu_buttons[0] = ("关闭音乐", self.settings_menu_buttons[0][1], self.toggle_music)
def toggle_sound(self):
if self.sound_on:
self.sound_on = False
self.settings_menu_buttons[1] = ("打开音效", self.settings_menu_buttons[1][1], self.toggle_sound)
else:
self.sound_on = True
self.settings_menu_buttons[1] = ("关闭音效", self.settings_menu_buttons[1][1], self.toggle_sound)
def load_students(self):
students = []
try:
df = pd.read_excel("./assets/1.xlsx")
for _, row in df.iterrows():
id = str(row['id'])
count = int(row['count'])
score = int(row['score'])
consecutive_correct = int(row['temp'])
students.append(Student(id, count, score, consecutive_correct))
except FileNotFoundError:
self.result_label = "学生信息文件未找到!"
except pd.errors.EmptyDataError:
self.result_label = "Excel文件格式错误或文件为空"
return students
def start_picking(self):
if not self.students:
self.result_label = "没有学生信息!"
return
if self.is_first_pick:
self.is_first_pick = False
button_text = "继续点名"
self.initial_buttons[0] = (button_text, self.initial_buttons[0][1], self.start_picking)
self.current_student = self.weighted_random_pick()
if self.current_student:
self.result_label = f"(被点名: {self.current_student.id})"
else:
self.result_label = "点名失败,没有可选学生。"
self.message_label = ""
self.state = "confirm"
self.background = pygame.image.load("./assets/01.1.png").convert()
self.background = pygame.transform.scale(self.background, (self.screen_width, self.screen_height))
def weighted_random_pick(self):
max_score = max(student.score for student in self.students)
weights = [max_score - student.score + 1 for student in self.students]
total_weight = sum(weights)
pick = random.uniform(0, total_weight)
current = 0
for student, weight in zip(self.students, weights):
current += weight
if current >= pick:
return student
def student_present(self):
if self.current_student:
self.current_student.score += 1
self.result_label = f"({self.current_student.id} 到场,奖励一分!新分数:{self.current_student.score})"
self.save_students()
self.pick_message = "啊,点到我了!"
self.background = pygame.image.load("./assets/02.png").convert()
self.background = pygame.transform.scale(self.background, (self.screen_width, self.screen_height))
self.state = "accuracy_check"
def accurate_repeat(self):
if self.current_student:
self.current_student.score += 0.5
self.result_label = f"({self.current_student.id} 能准确重复奖励0.5分!新分数:{self.current_student.score})"
self.save_students()
self.state = "picking"
def inaccurate_repeat(self):
if self.current_student:
self.current_student.score -= 1
self.result_label = f"({self.current_student.id} 不能重复扣1分新分数{self.current_student.score})"
self.save_students()
self.state = "picking"
def student_absent(self):
self.state = "initial"
self.background = pygame.image.load("./assets/01.png").convert()
self.background = pygame.transform.scale(self.background, (self.screen_width, self.screen_height))
def update_score(self, delta, answer_type):
self.result_label = ""
self.message_label = ""
multiplier_message = ""
if self.current_student.score % 4 == 0 and answer_type == "错误":
delta *= 2
multiplier_message = ",触发双倍扣分!"
elif self.current_student.score % 6 == 0 and answer_type == "完全正确":
delta *= 2
multiplier_message = ",触发双倍加分!"
self.current_student.score += delta
self.current_student.count += 1
if answer_type == "完全正确":
self.current_student.consecutive_correct += 1
else:
self.current_student.consecutive_correct = 0
if self.current_student.consecutive_correct == 7:
self.current_student.score = 50
multiplier_message += " 连续7次完全正确分数直升至50分。"
if self.current_student.score >= 50:
multiplier_message += " 已达到满分50分将不会再被点到。"
self.result_label = f"{self.current_student.id} 的新分数 {self.current_student.score},点名次数:{self.current_student.count}{multiplier_message}"
self.save_students()
if answer_type == "部分正确":
self.message_label = "可惜,下次再加油吧•﹏•"
elif answer_type == "完全正确":
self.message_label = "yeah~答对咯!( ^ _ ^ )"
elif answer_type == "勉强正确":
self.message_label = "还行,勉强算正确吧。"
elif answer_type == "错误":
self.message_label = "啊啊啊啊——答错啦╥﹏╥..."
if answer_type == "完全正确":
self.background = pygame.image.load("./assets/04对.png").convert()
elif answer_type == "部分正确" or answer_type == "勉强正确":
self.background = pygame.image.load("./assets/04中.png").convert()
elif answer_type == "错误":
self.background = pygame.image.load("./assets/04错.png").convert()
self.background = pygame.transform.scale(self.background, (self.screen_width, self.screen_height))
self.pick_message = ""
self.state = "initial"
def save_students(self):
df = pd.DataFrame([{'id': student.id, 'count': student.count, 'score': student.score,
'temp': student.consecutive_correct} for student in self.students])
df.to_excel("./assets/1.xlsx", index=False)
def open_settings(self):
self.temp_result_label = self.result_label
self.temp_message_label = self.message_label
self.result_label = ""
self.message_label = ""
self.previous_background = self.background # 保存之前的背景图
self.state = "settings"
self.background = pygame.Surface((self.screen_width, self.screen_height))
self.background.fill((169, 169, 169))
def close_settings(self):
self.result_label = self.temp_result_label
self.message_label = self.temp_message_label
self.state = "initial"
if self.previous_background:
self.background = self.previous_background # 恢复之前的背景图
self.previous_background = None
def open_help(self):
self.temp_result_label = self.result_label
self.temp_message_label = self.message_label
self.result_label = ""
self.message_label = ""
self.previous_background = self.background # 保存之前的背景图
self.state = "help"
self.background = pygame.image.load("./assets/介绍.png").convert()
self.background = pygame.transform.scale(self.background, (self.screen_width, self.screen_height))
# 绘制圆形按钮
def draw_circle_button(self, text, rect, color):
center = rect.center
radius = rect.width // 2
pygame.draw.circle(self.screen, color, center, radius)
label = self.font.render(text, True, (0, 0, 0))
label_rect = label.get_rect(center=rect.center)
self.screen.blit(label, label_rect)
# 绘制圆角矩形按钮
def draw_rounded_rect_button(self, text, rect, color):
pygame.draw.rect(self.screen, color, rect, border_radius=20)
label = self.font.render(text, True, (0, 0, 0))
label_rect = label.get_rect(center=rect.center)
self.screen.blit(label, label_rect)
def draw_buttons(self):
mouse_pos = pygame.mouse.get_pos()
if self.state == "initial":
buttons = self.initial_buttons + [self.settings_button, self.help_button]
elif self.state == "confirm":
buttons = self.confirm_buttons
elif self.state == "accuracy_check":
buttons = self.accuracy_buttons
elif self.state == "settings": # 设置界面显示 X 按钮和设置选项
buttons = self.settings_menu_buttons + [self.close_settings_button]
elif self.state == "help": # 帮助界面只显示 X 按钮
buttons = [self.close_settings_button]
else:
buttons = self.picking_buttons
for text, rect, _ in buttons:
color = (100, 100, 255) if rect.collidepoint(mouse_pos) else (255, 255, 255)
if text == "设置" or text == "X" or text == "帮助": # 圆形按钮
self.draw_circle_button(text, rect, color)
else:
self.draw_rounded_rect_button(text, rect, color)
def circle_button_clicked(self, rect, mouse_pos):
center = rect.center
radius = rect.width // 2
dist = ((mouse_pos[0] - center[0]) ** 2 + (mouse_pos[1] - center[1]) ** 2) ** 0.5
return dist <= radius
def draw_label(self):
if self.result_label or self.message_label or self.pick_message:
label_x = 100
if self.pick_message:
pick_surface = self.font.render(self.pick_message, True, (0, 0, 0))
pick_y = self.screen_height - 150
self.screen.blit(pick_surface, (label_x, pick_y))
if self.message_label:
message_surface = self.font.render(self.message_label, True, (0, 0, 0))
message_y = self.screen_height - 150
self.screen.blit(message_surface, (label_x, message_y))
if self.result_label:
result_surface = self.font.render(self.result_label, True, (0, 0, 0))
result_y = self.screen_height - 100
self.screen.blit(result_surface, (label_x, result_y))
def run(self):
running = True
while running:
self.screen.blit(self.background, (0, 0))
self.draw_buttons()
self.draw_label()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
if self.state == "initial":
buttons = self.initial_buttons + [self.settings_button, self.help_button]
elif self.state == "confirm":
buttons = self.confirm_buttons
elif self.state == "accuracy_check":
buttons = self.accuracy_buttons
elif self.state == "settings":
buttons = self.settings_menu_buttons + [self.close_settings_button]
elif self.state == "help":
buttons = [self.close_settings_button]
else:
buttons = self.picking_buttons
mouse_pos = event.pos
for text, rect, action in buttons:
if text == "设置" or text == "X" or text == "帮助":
if self.circle_button_clicked(rect, mouse_pos):
if self.sound_on:
self.button_sound.play()
action()
elif rect.collidepoint(mouse_pos):
if self.sound_on:
self.button_sound.play()
action()
if self.music_on and not pygame.mixer.music.get_busy():
self.play_music()
pygame.display.flip()
pygame.quit()
if __name__ == '__main__':
picker = RandomNamePicker()
picker.run()