Files
snake/high_score.py
T

107 lines
3.5 KiB
Python

"""High score and game statistics management."""
import json
from pathlib import Path
from typing import Optional, Dict, List
from dataclasses import dataclass, asdict
from datetime import datetime
@dataclass
class GameRecord:
"""A single game record."""
player_name: str
score: int
length: int
speed: int
timestamp: str
@classmethod
def from_dict(cls, data: dict) -> 'GameRecord':
return cls(**data)
def to_dict(self) -> dict:
return asdict(self)
class HighScoreManager:
"""Manages high scores and game statistics by player."""
def __init__(self):
self.scores_file = Path.home() / '.snake_scores.json'
self.game_records: List[GameRecord] = []
self.load_scores()
def load_scores(self) -> None:
"""Load scores from file."""
if self.scores_file.exists():
try:
with open(self.scores_file, 'r') as f:
data = json.load(f)
self.game_records = [GameRecord.from_dict(r) for r in data.get('records', [])]
except (json.JSONDecodeError, IOError):
self.game_records = []
else:
self.game_records = []
def save_game(self, player_name: str, score: int, length: int, speed: int) -> None:
"""Save a completed game."""
record = GameRecord(
player_name=player_name,
score=score,
length=length,
speed=speed,
timestamp=datetime.now().isoformat()
)
self.game_records.append(record)
self._save_to_file()
def _save_to_file(self) -> None:
"""Save scores to file."""
try:
with open(self.scores_file, 'w') as f:
json.dump({
'records': [r.to_dict() for r in self.game_records]
}, f, indent=2)
except IOError as e:
print(f"Warning: Could not save scores: {e}")
def get_player_stats(self, player_name: str) -> dict:
"""Get game statistics for a specific player."""
player_records = [r for r in self.game_records if r.player_name == player_name]
if not player_records:
return {
'total_games': 0,
'high_score': 0,
'average_score': 0,
'total_length': 0,
}
scores = [r.score for r in player_records]
return {
'total_games': len(player_records),
'high_score': max(scores),
'average_score': sum(scores) // len(scores),
'total_length': sum(r.length for r in player_records),
}
def get_all_stats(self) -> Dict[str, dict]:
"""Get statistics for all players."""
player_names = set(r.player_name for r in self.game_records)
return {name: self.get_player_stats(name) for name in player_names}
def get_leaderboard(self, limit: int = 10) -> List[tuple]:
"""Get top scores across all players."""
# Group by player and get their best score
player_best_scores = {}
for record in self.game_records:
if record.player_name not in player_best_scores:
player_best_scores[record.player_name] = record.score
else:
player_best_scores[record.player_name] = max(player_best_scores[record.player_name], record.score)
# Sort by score descending
sorted_scores = sorted(player_best_scores.items(), key=lambda x: x[1], reverse=True)
return sorted_scores[:limit]