chess_stats / utils /game_analysis.py
gael1130's picture
Upload 5 files
641009d verified
from collections import defaultdict
from datetime import datetime
from statistics import median
import pandas as pd
def calculate_probability(numerator, denominator):
"""Calculate percentage probability."""
return (numerator / denominator * 100) if denominator else 0
def analyze_streaks(games_sorted, username):
"""Analyze win/loss streaks within the same hour."""
win_after_win_same_hour = 0
loss_after_loss_same_hour = 0
total_win_streaks_same_hour = 0
total_loss_streaks_same_hour = 0
previous_result = None
previous_hour = None
for game in games_sorted:
end_time = game.get('end_time')
if not end_time:
continue
hour_of_day = datetime.fromtimestamp(end_time).hour
current_result = get_game_result(game, username)
if not current_result:
continue
if previous_result and previous_hour == hour_of_day:
if previous_result == 'win':
total_win_streaks_same_hour += 1
if current_result == 'win':
win_after_win_same_hour += 1
elif previous_result == 'loss':
total_loss_streaks_same_hour += 1
if current_result == 'loss':
loss_after_loss_same_hour += 1
previous_result = current_result
previous_hour = hour_of_day
print(f"Total win streaks: {total_win_streaks_same_hour}, Wins after win: {win_after_win_same_hour}")
print(f"Total loss streaks: {total_loss_streaks_same_hour}, Losses after loss: {loss_after_loss_same_hour}")
win_probability = calculate_probability(win_after_win_same_hour, total_win_streaks_same_hour)
loss_probability = calculate_probability(loss_after_loss_same_hour, total_loss_streaks_same_hour)
return win_probability, loss_probability
def analyze_sequences(games_sorted, username):
"""Analyze 'win-loss' and 'loss-win' sequences within the same hour."""
win_after_win_loss_same_hour = 0
win_after_loss_win_same_hour = 0
total_win_loss_sequences_same_hour = 0
total_loss_win_sequences_same_hour = 0
previous_result = None
previous_hour = None
for i, game in enumerate(games_sorted):
end_time = game.get('end_time')
if not end_time:
continue
hour_of_day = datetime.fromtimestamp(end_time).hour
current_result = get_game_result(game, username)
if not current_result:
continue
if previous_result and previous_hour == hour_of_day:
if previous_result == 'win' and current_result == 'loss':
total_win_loss_sequences_same_hour += 1
next_game_result = get_game_result(games_sorted[i + 1], username) if i + 1 < len(games_sorted) else None
if next_game_result == 'win':
win_after_win_loss_same_hour += 1
elif previous_result == 'loss' and current_result == 'win':
total_loss_win_sequences_same_hour += 1
next_game_result = get_game_result(games_sorted[i + 1], username) if i + 1 < len(games_sorted) else None
if next_game_result == 'win':
win_after_loss_win_same_hour += 1
previous_result = current_result
previous_hour = hour_of_day
print(f"Total 'win-loss' sequences: {total_win_loss_sequences_same_hour}, Wins after 'win-loss': {win_after_win_loss_same_hour}")
print(f"Total 'loss-win' sequences: {total_loss_win_sequences_same_hour}, Wins after 'loss-win': {win_after_loss_win_same_hour}")
win_after_win_loss_probability = calculate_probability(win_after_win_loss_same_hour, total_win_loss_sequences_same_hour)
win_after_loss_win_probability = calculate_probability(win_after_loss_win_same_hour, total_loss_win_sequences_same_hour)
return win_after_win_loss_probability, win_after_loss_win_probability
def analyze_games(games, username):
"""Analyze games by month and return statistics."""
games_per_month = defaultdict(int)
stats_per_month = defaultdict(lambda: defaultdict(int))
total_games = 0
total_wins = 0
total_losses = 0
total_timeouts = 0
for game in games:
end_time = game.get('end_time')
if not end_time:
continue
end_datetime = datetime.fromtimestamp(end_time)
month = end_datetime.strftime('%Y-%m')
result = get_game_result(game, username)
if result == 'win':
stats_per_month[month]['wins'] += 1
total_wins += 1
elif result == 'timeout':
stats_per_month[month]['timeouts'] += 1
total_timeouts += 1
stats_per_month[month]['losses'] += 1 # Count timeout as a loss
total_losses += 1
elif result == 'loss':
stats_per_month[month]['losses'] += 1
total_losses += 1
games_per_month[month] += 1
total_games += 1
total_months_played = len(games_per_month)
return games_per_month, stats_per_month, total_games, total_wins, total_losses, total_timeouts, total_months_played
def generate_monthly_report(games_per_month, stats_per_month):
"""Generate a Pandas DataFrame report for monthly analysis including Timeout Rate."""
data = []
for month, total_games in games_per_month.items():
wins = stats_per_month[month]['wins']
losses = stats_per_month[month]['losses']
timeouts = stats_per_month[month]['timeouts']
win_rate = (wins / total_games * 100) if total_games else 0
loss_rate = (losses / total_games * 100) if total_games else 0
timeout_rate = (timeouts / total_games * 100) if total_games else 0
data.append({
'Month': month,
'Games Played': total_games,
'Wins': wins,
'Losses': losses,
'Win Rate (%)': round(win_rate, 1),
'Loss Rate (%)': round(loss_rate, 1),
'Timeout Rate (%)': round(timeout_rate, 1)
})
return pd.DataFrame(data)
def get_game_result(game, username):
"""Determine if the user won or lost the game."""
result = None
if game.get('white', {}).get('username') == username:
result = game.get('white', {}).get('result')
elif game.get('black', {}).get('username') == username:
result = game.get('black', {}).get('result')
if result == 'win':
return 'win'
elif result == 'timeout':
return 'timeout' # Explicitly return "timeout"
elif result in ['checkmated', 'resigned', 'lose', 'abandoned']:
return 'loss'
return None
def calculate_average_and_median_games(games):
"""Calculate the average and median number of games played per day."""
games_per_day = defaultdict(int)
for game in games:
end_time = game.get('end_time')
if not end_time:
continue
end_date = datetime.fromtimestamp(end_time).date()
games_per_day[end_date] += 1
total_days = len(games_per_day)
total_games = sum(games_per_day.values())
average_games = total_games / total_days if total_days else 0
median_games = median(games_per_day.values()) if total_days else 0
return average_games, median_games
def format_duration(total_months):
"""Format the duration as 'X years, Y months'."""
years = total_months // 12
months = total_months % 12
if years > 0 and months > 0:
return f"{years} year(s), {months} month(s)"
elif years > 0:
return f"{years} year(s)"
else:
return f"{months} month(s)"