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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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