Skip to content

Commit 5a9247c

Browse files
committed
feat: implement champion pool feature
1 parent fe32024 commit 5a9247c

1 file changed

Lines changed: 141 additions & 1 deletion

File tree

app/services/players/roster_management_service.rb

Lines changed: 141 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,13 @@ def create_scouting_target_from_player(previous_org_name:, removal_reason:)
117117
target = ScoutingTarget.find_or_initialize_by(riot_puuid: player.riot_puuid) if player.riot_puuid.present?
118118
target ||= ScoutingTarget.new
119119

120+
# Calculate performance data
121+
recent_perf = calculate_recent_performance(player)
122+
champion_stats = calculate_champion_stats(player)
123+
124+
# Merge champion stats into recent performance
125+
recent_perf[:champion_stats] = champion_stats
126+
120127
# Update global player data
121128
target.assign_attributes(
122129
summoner_name: player.summoner_name,
@@ -126,7 +133,9 @@ def create_scouting_target_from_player(previous_org_name:, removal_reason:)
126133
current_tier: player.solo_queue_tier,
127134
current_rank: player.solo_queue_rank,
128135
current_lp: player.solo_queue_lp,
129-
champion_pool: player.champion_pool,
136+
champion_pool: calculate_champion_pool_from_stats(player),
137+
recent_performance: recent_perf,
138+
performance_trend: calculate_performance_trend(player),
130139
playstyle: extract_playstyle_from_notes(player.notes),
131140
twitter_handle: player.twitter_handle,
132141
status: 'free_agent',
@@ -160,6 +169,137 @@ def build_free_agent_notes(previous_org_name, removal_reason, existing_notes = n
160169
notes.join("\n\n")
161170
end
162171

172+
# Calculate champion pool from player's actual match statistics
173+
# Prioritizes champions from champion_pools table, falls back to player_match_stats
174+
# @param player [Player] The player to calculate champion pool for
175+
# @return [Array<String>] Array of champion names (up to 10)
176+
def calculate_champion_pool_from_stats(player)
177+
# First, try to get from champion_pools table (most reliable)
178+
champions_from_pool = player.champion_pools
179+
.order(games_played: :desc, average_kda: :desc)
180+
.limit(10)
181+
.pluck(:champion)
182+
183+
return champions_from_pool if champions_from_pool.any?
184+
185+
# Fallback: get from player_match_stats
186+
champions_from_stats = player.player_match_stats
187+
.group(:champion)
188+
.order('COUNT(*) DESC')
189+
.limit(10)
190+
.pluck(:champion)
191+
192+
return champions_from_stats if champions_from_stats.any?
193+
194+
# Last resort: use the champion_pool array attribute if it exists
195+
player.champion_pool.presence || []
196+
end
197+
198+
# Calculate champion statistics with winrate per champion
199+
# @param player [Player] The player to calculate champion stats for
200+
# @param limit [Integer] Number of recent games to analyze (default: 50)
201+
# @return [Array<Hash>] Array of champion stats with name, games, wins, winrate
202+
def calculate_champion_stats(player, limit: 50)
203+
recent_stats = player.player_match_stats
204+
.joins(:match)
205+
.order('matches.game_start DESC')
206+
.limit(limit)
207+
208+
return [] if recent_stats.empty?
209+
210+
# Group by champion
211+
champion_data = recent_stats.group_by(&:champion)
212+
213+
champion_data.map do |champion, stats|
214+
games = stats.count
215+
wins = stats.count { |s| s.match&.victory? }
216+
win_rate = games.zero? ? 0.0 : ((wins.to_f / games) * 100).round(1)
217+
218+
{
219+
champion: champion,
220+
games: games,
221+
wins: wins,
222+
win_rate: win_rate
223+
}
224+
end.sort_by { |c| -c[:games] }.take(10) # Top 10 most played
225+
end
226+
227+
# Calculate recent performance statistics from last 50 games
228+
# @param player [Player] The player to calculate performance for
229+
# @param limit [Integer] Number of recent games to analyze (default: 50)
230+
# @return [Hash] Performance statistics
231+
def calculate_recent_performance(player, limit: 50)
232+
recent_stats = player.player_match_stats
233+
.joins(:match)
234+
.order('matches.game_start DESC')
235+
.limit(limit)
236+
237+
return {} if recent_stats.empty?
238+
239+
total_games = recent_stats.count
240+
wins = recent_stats.count { |stat| stat.match&.victory? }
241+
242+
# Calculate KDA manually since it's a virtual method
243+
total_kills = recent_stats.sum(:kills)
244+
total_deaths = recent_stats.sum(:deaths)
245+
total_assists = recent_stats.sum(:assists)
246+
avg_kda = total_deaths.zero? ? total_kills + total_assists : ((total_kills + total_assists).to_f / total_deaths).round(2)
247+
248+
# Calculate averages only for non-null values
249+
damage_shares = recent_stats.pluck(:damage_share).compact
250+
kill_participations = recent_stats.pluck(:kill_participation).compact
251+
252+
{
253+
games_played: total_games,
254+
wins: wins,
255+
losses: total_games - wins,
256+
win_rate: total_games.zero? ? 0.0 : ((wins.to_f / total_games) * 100).round(1),
257+
avg_kda: avg_kda,
258+
avg_cs_per_min: recent_stats.average(:cs_per_min)&.to_f&.round(1) || 0.0,
259+
avg_vision_score: recent_stats.average(:vision_score)&.to_f&.round(1) || 0.0,
260+
avg_damage_share: damage_shares.any? ? (damage_shares.sum / damage_shares.size).round(1) : 0.0,
261+
avg_kill_participation: kill_participations.any? ? (kill_participations.sum / kill_participations.size).round(1) : 0.0,
262+
last_game_date: recent_stats.first&.match&.game_start&.to_date
263+
}
264+
end
265+
266+
# Calculate performance trend based on recent games
267+
# @param player [Player] The player to calculate trend for
268+
# @param limit [Integer] Number of recent games to analyze (default: 50)
269+
# @return [String] 'improving', 'stable', or 'declining'
270+
def calculate_performance_trend(player, limit: 50)
271+
recent_stats = player.player_match_stats
272+
.joins(:match)
273+
.order('matches.game_start DESC')
274+
.limit(limit)
275+
276+
return 'stable' if recent_stats.count < 20
277+
278+
# Split into two halves
279+
mid_point = recent_stats.count / 2
280+
recent_half = recent_stats.first(mid_point)
281+
older_half = recent_stats.last(mid_point)
282+
283+
recent_wr = calculate_win_rate(recent_half)
284+
older_wr = calculate_win_rate(older_half)
285+
286+
if recent_wr > older_wr + 10
287+
'improving'
288+
elsif recent_wr < older_wr - 10
289+
'declining'
290+
else
291+
'stable'
292+
end
293+
end
294+
295+
# Helper to calculate win rate from a collection of stats
296+
def calculate_win_rate(stats)
297+
return 0 if stats.empty?
298+
299+
wins = stats.count { |stat| stat.match&.victory? }
300+
(wins.to_f / stats.count * 100).round(1)
301+
end
302+
163303
# Extract playstyle from player notes
164304
def extract_playstyle_from_notes(notes)
165305
return nil if notes.blank?

0 commit comments

Comments
 (0)