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()