From: Steinar H. Gunderson Date: Sun, 6 Aug 2023 15:31:27 +0000 (+0200) Subject: Support filtering passes by thrower and receiver. X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;p=pkanalytics Support filtering passes by thrower and receiver. --- diff --git a/ultimate.js b/ultimate.js index ead0047..f556ee4 100644 --- a/ultimate.js +++ b/ultimate.js @@ -649,23 +649,23 @@ function calc_stats(json, filters) { // _not_ after an interception, or a self-pass that's not a goal. // (It must mean we tipped off someone.) We'll count it as a regular one // for the time being, although it will make hockey assists weird. - if (keep) { + if (keep) { // TODO: keep_pass()? ++p.goals; ++p.callahans; } handler = prev_handler = null; } else if (type === 'catch' || type === 'goal') { if (handler !== null) { - if (keep) { + if (keep && keep_pass(handler, e['player'], filters)) { ++players[handler].num_throws; ++p.catches; } } - if (keep) ++p.touches; + if (keep && keep_pass(handler, e['player'], filters)) ++p.touches; ++touches_this_possession; if (type === 'goal') { - if (keep) { + if (keep && keep_pass(handler, e['player'], filters)) { if (prev_handler !== null) { ++players[prev_handler].hockey_assists; } @@ -682,24 +682,24 @@ function calc_stats(json, filters) { handler_got_by_interception = false; } } else if (type === 'throwaway') { - if (keep) { + if (keep && keep_pass(e['player'], null, filters)) { ++p.num_throws; ++p.throwaways; } handler = prev_handler = null; } else if (type === 'drop') { - if (keep) ++p.drops; + if (keep && keep_pass(handler, e['player'], filters)) ++p.drops; handler = prev_handler = null; } else if (type === 'stallout') { if (keep) ++p.stallouts; handler = prev_handler = null; } else if (type === 'was_d') { - if (keep) ++p.was_ds; + if (keep && keep_pass(handler, e['player'], filters)) ++p.was_ds; handler = prev_handler = null; } else if (type === 'defense') { if (keep) ++p.defenses; } else if (type === 'interception') { - if (keep) { + if (keep && keep_pass(null, e['player'], filters)) { ++p.catches; ++p.defenses; ++p.touches; @@ -1555,10 +1555,12 @@ function open_filter_menu(click_to_add_div) { add_menu_item(filter_div, filterset, menu, 0, 'match', 'Match (any)'); add_menu_item(filter_div, filterset, menu, 1, 'player_any', 'Player on field (any)'); add_menu_item(filter_div, filterset, menu, 2, 'player_all', 'Player on field (all)'); - add_menu_item(filter_div, filterset, menu, 3, 'formation_offense', 'Offense played (any)'); - add_menu_item(filter_div, filterset, menu, 4, 'formation_defense', 'Defense played (any)'); - add_menu_item(filter_div, filterset, menu, 5, 'starting_on', 'Starting on'); - add_menu_item(filter_div, filterset, menu, 6, 'gender_ratio', 'Gender ratio'); + add_menu_item(filter_div, filterset, menu, 3, 'thrower', 'Thrower (any)'); + add_menu_item(filter_div, filterset, menu, 4, 'receiver', 'Receiver (any)'); + add_menu_item(filter_div, filterset, menu, 5, 'formation_offense', 'Offense played (any)'); + add_menu_item(filter_div, filterset, menu, 6, 'formation_defense', 'Defense played (any)'); + add_menu_item(filter_div, filterset, menu, 7, 'starting_on', 'Starting on'); + add_menu_item(filter_div, filterset, menu, 8, 'gender_ratio', 'Gender ratio'); } function add_menu_item(filter_div, filterset, menu, menu_idx, filter_type, title) { @@ -1630,7 +1632,7 @@ function show_submenu(filter_div, filterset, menu_idx, pill, filter_type) { 'id': match['match_id'] }); } - } else if (filter_type === 'player_any' || filter_type === 'player_all') { + } else if (filter_type === 'player_any' || filter_type === 'player_all' || filter_type === 'thrower' || filter_type === 'receiver') { for (const player of global_json['players']) { choices.push({ 'title': player['name'], @@ -1930,8 +1932,14 @@ function make_filter_pill(filter_div, filterset, filter) { if (common_prefix !== null) { text += ')'; } - } else if (filter.type === 'player_any') { - text = 'Player (any): '; + } else if (filter.type === 'player_any' || filter.type === 'thrower' || filter.type === 'receiver') { + if (filter.type === 'player_any') { + text = 'Player (any): '; + } else if (filter.type === 'thrower') { + text = 'Thrower (any): '; + } else { + text = 'Receiver (any): '; + } let sorted_players = Array.from(filter.elements).sort((a, b) => player_pos(a) - player_pos(b)); let first = true; for (const player_id of sorted_players) { @@ -2081,7 +2089,7 @@ function make_filter_marker(filterset) { text += desc.substr(common_prefix.length, 3); } } - } else if (filter.type === 'player_any' || filter.type === 'player_all') { + } else if (filter.type === 'player_any' || filter.type === 'player_all' || filter.type === 'thrower' || filter.type === 'receiver') { let sorted_players = Array.from(filter.elements).sort((a, b) => player_pos(a) - player_pos(b)); if (filter.elements.size >= 3 && entire_gender(filter.elements)) { text += find_player(sorted_players[0]).gender; @@ -2293,6 +2301,8 @@ function filter_passes(players, formations_used_this_point, last_pull_was_ours, } else if (filter.type === 'gender_ratio') { return filter.elements.has(find_gender_ratio_code(players)); } + // NOTE: thrower and receiver uses different state information and applies + // to throws only, so will be checked by keep_pass() instead. return true; } @@ -2305,6 +2315,25 @@ function keep_event(players, formations_used_this_point, last_pull_was_ours, fil return true; } +function pass_filter_passes(thrower, receiver, filter) { + if (filter.type === 'thrower') { + return filter.elements.has(thrower); + } else if (filter.type === 'receiver') { + return filter.elements.has(receiver); + } + // The others are tested in keep_event(). + return true; +} + +function keep_pass(thrower, receiver, filters) { + for (const filter of filters) { + if (!pass_filter_passes(thrower, receiver, filter)) { + return false; + } + } + return true; +} + // Heuristic: If we go at least ten seconds without the possession changing // or the operator specifying some other formation, we probably play the // same formation as the last point.