]> git.sesse.net Git - pkanalytics/commitdiff
Implement filter-by-player-on-field.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 28 May 2023 20:53:22 +0000 (22:53 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 28 May 2023 21:10:17 +0000 (23:10 +0200)
ultimate.js

index 0c44658adcdd30a1b99ca2b45b696e5c2600aa12..40461d860a94abafd406452610b5e7ee61e74bb6 100644 (file)
@@ -27,14 +27,16 @@ function attribute_player_time(player, to, from, offense) {
        }
 }
 
-function take_off_field(player, t, live_since, offense) {
-       if (live_since === null) {
-               // Play isn't live, so nothing to do.
-       } else {
-               attribute_player_time(player, t, live_since, offense);
-       }
-       if (player.on_field_since !== null) {  // Just a safeguard; out without in should never happen.
-               player.field_time_ms += t - player.on_field_since;
+function take_off_field(player, t, live_since, offense, keep) {
+       if (keep) {
+               if (live_since === null) {
+                       // Play isn't live, so nothing to do.
+               } else {
+                       attribute_player_time(player, t, live_since, offense);
+               }
+               if (player.on_field_since !== null) {  // Just a safeguard; out without in should never happen.
+                       player.field_time_ms += t - player.on_field_since;
+               }
        }
        player.on_field_since = null;
 }
@@ -229,19 +231,43 @@ function process_matches(json, filters) {
                        p.last_point_seen = null;
                }
                for (const e of match['events']) {
-                       // TODO: filter events
-
                        let t = e['t'];
                        let type = e['type'];
                        let p = players[e['player']];
 
                        // Sub management
+                       let keep = keep_event(players, filters);
                        if (type === 'in' && p.on_field_since === null) {
                                p.on_field_since = t;
+                               if (!keep && keep_event(players, filters)) {
+                                       // A player needed for the filters went onto the field,
+                                       // so pretend people walked on right now (to start their
+                                       // counting time).
+                                       for (const [q,p2] of Object.entries(players)) {
+                                               if (p2.on_field_since !== null) {
+                                                       p2.on_field_since = t;
+                                               }
+                                       }
+                               }
                        } else if (type === 'out') {
-                               take_off_field(p, t, live_since, offense);
+                               take_off_field(p, t, live_since, offense, keep);
+                               if (keep && !keep_event(players, filters)) {
+                                       // A player needed for the filters went off the field,
+                                       // so we need to attribute time for all the others.
+                                       // Pretend they walked off and then immediately on again.
+                                       //
+                                       // TODO: We also need to take care of this to get the globals right.
+                                       for (const [q,p2] of Object.entries(players)) {
+                                               if (p2.on_field_since !== null) {
+                                                       take_off_field(p2, t, live_since, offense, keep);
+                                                       p2.on_field_since = t;
+                                               }
+                                       }
+                               }
                        }
 
+                       keep = keep_event(players, filters);  // Recompute after in/out.
+
                        // Liveness management
                        if (type === 'pull' || type === 'their_pull' || type === 'restart') {
                                live_since = t;
@@ -256,51 +282,57 @@ function process_matches(json, filters) {
                                                continue;
                                        }
                                        if (type !== 'stoppage' && p.last_point_seen !== point_num) {
-                                               // In case the player did nothing this point,
-                                               // not even subbing in.
-                                               p.last_point_seen = point_num;
-                                               ++p.points_played;
+                                               if (keep) {
+                                                       // In case the player did nothing this point,
+                                                       // not even subbing in.
+                                                       p.last_point_seen = point_num;
+                                                       ++p.points_played;
+                                               }
+                                       }
+                                       if (keep) attribute_player_time(p, t, live_since, offense);
+
+                                       if (type !== 'stoppage') {
+                                               if (keep) {
+                                                       if (last_pull_was_ours === true) {  // D point.
+                                                               ++p.defensive_points_completed;
+                                                               if (type === 'goal') {
+                                                                       ++p.defensive_points_won;
+                                                               }
+                                                       } else if (last_pull_was_ours === false) {  // O point.
+                                                               ++p.offensive_points_completed;
+                                                               if (type === 'goal') {
+                                                                       ++p.offensive_points_won;
+                                                               }
+                                                       }
+                                               }
                                        }
-                                       attribute_player_time(p, t, live_since, offense);
+                               }
 
+                               if (keep) {
                                        if (type !== 'stoppage') {
+                                               // Update globals.
+                                               ++globals.points_played;
                                                if (last_pull_was_ours === true) {  // D point.
-                                                       ++p.defensive_points_completed;
+                                                       ++globals.defensive_points_completed;
                                                        if (type === 'goal') {
-                                                               ++p.defensive_points_won;
+                                                               ++globals.defensive_points_won;
                                                        }
                                                } else if (last_pull_was_ours === false) {  // O point.
-                                                       ++p.offensive_points_completed;
+                                                       ++globals.offensive_points_completed;
                                                        if (type === 'goal') {
-                                                               ++p.offensive_points_won;
+                                                               ++globals.offensive_points_won;
                                                        }
                                                }
                                        }
-                               }
-
-                               if (type !== 'stoppage') {
-                                       // Update globals.
-                                       ++globals.points_played;
-                                       if (last_pull_was_ours === true) {  // D point.
-                                               ++globals.defensive_points_completed;
-                                               if (type === 'goal') {
-                                                       ++globals.defensive_points_won;
-                                               }
-                                       } else if (last_pull_was_ours === false) {  // O point.
-                                               ++globals.offensive_points_completed;
-                                               if (type === 'goal') {
-                                                       ++globals.offensive_points_won;
+                                       if (live_since !== null) {
+                                               globals.playing_time_ms += t - live_since;
+                                               if (offense === true) {
+                                                       globals.offensive_playing_time_ms += t - live_since;
+                                               } else if (offense === false) {
+                                                       globals.defensive_playing_time_ms += t - live_since;
                                                }
                                        }
                                }
-                               if (live_since !== null) {
-                                       globals.playing_time_ms += t - live_since;
-                                       if (offense === true) {
-                                               globals.offensive_playing_time_ms += t - live_since;
-                                       } else if (offense === false) {
-                                               globals.defensive_playing_time_ms += t - live_since;
-                                       }
-                               }
 
                                live_since = null;
                        }
@@ -314,8 +346,10 @@ function process_matches(json, filters) {
 
                        // Point count management
                        if (p !== undefined && type !== 'out' && p.last_point_seen !== point_num) {
-                               p.last_point_seen = point_num;
-                               ++p.points_played;
+                               if (keep) {
+                                       p.last_point_seen = point_num;
+                                       ++p.points_played;
+                               }
                        }
                        if (type === 'goal' || type === 'their_goal') {
                                ++point_num;
@@ -329,13 +363,13 @@ function process_matches(json, filters) {
                        if (type === 'pull') {
                                puller = e['player'];
                                pull_started = t;
-                               ++p.pulls;
+                               if (keep) ++p.pulls;
                        } else if (type === 'in' || type === 'out' || type === 'stoppage' || type === 'restart' || type === 'unknown' || type === 'set_defense' || type === 'set_offense') {
                                // No effect on pull.
                        } else if (type === 'pull_landed' && puller !== null) {
-                               players[puller].pull_times.push(t - pull_started);
+                               if (keep) players[puller].pull_times.push(t - pull_started);
                        } else if (type === 'pull_oob' && puller !== null) {
-                               ++players[puller].oob_pulls;
+                               if (keep) ++players[puller].oob_pulls;
                        } else {
                                // Not pulling (if there was one, we never recorded its outcome, but still count it).
                                puller = pull_started = null;
@@ -351,17 +385,19 @@ function process_matches(json, filters) {
                        if (last_offense !== offense && live_since !== null) {
                                // Switched offense/defense status, so attribute this drive as needed,
                                // and update live_since to take that into account.
-                               for (const [q,p] of Object.entries(players)) {
-                                       if (p.on_field_since === null) {
-                                               continue;
+                               if (keep) {
+                                       for (const [q,p] of Object.entries(players)) {
+                                               if (p.on_field_since === null) {
+                                                       continue;
+                                               }
+                                               attribute_player_time(p, t, live_since, last_offense);
+                                       }
+                                       globals.playing_time_ms += t - live_since;
+                                       if (offense === true) {
+                                               globals.offensive_playing_time_ms += t - live_since;
+                                       } else if (offense === false) {
+                                               globals.defensive_playing_time_ms += t - live_since;
                                        }
-                                       attribute_player_time(p, t, live_since, last_offense);
-                               }
-                               globals.playing_time_ms += t - live_since;
-                               if (offense === true) {
-                                       globals.offensive_playing_time_ms += t - live_since;
-                               } else if (offense === false) {
-                                       globals.defensive_playing_time_ms += t - live_since;
                                }
                                live_since = t;
                        }
@@ -389,19 +425,23 @@ function process_matches(json, filters) {
                        // Event management
                        if (type === 'catch' || type === 'goal') {
                                if (handler !== null) {
-                                       ++players[handler].num_throws;
-                                       ++p.catches;
+                                       if (keep) {
+                                               ++players[handler].num_throws;
+                                               ++p.catches;
+                                       }
                                }
 
-                               ++p.touches;
+                               if (keep) ++p.touches;
                                if (type === 'goal') {
-                                       if (prev_handler !== null) {
-                                               ++players[prev_handler].hockey_assists;
-                                       }
-                                       if (handler !== null) {
-                                               ++players[handler].assists;
+                                       if (keep) {
+                                               if (prev_handler !== null) {
+                                                       ++players[prev_handler].hockey_assists;
+                                               }
+                                               if (handler !== null) {
+                                                       ++players[handler].assists;
+                                               }
+                                               ++p.goals;
                                        }
-                                       ++p.goals;
                                        handler = prev_handler = null;
                                } else {
                                        // Update hold history.
@@ -409,22 +449,26 @@ function process_matches(json, filters) {
                                        handler = e['player'];
                                }
                        } else if (type === 'throwaway') {
-                               ++p.num_throws;
-                               ++p.throwaways;
+                               if (keep) {
+                                       ++p.num_throws;
+                                       ++p.throwaways;
+                               }
                                handler = prev_handler = null;
                        } else if (type === 'drop') {
-                               ++p.drops;
+                               if (keep) ++p.drops;
                                handler = prev_handler = null;
                        } else if (type === 'defense') {
-                               ++p.defenses;
+                               if (keep) ++p.defenses;
                        } else if (type === 'interception') {
-                               ++p.interceptions;
-                               ++p.defenses;
-                               ++p.touches;
+                               if (keep) {
+                                       ++p.interceptions;
+                                       ++p.defenses;
+                                       ++p.touches;
+                               }
                                prev_handler = null;
                                handler = e['player'];
                        } else if (type === 'offensive_soft_plus' || type === 'offensive_soft_minus' || type === 'defensive_soft_plus' || type === 'defensive_soft_minus') {
-                               ++p[type];
+                               if (keep) ++p[type];
                        } else if (type !== 'in' && type !== 'out' && type !== 'pull' &&
                                   type !== 'their_goal' && type !== 'stoppage' && type !== 'restart' && type !== 'unknown' &&
                                   type !== 'set_defense' && type !== 'goal' && type !== 'throwaway' &&
@@ -436,20 +480,23 @@ function process_matches(json, filters) {
                }
 
                // Add field time for all players still left at match end.
-               for (const [q,p] of Object.entries(players)) {
-                       if (p.on_field_since !== null && last_goal !== null) {
-                               p.field_time_ms += last_goal - p.on_field_since;
+               const keep = keep_event(players, filters);
+               if (keep) {
+                       for (const [q,p] of Object.entries(players)) {
+                               if (p.on_field_since !== null && last_goal !== null) {
+                                       p.field_time_ms += last_goal - p.on_field_since;
+                               }
                        }
-               }
-               if (game_started !== null && last_goal !== null) {
-                       globals.field_time_ms += last_goal - game_started;
-               }
-               if (live_since !== null && last_goal !== null) {
-                       globals.playing_time_ms += last_goal - live_since;
-                       if (offense === true) {
-                               globals.offensive_playing_time_ms += last_goal - live_since;
-                       } else if (offense === false) {
-                               globals.defensive_playing_time_ms += last_goal - live_since;
+                       if (game_started !== null && last_goal !== null) {
+                               globals.field_time_ms += last_goal - game_started;
+                       }
+                       if (live_since !== null && last_goal !== null) {
+                               globals.playing_time_ms += last_goal - live_since;
+                               if (offense === true) {
+                                       globals.offensive_playing_time_ms += last_goal - live_since;
+                               } else if (offense === false) {
+                                       globals.defensive_playing_time_ms += last_goal - live_since;
+                               }
                        }
                }
        }
@@ -1192,6 +1239,27 @@ function keep_match(match_id, filters) {
        return true;
 }
 
+function keep_event(players, filters) {
+       for (const filter of filters) {
+               if (filter.type === 'player_any') {
+                       for (const p of Array.from(filter.elements)) {
+                               if (players[p].on_field_since !== null) {
+                                       return true;
+                               }
+                       }
+                       return false;
+               } else if (filter.type === 'player_all') {
+                       for (const p of Array.from(filter.elements)) {
+                               if (players[p].on_field_since === null) {
+                                       return false;
+                               }
+                       }
+                       return true;
+               }
+       }
+       return true;
+}
+
 function possibly_close_menu(e) {
        if (e.target.closest('#filter-click-to-add') === null &&
            e.target.closest('#filter-add-menu') === null &&