import json import pygame from src.settings import HIGHSCORE_COLOR_FONT, HIGHSCORE_COLOR_TABLE class Highscore: def __init__(self): # fix path to json file with highscores self.path = "src/highscore.json" self.font_title = pygame.font.SysFont("Arial", 28, bold=True) self.font_score = pygame.font.SysFont("Arial", 18, bold=True) # check if file already exists, otherwise create it try: with open(self.path, "r") as f: pass except FileNotFoundError: self.save_scores([]) def load_scores(self): """ Will load the highscore json file. :return: All scores form json file. """ with open(self.path, "r") as f: return json.load(f) def save_scores(self, scores): """ Write score data into json file. File will be overwritten. :param scores: Scores to store in json highscore file. :return: None. """ # save scores to file with open(self.path, "w") as file: json.dump(scores, file, indent=4) def add_score(self, player_name, score_ects, time_survived, won): """ Add a new score to the list of existing scores from highscore file. The number of entries is limited to 50. :param player_name: Name of the player. :param score_ects: Scored ECTS in game. :param time_survived: Time survived in game. :param won: Game won/lose. :return: None. """ # load existing scores from file scores = self.load_scores() # assign values from new score and append to existing scores new_score = { "name": player_name, "ects": score_ects, "time": time_survived, "won": won } scores.append(new_score) # sort by ects descending scores.sort(key=lambda score: score["ects"], reverse=True) # keep only top 50 elements scores = scores[:50] self.save_scores(scores) def get_top_scores(self): """ Get top 5 scores from highscore file. :return: Return top 5 scores as list. """ scores = self.load_scores() scores.sort(key=lambda score: score["ects"], reverse=True) return scores[:5] def get_top_scores_formatted(self): """ Get top 5 scores from highscore file in nice format. :return: Return top 5 scores as formatted string in list. """ top_scores = self.get_top_scores() formatted_scores = [] for index, score in enumerate(top_scores): result = "PASSED" if score["won"] else "FAILED" line = ( f"{index + 1}. {score['name']} | " f"ECTS: {score['ects']} | " f"Time: {score['time']} | " f"Result: {result}" ) formatted_scores.append(line) return formatted_scores def draw(self, screen, x, y): # draw box background box_rect = pygame.Rect(x, y, 500, 300) pygame.draw.rect(screen, HIGHSCORE_COLOR_TABLE, box_rect, border_radius=12) pygame.draw.rect(screen, HIGHSCORE_COLOR_TABLE, box_rect, border_radius=12) # title title = self.font_title.render( "ECTS Leaderboard", True, HIGHSCORE_COLOR_FONT ) screen.blit(title, (x + 20, y + 20)) # Get highscore lines highscore_lines = self.get_top_scores_formatted() if len(highscore_lines) == 0: no_scores_text = self.font_score.render( "No students ranked yet.", True, HIGHSCORE_COLOR_FONT ) screen.blit(no_scores_text, (x + 20, y + 70)) return # Draw scores score_y = y + 70 for line in highscore_lines: score_text = self.font_score.render( line, True, HIGHSCORE_COLOR_FONT ) screen.blit(score_text, (x + 20, score_y)) score_y += 35