public void CalculateAveragePenaltyCosts() { // pull data SqlConnection connection = new SqlConnection(_connectionString); connection.Open(); SqlTransaction transaction = connection.BeginTransaction(); var jamData = _jamTeamData .GroupBy(jd => jd.JamID) .ToDictionary( g => g.Key, g => g.ToDictionary(g2 => g2.TeamID, g2 => g2) ); var jamPlayerMap = _jamPlayers .GroupBy(jp => jp.JamID) .ToDictionary( g => g.Key, g => g.ToDictionary(g2 => g2.PlayerID, g2 => g2) ); Dictionary <FoulComparison, Dictionary <int, float> > sss = new SituationalScoreGateway(connection, transaction).GetAllSituationalScores(); var penaltyGroupCost = PenaltyCostCalculator.CalculatePointCosts(jamData, jamPlayerMap, _penaltyGroups, _boxTimeEstimates, sss); var jteMap = _jamTeamEffectiveness.GroupBy(jte => jte.JamID).ToDictionary(g => g.Key, g => g.ToDictionary(g2 => g2.TeamID, g2 => g2.Percentile)); var penaltyGroupValueCost = PenaltyCostCalculator.CalculateValueCosts(jamData, jamPlayerMap, _penaltyGroups, _boxTimeEstimates, sss, jteMap); double jammerPointCost = 0; double blockerPointCost = 0; double jammerValueCost = 0; double blockerValueCost = 0; foreach (PenaltyGroup pg in _penaltyGroups) { if (!penaltyGroupCost.ContainsKey(pg.GroupID) || !penaltyGroupValueCost.ContainsKey(pg.GroupID)) { continue; } // determine whether this penalty group is for a jammer or blocker var penalty = pg.Penalties[0]; if (jamPlayerMap[penalty.JamID][penalty.PlayerID].IsJammer) { jammerPointCost += penaltyGroupCost[pg.GroupID] * pg.Penalties.Count; jammerValueCost += penaltyGroupValueCost[pg.GroupID] * pg.Penalties.Count; } else { blockerPointCost += penaltyGroupCost[pg.GroupID] * pg.Penalties.Count; blockerValueCost += penaltyGroupValueCost[pg.GroupID] * pg.Penalties.Count; } } new AveragePenaltyCostGateway(connection, transaction).InsertAveragePenaltyCost(new AveragePenaltyCostPerJam { BlockerPointCost = blockerPointCost / (8 * jamData.Keys.Count), BlockerValueCost = blockerValueCost / (8 * jamData.Keys.Count), JammerPointCost = jammerPointCost / (2 * jamData.Keys.Count), JammerValueCost = jammerValueCost / (2 * jamData.Keys.Count) }); transaction.Commit(); connection.Close(); }
public IList <Dictionary <int, PlayerPerformance> > GetAllPlayerPointPerformances(int numberOfIterations) { // pull data SqlConnection connection = new SqlConnection(_connectionString); connection.Open(); SqlTransaction transaction = connection.BeginTransaction(); var players = new PlayerGateway(connection, transaction).GetAllPlayers().GroupBy(p => p.ID).ToDictionary(g => g.Key, g => g.ToDictionary(g2 => g2.TeamID)); var jams = new JamGateway(connection, transaction).GetAllJams().OrderBy(j => j.ID); var jamBoutMap = jams.ToDictionary(j => j.ID, j => j.BoutID); var jpe = new JamPlayerEffectivenessGateway(connection, transaction).GetAllJamPlayerEffectiveness(); var jamData = new JamDataGateway(connection, transaction).GetJamTeamDataForYear(STATS_START_DATE.Year) .GroupBy(jd => jd.JamID) .ToDictionary(g => g.Key, g => g.ToDictionary(g2 => g2.TeamID)); var teams = new TeamGateway(connection, transaction).GetAllTeams().ToDictionary(t => t.ID); var bouts = new BoutGateway(connection, transaction).GetBouts().ToDictionary(t => t.ID); var penalties = new PenaltyGateway(connection, transaction).GetAllPenalties() .GroupBy(p => p.JamID) .ToDictionary( g => g.Key, g => g.GroupBy(g2 => g2.PlayerID).ToDictionary(g3 => g3.Key, g3 => g3.ToList())); var pgs = new PenaltyGroupGateway(connection, transaction).GetAllPenaltyGroups(); Dictionary <int, int> boxTimeEstimates = new BoxTimeEstimateGateway(connection, transaction).GetAllBoxTimeEstimates(); Dictionary <FoulComparison, Dictionary <int, float> > sss = new SituationalScoreGateway(connection, transaction).GetAllSituationalScores(); AveragePenaltyCostPerJam avgPenCost = new AveragePenaltyCostGateway(connection, transaction).GetAveragePenaltyCost(); Dictionary <int, Dictionary <int, JamPlayer> > jamPlayerMap = new JamPlayerGateway(connection, transaction).GetJamPlayers() .GroupBy(jp => jp.JamID) .ToDictionary(g => g.Key, g => g.ToDictionary(g2 => g2.PlayerID)); transaction.Commit(); connection.Close(); Dictionary <FoulComparison, float> medians = CalculateMedianScores(sss); PenaltyCostCalculator ppcCalc = new PenaltyCostCalculator(_connectionString); Dictionary <int, double> groupPenaltyCostMap = PenaltyCostCalculator.CalculatePointCosts(jamData, jamPlayerMap, pgs, boxTimeEstimates, sss); Dictionary <int, double> jamTotalPortionMap = new Dictionary <int, double>(300); var previousResult = GenerateInitialPlayerPerformance(players, jams, jpe, jamData, teams, bouts, penalties, pgs, avgPenCost, medians, groupPenaltyCostMap, jamTotalPortionMap); List <Dictionary <int, PlayerPerformance> > result = new List <Dictionary <int, PlayerPerformance> >(numberOfIterations); result.Add(previousResult); int i = 0; while (i < numberOfIterations) { previousResult = GeneratePlayerPerformanceIteration(previousResult, jams, jamData, jamTotalPortionMap, jpe, avgPenCost); result.Add(previousResult); i++; } return(result); }
public IList<Dictionary<int, PlayerPerformance>> GetAllPlayerPointPerformances(int numberOfIterations) { // pull data SqlConnection connection = new SqlConnection(_connectionString); connection.Open(); SqlTransaction transaction = connection.BeginTransaction(); var players = new PlayerGateway(connection, transaction).GetAllPlayers().GroupBy(p => p.ID).ToDictionary(g => g.Key, g => g.ToDictionary(g2 => g2.TeamID)); var jams = new JamGateway(connection, transaction).GetAllJams().OrderBy(j => j.ID); var jamBoutMap = jams.ToDictionary(j => j.ID, j => j.BoutID); var jpe = new JamPlayerEffectivenessGateway(connection, transaction).GetAllJamPlayerEffectiveness(); var jamData = new JamDataGateway(connection, transaction).GetAllJamData() .GroupBy(jd => jd.JamID) .ToDictionary(g => g.Key, g => g.ToDictionary(g2 => g2.TeamID)); var teams = new TeamGateway(connection, transaction).GetAllTeams().ToDictionary(t => t.ID); var bouts = new BoutGateway(connection, transaction).GetBouts().ToDictionary(t => t.ID); var penalties = new PenaltyGateway(connection, transaction).GetAllPenalties() .GroupBy(p => p.JamID) .ToDictionary( g => g.Key, g => g.GroupBy(g2 => g2.PlayerID).ToDictionary(g3 => g3.Key, g3 => g3.ToList())); var pgs = new PenaltyGroupGateway(connection, transaction).GetAllPenaltyGroups(); Dictionary<int, int> boxTimeEstimates = new BoxTimeEstimateGateway(connection, transaction).GetAllBoxTimeEstimates(); Dictionary<FoulComparison, Dictionary<int, float>> sss = new SituationalScoreGateway(connection, transaction).GetAllSituationalScores(); AveragePenaltyCostPerJam avgPenCost = new AveragePenaltyCostGateway(connection, transaction).GetAveragePenaltyCost(); Dictionary<int, Dictionary<int, JamPlayer>> jamPlayerMap = new JamPlayerGateway(connection, transaction).GetJamPlayers() .GroupBy(jp => jp.JamID) .ToDictionary(g => g.Key, g => g.ToDictionary(g2 => g2.PlayerID)); transaction.Commit(); connection.Close(); Dictionary<FoulComparison, float> medians = CalculateMedianScores(sss); PenaltyCostCalculator ppcCalc = new PenaltyCostCalculator(_connectionString); Dictionary<int, double> groupPenaltyCostMap = PenaltyCostCalculator.CalculatePointCosts(jamData, jamPlayerMap, pgs, boxTimeEstimates, sss); Dictionary<int, double> jamTotalPortionMap = new Dictionary<int, double>(300); var previousResult = GenerateInitialPlayerPerformance(players, jams, jpe, jamData, teams, bouts, penalties, pgs, avgPenCost, medians, groupPenaltyCostMap, jamTotalPortionMap); List<Dictionary<int, PlayerPerformance>> result = new List<Dictionary<int, PlayerPerformance>>(numberOfIterations); result.Add(previousResult); int i = 0; while(i < numberOfIterations) { previousResult = GeneratePlayerPerformanceIteration(previousResult, jams, jamData, jamTotalPortionMap, jpe, avgPenCost); result.Add(previousResult); i++; } return result; }
public IList <PlayerPerformance> GetPlayerPointPerformancesForTeam(int teamID) { // pull data SqlConnection connection = new SqlConnection(_connectionString); connection.Open(); SqlTransaction transaction = connection.BeginTransaction(); var players = new PlayerGateway(connection, transaction).GetPlayersForTeam(teamID).ToDictionary(p => p.ID); var jams = new JamGateway(connection, transaction).GetJamsForTeamAfterDate(teamID, STATS_START_DATE).OrderBy(j => j.ID); var jamBoutMap = jams.ToDictionary(j => j.ID, j => j.BoutID); var jpe = new JamPlayerEffectivenessGateway(connection, transaction).GetJamPlayerEffectivenessForTeam(teamID); var jdg = new JamDataGateway(connection, transaction); var jamTeamData = jdg.GetJamDataForTeam(teamID).ToDictionary(jd => jd.JamID); var jamData = jdg.GetAllJamData().ToDictionary(jd => jd.JamID); foreach (JamTeamData jtd in jamTeamData.Values) { jtd.Year = jamData[jtd.JamID].PlayDate.Year; } var teams = new TeamGateway(connection, transaction).GetAllTeams().ToDictionary(t => t.ID); var bouts = new BoutGateway(connection, transaction).GetBouts().ToDictionary(t => t.ID); var penalties = new PenaltyGateway(connection, transaction).GetPenaltiesForTeam(teamID) .GroupBy(p => p.JamID) .ToDictionary( g => g.Key, g => g.GroupBy(g2 => g2.PlayerID).ToDictionary(g3 => g3.Key, g3 => g3.ToList())); var pgs = new PenaltyGroupGateway(connection, transaction).GetPenaltyGroupsForTeamAfterDate(teamID, STATS_START_DATE); Dictionary <int, int> boxTimeEstimates = new BoxTimeEstimateGateway(connection, transaction).GetAllBoxTimeEstimates(); Dictionary <FoulComparison, Dictionary <int, float> > sss = new SituationalScoreGateway(connection, transaction).GetAllSituationalScores(); AveragePenaltyCostPerJam avgPenCost = new AveragePenaltyCostGateway(connection, transaction).GetAveragePenaltyCost(); transaction.Commit(); connection.Close(); Dictionary <FoulComparison, float> medians = CalculateMedianScores(sss); PenaltyCostCalculator ppcCalc = new PenaltyCostCalculator(_connectionString); Dictionary <int, double> groupPenaltyCostMap = ppcCalc.CalculatePointCostsForTeam(jamTeamData, pgs, boxTimeEstimates, sss); Dictionary <int, PlayerPerformance> pps = new Dictionary <int, PlayerPerformance>(25); Dictionary <int, double> jamTotalPortionMap = new Dictionary <int, double>(300); // we use "jam portions" to divide up the total value of the jam among participating players // we give jammers an additional multiplier to their jam portions, based on year, to represent their greater impact on team success foreach (Jam jam in jams) { var pe = jpe[jam.ID]; foreach (JamPlayerEffectiveness eff in pe.Values) { // get/set PlayerPerformance object if (!pps.ContainsKey(eff.PlayerID)) { pps[eff.PlayerID] = new PlayerPerformance { Player = players[eff.PlayerID], Bouts = new List <BoutPerformance>() }; } PlayerPerformance curPP = pps[eff.PlayerID]; // get/set BoutPerformance object Bout bout = bouts[jam.BoutID]; BoutPerformance bp = null; if (!curPP.Bouts.Any() || curPP.Bouts.Last().BoutID != bout.ID) { bp = new BoutPerformance { BoutID = bout.ID, AwayTeamName = teams[bout.AwayTeamID].Name, HomeTeamName = teams[bout.HomeTeamID].Name, BoutDate = bout.BoutDate, Jams = new List <JamPerformance>() }; curPP.Bouts.Add(bp); } else { bp = curPP.Bouts.Last(); } JamTeamData jd = jamTeamData[jam.ID]; int penaltyCount = penalties.ContainsKey(jam.ID) && penalties[jam.ID].ContainsKey(eff.PlayerID) ? penalties[jam.ID][eff.PlayerID].Count() : 0; JamPerformance jp = new JamPerformance { BlockerJamPercentage = eff.IsJammer ? 0 : eff.JamPortion, DeltaPercentile = eff.BaseQuality, IsFirstHalf = jam.IsFirstHalf, JamID = jam.ID, JammerJamPercentage = eff.IsJammer ? eff.JamPortion : 0, JamNumber = jam.JamNumber, JamPenalties = penaltyCount, MedianDelta = medians[jd.FoulComparison], PenaltyCost = 0, PointDelta = jd.PointDelta }; double jammerRatio = bouts[jamBoutMap[jam.ID]].BoutDate.Year == 2019 ? 2.0 : 4.0; if (jamTotalPortionMap.ContainsKey(jam.ID)) { jamTotalPortionMap[jam.ID] += eff.IsJammer ? eff.JamPortion * jammerRatio : eff.JamPortion; } else { jamTotalPortionMap[jam.ID] = eff.IsJammer ? eff.JamPortion * jammerRatio : eff.JamPortion; } bp.Jams.Add(jp); } } foreach (PenaltyGroup pg in pgs) { foreach (Penalty p in pg.Penalties) { if (jams.Any(j => j.ID == p.JamID)) { JamPerformance jp = pps[p.PlayerID].Bouts.SelectMany(b => b.Jams).Where(j => j.JamID == p.JamID).First(); jp.PenaltyCost += groupPenaltyCostMap[pg.GroupID]; } } } foreach (PlayerPerformance pp in pps.Values) { RollUpPlayerPerformance(avgPenCost, jamTotalPortionMap, pp); } CalculateTeamAverages(pps, bouts); foreach (PlayerPerformance pp in pps.Values) { pp.BlockerPerformance.PlayerValueVersusTeamAverage = pp.Bouts.Sum(b => b.BlockerPerformance.PlayerValueVersusTeamAverage); pp.JammerPerformance.PlayerValueVersusTeamAverage = pp.Bouts.Sum(b => b.JammerPerformance.PlayerValueVersusTeamAverage); } return(pps.Values.ToList()); }
public IList <PlayerPerformance> GetPlayerValuePerformancesForTeam(int teamID) { // pull data SqlConnection connection = new SqlConnection(_connectionString); connection.Open(); SqlTransaction transaction = connection.BeginTransaction(); var players = new PlayerGateway(connection, transaction).GetPlayersForTeam(teamID).ToDictionary(p => p.ID); var jams = new JamGateway(connection, transaction).GetJamsForTeamAfterDate(teamID, new DateTime(2016, 1, 1)).OrderBy(j => j.ID); var jamBoutMap = jams.ToDictionary(j => j.ID, j => j.BoutID); var jpe = new JamPlayerEffectivenessGateway(connection, transaction).GetJamPlayerEffectivenessForTeam(teamID); var jamData = new JamDataGateway(connection, transaction).GetJamDataForTeam(teamID).ToDictionary(jd => jd.JamID); var teams = new TeamGateway(connection, transaction).GetAllTeams().ToDictionary(t => t.ID); var bouts = new BoutGateway(connection, transaction).GetBouts().ToDictionary(t => t.ID); var penalties = new PenaltyGateway(connection, transaction).GetPenaltiesForTeam(teamID) .GroupBy(p => p.JamID) .ToDictionary( g => g.Key, g => g.GroupBy(g2 => g2.PlayerID).ToDictionary(g3 => g3.Key, g3 => g3.ToList())); var pgs = new PenaltyGroupGateway(connection, transaction).GetPenaltyGroupsForTeam(teamID); Dictionary <int, int> boxTimeEstimates = new BoxTimeEstimateGateway(connection, transaction).GetAllBoxTimeEstimates(); Dictionary <FoulComparison, Dictionary <int, float> > sss = new SituationalScoreGateway(connection, transaction).GetAllSituationalScores(); Dictionary <int, double> jte = new JamTeamEffectivenessGateway(connection, transaction).GetJamTeamEffectivenessForTeam(teamID); AveragePenaltyCostPerJam avgPenCost = new AveragePenaltyCostGateway(connection, transaction).GetAveragePenaltyCost(); transaction.Commit(); connection.Close(); Dictionary <FoulComparison, float> medians = CalculateMedianScores(sss); PenaltyCostCalculator pcCalc = new PenaltyCostCalculator(_connectionString); Dictionary <int, double> groupPenaltyCostMap = pcCalc.CalculateValueCostsForTeam(jamData, pgs, boxTimeEstimates, sss, jte); Dictionary <int, PlayerPerformance> ppMap = new Dictionary <int, PlayerPerformance>(25); Dictionary <int, double> jamTotalPortionMap = new Dictionary <int, double>(300); foreach (Jam jam in jams) { var pe = jpe[jam.ID]; foreach (JamPlayerEffectiveness eff in pe.Values) { // get/set PlayerPerformance object if (!ppMap.ContainsKey(eff.PlayerID)) { ppMap[eff.PlayerID] = new PlayerPerformance { Player = players[eff.PlayerID], Bouts = new List <BoutPerformance>() }; } PlayerPerformance curPP = ppMap[eff.PlayerID]; // get/set BoutPerformance object Bout bout = bouts[jam.BoutID]; BoutPerformance bp = null; if (!curPP.Bouts.Any() || curPP.Bouts.Last().BoutDate != bout.BoutDate || curPP.Bouts.Last().HomeTeamName != teams[bout.HomeTeamID].Name || curPP.Bouts.Last().AwayTeamName != teams[bout.AwayTeamID].Name) { bp = new BoutPerformance { AwayTeamName = teams[bout.AwayTeamID].Name, HomeTeamName = teams[bout.HomeTeamID].Name, BoutDate = bout.BoutDate, Jams = new List <JamPerformance>() }; curPP.Bouts.Add(bp); } else { bp = curPP.Bouts.Last(); } JamTeamData jd = jamData[jam.ID]; int penaltyCount = penalties.ContainsKey(jam.ID) && penalties[jam.ID].ContainsKey(eff.PlayerID) ? penalties[jam.ID][eff.PlayerID].Count() : 0; JamPerformance jp = new JamPerformance { BlockerJamPercentage = eff.IsJammer ? 0 : eff.JamPortion, DeltaPercentile = eff.BaseQuality, IsFirstHalf = jam.IsFirstHalf, JamID = jam.ID, JammerJamPercentage = eff.IsJammer ? eff.JamPortion : 0, JamNumber = jam.JamNumber, JamPenalties = penaltyCount, MedianDelta = medians[jd.FoulComparison], PenaltyCost = 0, PointDelta = jd.PointDelta }; if (jamTotalPortionMap.ContainsKey(jam.ID)) { jamTotalPortionMap[jam.ID] += eff.IsJammer ? eff.JamPortion * 4 : eff.JamPortion; } else { jamTotalPortionMap[jam.ID] = eff.IsJammer ? eff.JamPortion * 4 : eff.JamPortion; } bp.Jams.Add(jp); } } foreach (PenaltyGroup pg in pgs) { foreach (Penalty p in pg.Penalties) { JamPerformance jp = ppMap[p.PlayerID].Bouts.SelectMany(b => b.Jams).Where(j => j.JamID == p.JamID).First(); jp.PenaltyCost += groupPenaltyCostMap[pg.GroupID]; } } foreach (PlayerPerformance pp in ppMap.Values) { pp.BlockerPerformance = new RolledUpPerformanceData(); pp.JammerPerformance = new RolledUpPerformanceData(); foreach (BoutPerformance bp in pp.Bouts) { bp.BlockerPerformance = new RolledUpPerformanceData(); bp.JammerPerformance = new RolledUpPerformanceData(); foreach (JamPerformance jp in bp.Jams) { double averagePenaltyCost = jp.JammerJamPercentage > 0 ? avgPenCost.JammerValueCost : avgPenCost.BlockerValueCost; double jamShare = (jp.JammerJamPercentage * 4 + jp.BlockerJamPercentage) / jamTotalPortionMap[jp.JamID]; jp.DeltaPortionVersusMedian = (jp.DeltaPercentile - 0.5) * jamShare; jp.PlayerValue = jp.DeltaPortionVersusMedian + jp.PenaltyCost - averagePenaltyCost; var rollUp = jp.JammerJamPercentage > 0 ? bp.JammerPerformance : bp.BlockerPerformance; rollUp.TotalJamPortions += jp.JammerJamPercentage + jp.BlockerJamPercentage; rollUp.TotalPenalties += jp.JamPenalties; rollUp.TotalPenaltyCost += jp.PenaltyCost; rollUp.TotalPointsVersusMedian += jp.DeltaPortionVersusMedian; rollUp.TotalPlayerValue += jp.PlayerValue; } pp.BlockerPerformance.TotalJamPortions += bp.BlockerPerformance.TotalJamPortions; pp.BlockerPerformance.TotalPenalties += bp.BlockerPerformance.TotalPenalties; pp.BlockerPerformance.TotalPenaltyCost += bp.BlockerPerformance.TotalPenaltyCost; pp.BlockerPerformance.TotalPointsVersusMedian += bp.BlockerPerformance.TotalPointsVersusMedian; pp.BlockerPerformance.TotalPlayerValue += bp.BlockerPerformance.TotalPlayerValue; pp.JammerPerformance.TotalJamPortions += bp.JammerPerformance.TotalJamPortions; pp.JammerPerformance.TotalPenalties += bp.JammerPerformance.TotalPenalties; pp.JammerPerformance.TotalPenaltyCost += bp.JammerPerformance.TotalPenaltyCost; pp.JammerPerformance.TotalPointsVersusMedian += bp.JammerPerformance.TotalPointsVersusMedian; pp.JammerPerformance.TotalPlayerValue += bp.JammerPerformance.TotalPlayerValue; } } return(ppMap.Values.ToList()); }
public IList<PlayerPerformance> GetPlayerPointPerformancesForTeam(int teamID) { // pull data SqlConnection connection = new SqlConnection(_connectionString); connection.Open(); SqlTransaction transaction = connection.BeginTransaction(); var players = new PlayerGateway(connection, transaction).GetPlayersForTeam(teamID).ToDictionary(p => p.ID); var jams = new JamGateway(connection, transaction).GetJamsForTeamAfterDate(teamID, new DateTime(2016,1,1)).OrderBy(j => j.ID); var jamBoutMap = jams.ToDictionary(j => j.ID, j => j.BoutID); var jpe = new JamPlayerEffectivenessGateway(connection, transaction).GetJamPlayerEffectivenessForTeam(teamID); var jamData = new JamDataGateway(connection, transaction).GetJamDataForTeam(teamID).ToDictionary(jd => jd.JamID); var teams = new TeamGateway(connection, transaction).GetAllTeams().ToDictionary(t => t.ID); var bouts = new BoutGateway(connection, transaction).GetBouts().ToDictionary(t => t.ID); var penalties = new PenaltyGateway(connection, transaction).GetPenaltiesForTeam(teamID) .GroupBy(p => p.JamID) .ToDictionary( g => g.Key, g => g.GroupBy(g2 => g2.PlayerID).ToDictionary(g3 => g3.Key, g3 => g3.ToList())); var pgs = new PenaltyGroupGateway(connection, transaction).GetPenaltyGroupsForTeam(teamID); Dictionary<int, int> boxTimeEstimates = new BoxTimeEstimateGateway(connection, transaction).GetAllBoxTimeEstimates(); Dictionary<FoulComparison, Dictionary<int, float>> sss = new SituationalScoreGateway(connection, transaction).GetAllSituationalScores(); AveragePenaltyCostPerJam avgPenCost = new AveragePenaltyCostGateway(connection, transaction).GetAveragePenaltyCost(); transaction.Commit(); connection.Close(); Dictionary<FoulComparison, float> medians = CalculateMedianScores(sss); PenaltyCostCalculator ppcCalc = new PenaltyCostCalculator(_connectionString); Dictionary<int, double> groupPenaltyCostMap = ppcCalc.CalculatePointCostsForTeam(jamData, pgs, boxTimeEstimates, sss); Dictionary<int, PlayerPerformance> pps = new Dictionary<int, PlayerPerformance>(25); Dictionary<int, double> jamTotalPortionMap = new Dictionary<int, double>(300); foreach(Jam jam in jams) { var pe = jpe[jam.ID]; foreach(JamPlayerEffectiveness eff in pe.Values) { // get/set PlayerPerformance object if(!pps.ContainsKey(eff.PlayerID)) { pps[eff.PlayerID] = new PlayerPerformance { Player = players[eff.PlayerID], Bouts = new List<BoutPerformance>() }; } PlayerPerformance curPP = pps[eff.PlayerID]; // get/set BoutPerformance object Bout bout = bouts[jam.BoutID]; BoutPerformance bp = null; if (!curPP.Bouts.Any() || curPP.Bouts.Last().BoutID != bout.ID) { bp = new BoutPerformance { BoutID = bout.ID, AwayTeamName = teams[bout.AwayTeamID].Name, HomeTeamName = teams[bout.HomeTeamID].Name, BoutDate = bout.BoutDate, Jams = new List<JamPerformance>() }; curPP.Bouts.Add(bp); } else { bp = curPP.Bouts.Last(); } JamTeamData jd = jamData[jam.ID]; int penaltyCount = penalties.ContainsKey(jam.ID) && penalties[jam.ID].ContainsKey(eff.PlayerID) ? penalties[jam.ID][eff.PlayerID].Count() : 0; JamPerformance jp = new JamPerformance { BlockerJamPercentage = eff.IsJammer ? 0 : eff.JamPortion, DeltaPercentile = eff.BaseQuality, IsFirstHalf = jam.IsFirstHalf, JamID = jam.ID, JammerJamPercentage = eff.IsJammer ? eff.JamPortion : 0, JamNumber = jam.JamNumber, JamPenalties = penaltyCount, MedianDelta = medians[jd.FoulComparison], PenaltyCost = 0, PointDelta = jd.PointDelta }; if (jamTotalPortionMap.ContainsKey(jam.ID)) { jamTotalPortionMap[jam.ID] += eff.IsJammer ? eff.JamPortion * 4 : eff.JamPortion; } else { jamTotalPortionMap[jam.ID] = eff.IsJammer ? eff.JamPortion * 4 : eff.JamPortion; } bp.Jams.Add(jp); } } foreach(PenaltyGroup pg in pgs) { foreach(Penalty p in pg.Penalties) { if (jams.Any(j => j.ID == p.JamID)) { JamPerformance jp = pps[p.PlayerID].Bouts.SelectMany(b => b.Jams).Where(j => j.JamID == p.JamID).First(); jp.PenaltyCost += groupPenaltyCostMap[pg.GroupID]; } } } foreach(PlayerPerformance pp in pps.Values) { RollUpPlayerPerformance(avgPenCost, jamTotalPortionMap, pp); } CalculateTeamAverages(pps, bouts); foreach(PlayerPerformance pp in pps.Values) { pp.BlockerPerformance.PlayerValueVersusTeamAverage = pp.Bouts.Sum(b => b.BlockerPerformance.PlayerValueVersusTeamAverage); pp.JammerPerformance.PlayerValueVersusTeamAverage = pp.Bouts.Sum(b => b.JammerPerformance.PlayerValueVersusTeamAverage); } return pps.Values.ToList(); }