From db63793cbaba047c6cd5b7cd00f6e76c5a6fb907 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Thu, 27 Jul 2023 10:21:07 +0200 Subject: [PATCH] Start working on some team-wide stats. --- ultimate.js | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 3 deletions(-) diff --git a/ultimate.js b/ultimate.js index 27a79b9..b5bc214 100644 --- a/ultimate.js +++ b/ultimate.js @@ -229,8 +229,16 @@ function calc_stats(json, filters) { 'offensive_points_completed': 0, 'offensive_points_won': 0, + 'clean_holds': 0, + 'defensive_points_completed': 0, 'defensive_points_won': 0, + 'clean_breaks': 0, + + 'turnovers_won': 0, + 'turnovers_lost': 0, + 'their_clean_holds': 0, + 'their_clean_breaks': 0, }; let globals = players['globals']; @@ -256,6 +264,9 @@ function calc_stats(json, filters) { let current_predominant_gender = null; let current_num_players_on_field = null; + let we_lost_disc = false; + let they_lost_disc = false; + // The last used formations of the given kind, if any; they may be reused // when the point starts, if nothing else is set. let last_offensive_formation = null; @@ -426,10 +437,8 @@ function calc_stats(json, filters) { // Score management if (type === 'goal') { ++our_score; - between_points = true; } else if (type === 'their_goal') { ++their_score; - between_points = true; } // Point count management @@ -463,12 +472,42 @@ function calc_stats(json, filters) { puller = pull_started = null; } + // Stats for clean holds or not (must be done before resetting we_lost_disc etc. below). + if (keep) { + if (type === 'goal' && !we_lost_disc) { + if (last_pull_was_ours === false) { // O point. + ++globals.clean_holds; + } else if (last_pull_was_ours === true) { + ++globals.clean_breaks; + } + } else if (type === 'their_goal' && !they_lost_disc) { + if (last_pull_was_ours === true) { // O point for them. + ++globals.their_clean_holds; + } else if (last_pull_was_ours === false) { + ++globals.their_clean_breaks; + } + } + } + // Offense/defense management let last_offense = offense; if (type === 'set_defense' || type === 'goal' || type === 'throwaway' || type === 'drop' || type === 'was_d' || type === 'stallout') { offense = false; + we_lost_disc = true; + if (keep && type !== 'goal' && !(type === 'set_defense' && last_pull_was_ours === null)) { + ++globals.turnovers_lost; + } } else if (type === 'set_offense' || type === 'their_goal' || type === 'their_throwaway' || type === 'defense' || type === 'interception') { offense = true; + they_lost_disc = true; + if (keep && type !== 'their_goal' && !(type === 'set_offense' && last_pull_was_ours === null)) { + ++globals.turnovers_won; + } + } + if (type === 'goal' || type === 'their_goal') { + between_points = true; + we_lost_disc = false; + they_lost_disc = false; } if (last_offense !== offense && live_since !== null) { // Switched offense/defense status, so attribute this drive as needed, @@ -684,6 +723,8 @@ function process_matches(json, filtersets) { rows = make_table_playing_time(players); } else if (chosen_category === 'per_point') { rows = make_table_per_point(players); + } else if (chosen_category === 'team_wide') { + rows = make_table_team_wide(players); } rowsets.push(rows); } @@ -743,6 +784,8 @@ function get_chosen_category() { return 'playing_time'; } else if (window.location.hash === '#per_point') { return 'per_point'; + } else if (window.location.hash === '#team_wide') { + return 'team_wide'; } else { return 'general'; } @@ -755,7 +798,8 @@ function write_main_menu(chosen_category) { ['offense', 'Offense'], ['defense', 'Defense'], ['playing_time', 'Playing time'], - ['per_point', 'Per point'] + ['per_point', 'Per point'], + ['team_wide', 'Team-wide'], ]; for (const [id, title] of categories) { if (chosen_category === id) { @@ -884,6 +928,56 @@ function make_table_general(players) { return rows; } +function make_table_team_wide(players) { + let globals = players['globals']; + + let rows = []; + { + let header = document.createElement('tr'); + add_th(header, ''); + add_th(header, 'Our team'); + add_th(header, 'Their team'); + rows.push(header); + } + + // Turnovers. + { + let row = document.createElement('tr'); + let name = add_3cell(row, 'Turnovers generated', 'name'); + add_3cell(row, globals.turnovers_won); + add_3cell(row, globals.turnovers_lost); + rows.push(row); + } + + // Clean holds. + { + let row = document.createElement('tr'); + let name = add_3cell(row, 'Clean holds', 'name'); + let our_clean_holds = make_binomial_ci(globals.clean_holds, globals.offensive_points_completed, z); + let their_clean_holds = make_binomial_ci(globals.their_clean_holds, globals.defensive_points_completed, z); + our_clean_holds.desired = 0.3; // Arbitrary. + their_clean_holds.desired = 0.3; + add_3cell_ci(row, our_clean_holds); + add_3cell_ci(row, their_clean_holds); + rows.push(row); + } + + // Clean breaks. + { + let row = document.createElement('tr'); + let name = add_3cell(row, 'Clean breaks', 'name'); + let our_clean_breaks = make_binomial_ci(globals.clean_breaks, globals.defensive_points_completed, z); + let their_clean_breaks = make_binomial_ci(globals.their_clean_breaks, globals.offensive_points_completed, z); + our_clean_breaks.desired = 0.3; // Arbitrary. + their_clean_breaks.desired = 0.3; + add_3cell_ci(row, our_clean_breaks); + add_3cell_ci(row, their_clean_breaks); + rows.push(row); + } + + return rows; +} + function make_table_offense(players) { let rows = []; { -- 2.39.2