gael1130 commited on
Commit
641009d
·
verified ·
1 Parent(s): 74eb469

Upload 5 files

Browse files
utils/__init__.py ADDED
File without changes
utils/data_loader.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import requests
3
+ import os
4
+
5
+ HEADERS = {'User-Agent': 'My Python Application. Contact me at [email protected]'}
6
+
7
+ def fetch_and_save_chess_data(username, filename):
8
+ """Fetch chess games data from Chess.com API for a specified username and save to a JSON file."""
9
+ if os.path.exists(filename):
10
+ print(f"Loading data from {filename}")
11
+ with open(filename, 'r') as file:
12
+ return json.load(file)
13
+
14
+ archives_url = f"https://api.chess.com/pub/player/{username}/games/archives"
15
+ response = requests.get(archives_url, headers=HEADERS)
16
+
17
+ if response.status_code != 200:
18
+ print(f"Error fetching archives for user {username}: {response.status_code}")
19
+ return []
20
+
21
+ archives = response.json().get('archives', [])
22
+ games = []
23
+
24
+ # Fetch game data for each archive URL
25
+ for archive_url in archives:
26
+ response = requests.get(archive_url, headers=HEADERS)
27
+ if response.status_code == 200:
28
+ games.extend(response.json().get('games', []))
29
+ else:
30
+ print(f"Failed to fetch games for {archive_url}")
31
+
32
+ # Save the data to a JSON file
33
+ with open(filename, 'w') as file:
34
+ json.dump(games, file, indent=4)
35
+ print(f"Data saved to {filename}")
36
+
37
+ return games
utils/game_analysis.py ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from collections import defaultdict
2
+ from datetime import datetime
3
+ from statistics import median
4
+ import pandas as pd
5
+
6
+
7
+ def calculate_probability(numerator, denominator):
8
+ """Calculate percentage probability."""
9
+ return (numerator / denominator * 100) if denominator else 0
10
+
11
+ def analyze_streaks(games_sorted, username):
12
+ """Analyze win/loss streaks within the same hour."""
13
+ win_after_win_same_hour = 0
14
+ loss_after_loss_same_hour = 0
15
+ total_win_streaks_same_hour = 0
16
+ total_loss_streaks_same_hour = 0
17
+
18
+ previous_result = None
19
+ previous_hour = None
20
+
21
+ for game in games_sorted:
22
+ end_time = game.get('end_time')
23
+ if not end_time:
24
+ continue
25
+
26
+ hour_of_day = datetime.fromtimestamp(end_time).hour
27
+ current_result = get_game_result(game, username)
28
+
29
+ if not current_result:
30
+ continue
31
+
32
+ if previous_result and previous_hour == hour_of_day:
33
+ if previous_result == 'win':
34
+ total_win_streaks_same_hour += 1
35
+ if current_result == 'win':
36
+ win_after_win_same_hour += 1
37
+ elif previous_result == 'loss':
38
+ total_loss_streaks_same_hour += 1
39
+ if current_result == 'loss':
40
+ loss_after_loss_same_hour += 1
41
+
42
+ previous_result = current_result
43
+ previous_hour = hour_of_day
44
+
45
+ print(f"Total win streaks: {total_win_streaks_same_hour}, Wins after win: {win_after_win_same_hour}")
46
+ print(f"Total loss streaks: {total_loss_streaks_same_hour}, Losses after loss: {loss_after_loss_same_hour}")
47
+
48
+ win_probability = calculate_probability(win_after_win_same_hour, total_win_streaks_same_hour)
49
+ loss_probability = calculate_probability(loss_after_loss_same_hour, total_loss_streaks_same_hour)
50
+
51
+ return win_probability, loss_probability
52
+
53
+ def analyze_sequences(games_sorted, username):
54
+ """Analyze 'win-loss' and 'loss-win' sequences within the same hour."""
55
+ win_after_win_loss_same_hour = 0
56
+ win_after_loss_win_same_hour = 0
57
+ total_win_loss_sequences_same_hour = 0
58
+ total_loss_win_sequences_same_hour = 0
59
+
60
+ previous_result = None
61
+ previous_hour = None
62
+
63
+ for i, game in enumerate(games_sorted):
64
+ end_time = game.get('end_time')
65
+ if not end_time:
66
+ continue
67
+
68
+ hour_of_day = datetime.fromtimestamp(end_time).hour
69
+ current_result = get_game_result(game, username)
70
+
71
+ if not current_result:
72
+ continue
73
+
74
+ if previous_result and previous_hour == hour_of_day:
75
+ if previous_result == 'win' and current_result == 'loss':
76
+ total_win_loss_sequences_same_hour += 1
77
+ next_game_result = get_game_result(games_sorted[i + 1], username) if i + 1 < len(games_sorted) else None
78
+ if next_game_result == 'win':
79
+ win_after_win_loss_same_hour += 1
80
+ elif previous_result == 'loss' and current_result == 'win':
81
+ total_loss_win_sequences_same_hour += 1
82
+ next_game_result = get_game_result(games_sorted[i + 1], username) if i + 1 < len(games_sorted) else None
83
+ if next_game_result == 'win':
84
+ win_after_loss_win_same_hour += 1
85
+
86
+ previous_result = current_result
87
+ previous_hour = hour_of_day
88
+
89
+ print(f"Total 'win-loss' sequences: {total_win_loss_sequences_same_hour}, Wins after 'win-loss': {win_after_win_loss_same_hour}")
90
+ print(f"Total 'loss-win' sequences: {total_loss_win_sequences_same_hour}, Wins after 'loss-win': {win_after_loss_win_same_hour}")
91
+
92
+ win_after_win_loss_probability = calculate_probability(win_after_win_loss_same_hour, total_win_loss_sequences_same_hour)
93
+ win_after_loss_win_probability = calculate_probability(win_after_loss_win_same_hour, total_loss_win_sequences_same_hour)
94
+
95
+ return win_after_win_loss_probability, win_after_loss_win_probability
96
+
97
+ def analyze_games(games, username):
98
+ """Analyze games by month and return statistics."""
99
+
100
+ games_per_month = defaultdict(int)
101
+ stats_per_month = defaultdict(lambda: defaultdict(int))
102
+ total_games = 0
103
+ total_wins = 0
104
+ total_losses = 0
105
+ total_timeouts = 0
106
+
107
+ for game in games:
108
+ end_time = game.get('end_time')
109
+ if not end_time:
110
+ continue
111
+
112
+ end_datetime = datetime.fromtimestamp(end_time)
113
+ month = end_datetime.strftime('%Y-%m')
114
+ result = get_game_result(game, username)
115
+
116
+ if result == 'win':
117
+ stats_per_month[month]['wins'] += 1
118
+ total_wins += 1
119
+ elif result == 'timeout':
120
+ stats_per_month[month]['timeouts'] += 1
121
+ total_timeouts += 1
122
+ stats_per_month[month]['losses'] += 1 # Count timeout as a loss
123
+ total_losses += 1
124
+ elif result == 'loss':
125
+ stats_per_month[month]['losses'] += 1
126
+ total_losses += 1
127
+
128
+ games_per_month[month] += 1
129
+ total_games += 1
130
+
131
+ total_months_played = len(games_per_month)
132
+
133
+ return games_per_month, stats_per_month, total_games, total_wins, total_losses, total_timeouts, total_months_played
134
+
135
+ def generate_monthly_report(games_per_month, stats_per_month):
136
+ """Generate a Pandas DataFrame report for monthly analysis including Timeout Rate."""
137
+ data = []
138
+ for month, total_games in games_per_month.items():
139
+ wins = stats_per_month[month]['wins']
140
+ losses = stats_per_month[month]['losses']
141
+ timeouts = stats_per_month[month]['timeouts']
142
+ win_rate = (wins / total_games * 100) if total_games else 0
143
+ loss_rate = (losses / total_games * 100) if total_games else 0
144
+ timeout_rate = (timeouts / total_games * 100) if total_games else 0
145
+
146
+ data.append({
147
+ 'Month': month,
148
+ 'Games Played': total_games,
149
+ 'Wins': wins,
150
+ 'Losses': losses,
151
+ 'Win Rate (%)': round(win_rate, 1),
152
+ 'Loss Rate (%)': round(loss_rate, 1),
153
+ 'Timeout Rate (%)': round(timeout_rate, 1)
154
+ })
155
+
156
+ return pd.DataFrame(data)
157
+
158
+ def get_game_result(game, username):
159
+ """Determine if the user won or lost the game."""
160
+ result = None
161
+ if game.get('white', {}).get('username') == username:
162
+ result = game.get('white', {}).get('result')
163
+ elif game.get('black', {}).get('username') == username:
164
+ result = game.get('black', {}).get('result')
165
+
166
+ if result == 'win':
167
+ return 'win'
168
+ elif result == 'timeout':
169
+ return 'timeout' # Explicitly return "timeout"
170
+ elif result in ['checkmated', 'resigned', 'lose', 'abandoned']:
171
+ return 'loss'
172
+ return None
173
+
174
+
175
+ def calculate_average_and_median_games(games):
176
+ """Calculate the average and median number of games played per day."""
177
+ games_per_day = defaultdict(int)
178
+
179
+ for game in games:
180
+ end_time = game.get('end_time')
181
+ if not end_time:
182
+ continue
183
+
184
+ end_date = datetime.fromtimestamp(end_time).date()
185
+ games_per_day[end_date] += 1
186
+
187
+ total_days = len(games_per_day)
188
+ total_games = sum(games_per_day.values())
189
+ average_games = total_games / total_days if total_days else 0
190
+ median_games = median(games_per_day.values()) if total_days else 0
191
+
192
+ return average_games, median_games
193
+
194
+
195
+ def format_duration(total_months):
196
+ """Format the duration as 'X years, Y months'."""
197
+ years = total_months // 12
198
+ months = total_months % 12
199
+ if years > 0 and months > 0:
200
+ return f"{years} year(s), {months} month(s)"
201
+ elif years > 0:
202
+ return f"{years} year(s)"
203
+ else:
204
+ return f"{months} month(s)"
utils/probability_analysis.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from collections import defaultdict
2
+
3
+ def calculate_win_probability(games_sorted, username):
4
+ """Calculate win probability based on game position in a day."""
5
+ wins_by_position = defaultdict(int)
6
+ games_by_position = defaultdict(int)
7
+ current_day = None
8
+ game_position = 1
9
+
10
+ for game in games_sorted:
11
+ end_time = game.get('end_time')
12
+ if not end_time:
13
+ continue
14
+
15
+ result = get_game_result(game, username)
16
+
17
+ if result == 'win':
18
+ wins_by_position[game_position] += 1
19
+ games_by_position[game_position] += 1
20
+
21
+ game_position += 1
22
+
23
+ probabilities = {pos: (wins / games_by_position[pos] * 100) for pos, wins in wins_by_position.items()}
24
+ return probabilities
utils/tilt_detector.py ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from datetime import datetime
2
+
3
+ def detect_tilt_streaks(games, username, tilt_streak_count=6, tilt_time_gap=10800):
4
+ """Detect tilt streaks based on consecutive losses."""
5
+ games_sorted = sorted(games, key=lambda x: x.get('end_time'))
6
+ tilt_occurrences = []
7
+ current_streak = 0
8
+ streak_start_time = None
9
+
10
+ for game in games_sorted:
11
+ end_time = game.get('end_time')
12
+ if not end_time:
13
+ continue
14
+
15
+ end_datetime = datetime.fromtimestamp(end_time)
16
+ result = get_game_result(game, username)
17
+
18
+ if result in ['checkmated', 'timeout', 'resigned', 'lose', 'abandoned']:
19
+ if current_streak == 0:
20
+ streak_start_time = end_datetime
21
+ current_streak += 1
22
+
23
+ if current_streak >= tilt_streak_count:
24
+ tilt_occurrences.append({
25
+ "start_time": streak_start_time,
26
+ "end_time": end_datetime,
27
+ "streak_length": current_streak
28
+ })
29
+ current_streak = 0
30
+ else:
31
+ current_streak = 0
32
+
33
+ return tilt_occurrences