예제 #1
0
        internal Dictionary <int, double> CalculateValueCostsForTeam(Dictionary <int, JamTeamData> jamData,
                                                                     IList <PenaltyGroup> pgs,
                                                                     Dictionary <int, int> boxTimeEstimates,
                                                                     Dictionary <FoulComparison, Dictionary <int, float> > sss,
                                                                     Dictionary <int, double> jamValueEstimates)
        {
            Dictionary <int, double> groupPenaltyCostMap = new Dictionary <int, double>();

            foreach (PenaltyGroup group in pgs)
            {
                double totalCost = 0;
                // calculate the cost of each box time in the group
                foreach (BoxTime boxTime in group.BoxTimes)
                {
                    int         estimateTime = boxTimeEstimates[boxTime.BoxTimeID];
                    JamTeamData thisJamData  = jamData[boxTime.JamID];
                    // determine how big the swing would be if there had been no box time served
                    double valueDiff = GetEstimatedValueWithoutBoxTime(sss, thisJamData, boxTime.IsJammer) - jamValueEstimates[boxTime.JamID];

                    double totalPenaltyTime = boxTime.IsJammer ?
                                              thisJamData.JammerBoxTime :
                                              thisJamData.BlockerBoxTime;
                    // modify this by how much of the total penalty time this player contributed

                    // doing the rough estimate version for now
                    totalCost += valueDiff * boxTimeEstimates[boxTime.BoxTimeID] / totalPenaltyTime;
                }
                groupPenaltyCostMap[group.GroupID] = totalCost / group.Penalties.Count;
            }

            return(groupPenaltyCostMap);
        }
예제 #2
0
        private JamTeamData ReadJamTeamData(SqlDataReader reader)
        {
            JamTeamData jamFoul = new JamTeamData();

            jamFoul.JamID             = reader.GetInt32(reader.GetOrdinal("JamID"));
            jamFoul.TeamID            = reader.GetInt32(reader.GetOrdinal("TeamID"));
            jamFoul.BlockerBoxTime    = reader.GetInt32(reader.GetOrdinal("BlockerBoxTime"));
            jamFoul.JammerBoxTime     = reader.GetInt32(reader.GetOrdinal("JammerBoxTime"));
            jamFoul.OppBlockerBoxTime = reader.GetInt32(reader.GetOrdinal("OppBlockerBoxTime"));
            jamFoul.OppJammerBoxTime  = reader.GetInt32(reader.GetOrdinal("OppJammerBoxTime"));
            jamFoul.PointDelta        = reader.GetInt32(reader.GetOrdinal("PointDelta"));
            return(jamFoul);
        }
예제 #3
0
        private void AssignPenaltyCosts(Dictionary <int, IGrouping <int, JamTeamData> > jamDataMap, Dictionary <int, JamTimeEstimate> jamTimeMap,
                                        Dictionary <int, List <JamPlayerEffectiveness> > pjeMap, Dictionary <int, List <PenaltyGroup> > jamBoxTimeMap,
                                        Dictionary <int, int> boxTimeEstimates, int jamID, JamTeamEffectiveness jte)
        {
            List <PenaltyGroup> jamPenaltyGroups = jamBoxTimeMap[jamID];
            JamTeamData         thisJamData      = jamDataMap[jamID].First(jd => jd.TeamID == jte.TeamID);

            foreach (PenaltyGroup group in jamPenaltyGroups)
            {
                int penaltyPlayerID = group.Penalties[0].PlayerID;
                foreach (BoxTime boxTime in group.BoxTimes)
                {
                    if (boxTime.JamID == jamID)
                    {
                        // determine how big the swing would be if there had been no box time served
                        double qualityDifference = DetermineQualityWithoutPenalty(thisJamData, boxTime.IsJammer) - jte.Percentile;

                        // the cost of the box time is how bad that player would have to be in that jam to have an equivalent effect
                        // we estimate this based on how important the player is in the jam, by position
                        double penaltyCost      = boxTime.IsJammer ? qualityDifference * 2 : qualityDifference * 8;
                        double totalPenaltyTime = boxTime.IsJammer ?
                                                  thisJamData.JammerBoxTime :
                                                  thisJamData.BlockerBoxTime;
                        // modify this by how much of the total penalty time this player contributed

                        // doing the rough estimate version for now
                        double penaltyPortion = boxTimeEstimates[boxTime.BoxTimeID] / totalPenaltyTime;

                        // a portion of that cost goes to each penalty that factors into this box time
                        int penaltyCount = group.Penalties.Count;
                        foreach (Penalty penalty in group.Penalties)
                        {
                            var penaltyPJE = pjeMap[penalty.JamID].First(pje => pje.PlayerID == penalty.PlayerID);
                            penaltyPJE.PenaltyCost += penaltyPortion * penaltyCost / penaltyCount;
                            if (double.IsNaN(penaltyPJE.PenaltyCost))
                            {
                                throw new Exception(penalty.JamID + ": bad penalty data");
                            }
                        }

                        // for a given penalty group, there should only ever be
                        // a single box time in a given jam
                        break;
                    }
                }
            }
        }
예제 #4
0
        internal static Dictionary <int, double> CalculatePointCosts(Dictionary <int, Dictionary <int, JamTeamData> > jamData,
                                                                     Dictionary <int, Dictionary <int, JamPlayer> > jamPlayerMap,
                                                                     IList <PenaltyGroup> pgs,
                                                                     Dictionary <int, int> boxTimeEstimates,
                                                                     Dictionary <FoulComparison, Dictionary <int, float> > sss)
        {
            Dictionary <int, double> groupPenaltyCostMap = new Dictionary <int, double>();

            foreach (PenaltyGroup group in pgs)
            {
                double totalCost = 0;
                int    teamID    = jamPlayerMap[group.Penalties[0].JamID][group.Penalties[0].PlayerID].TeamID;
                // calculate the cost of each box time in the group
                foreach (BoxTime boxTime in group.BoxTimes)
                {
                    if (!jamData.ContainsKey(boxTime.JamID))
                    {
                        continue;
                    }
                    int         estimateTime = boxTimeEstimates[boxTime.BoxTimeID];
                    JamTeamData thisJamData  = jamData[boxTime.JamID][teamID];
                    // determine how big the swing would be if there had been no box time served
                    double pointDiff = GetEstimatedPointsWithoutBoxTime(sss, thisJamData, boxTime.IsJammer) - thisJamData.PointDelta;

                    double totalPenaltyTime = boxTime.IsJammer ?
                                              thisJamData.JammerBoxTime :
                                              thisJamData.BlockerBoxTime;
                    // modify this by how much of the total penalty time this player contributed

                    // doing the rough estimate version for now
                    totalCost += pointDiff * boxTimeEstimates[boxTime.BoxTimeID] / totalPenaltyTime;
                }
                groupPenaltyCostMap[group.GroupID] = totalCost / group.Penalties.Count;
            }

            return(groupPenaltyCostMap);
        }
예제 #5
0
        internal static double GetEstimatedValueWithoutBoxTime(Dictionary <FoulComparison, Dictionary <int, float> > sss, JamTeamData jamData, bool isJammer)
        {
            if (!sss.ContainsKey(jamData.FoulComparison))
            {
                throw new InvalidOperationException("This is bad data");
            }

            // figure out the foul differential if this team did not commit fouls of this type this jam
            int            jammerPenaltyDiff  = (isJammer ? 0 : jamData.JammerBoxTime) - jamData.OppJammerBoxTime;
            int            blockerPenaltyDiff = (isJammer ? jamData.BlockerBoxTime : 0) - jamData.OppBlockerBoxTime;
            double         jammerBoxComp      = Math.Round(jammerPenaltyDiff / 15.0, MidpointRounding.AwayFromZero) / 2.0;
            double         blockerBoxComp     = Math.Round(blockerPenaltyDiff / 15.0, MidpointRounding.AwayFromZero) / 2.0;
            FoulComparison foul = new FoulComparison
            {
                Year = jamData.Year,
                JammerBoxComparison  = jammerBoxComp,
                BlockerBoxComparison = blockerBoxComp
            };

            if (!sss.ContainsKey(foul))
            {
                // lacking anything better, sum the distance of each factor from the percentile of the base
                JamTeamData baseJamData = new JamTeamData
                {
                    Year              = jamData.Year,
                    BlockerBoxTime    = 0,
                    JammerBoxTime     = 0,
                    OppBlockerBoxTime = 0,
                    OppJammerBoxTime  = 0,
                    PointDelta        = jamData.PointDelta
                };
                double baseDelta = GetPercentileForScore(sss[baseJamData.FoulComparison], jamData.PointDelta);

                // pull team 1 values
                baseJamData.BlockerBoxTime = isJammer ? jamData.BlockerBoxTime : 0;
                baseJamData.JammerBoxTime  = isJammer ? 0 : jamData.JammerBoxTime;
                if (baseJamData.FoulComparison.Equals(foul))
                {
                    return(0);
                }
                double score1 = 0;
                if (!sss.ContainsKey(baseJamData.FoulComparison))
                {
                    while (baseJamData.Year > 2013)
                    {
                        baseJamData.Year--;
                        if (sss.ContainsKey(baseJamData.FoulComparison))
                        {
                            score1 = GetPercentileForScore(sss[baseJamData.FoulComparison], jamData.PointDelta);
                            break;
                        }
                    }
                    if (baseJamData.Year == 2013)
                    {
                        throw new InvalidOperationException("Bad data");
                    }
                }
                else
                {
                    score1 = GetPercentileForScore(sss[baseJamData.FoulComparison], jamData.PointDelta);
                }

                // pull team 2 blocker
                baseJamData.BlockerBoxTime    = 0;
                baseJamData.JammerBoxTime     = 0;
                baseJamData.OppBlockerBoxTime = jamData.OppBlockerBoxTime;
                if (baseJamData.FoulComparison.Equals(foul))
                {
                    return(0);
                }
                double score2 = 0;
                if (!sss.ContainsKey(baseJamData.FoulComparison))
                {
                    while (baseJamData.Year > 2013)
                    {
                        baseJamData.Year--;
                        if (sss.ContainsKey(baseJamData.FoulComparison))
                        {
                            score1 = GetPercentileForScore(sss[baseJamData.FoulComparison], jamData.PointDelta);
                            break;
                        }
                    }
                    if (baseJamData.Year == 2013)
                    {
                        throw new InvalidOperationException("Bad data");
                    }
                }
                else
                {
                    score2 = GetPercentileForScore(sss[baseJamData.FoulComparison], jamData.PointDelta);
                }

                // pull team 2 jammer
                baseJamData.OppBlockerBoxTime = 0;
                baseJamData.OppJammerBoxTime  = jamData.OppJammerBoxTime;
                if (baseJamData.FoulComparison.Equals(foul))
                {
                    return(0);
                }
                double score3 = GetPercentileForScore(sss[baseJamData.FoulComparison], jamData.PointDelta);

                return(score1 + score2 + score3 - 2 * baseDelta);
            }
            else
            {
                return(GetPercentileForScore(sss[foul], jamData.PointDelta));
            }
        }
        private static Dictionary <int, PlayerPerformance> GenerateInitialPlayerPerformance(Dictionary <int, Dictionary <int, Player> > players,
                                                                                            IOrderedEnumerable <Jam> jams,
                                                                                            Dictionary <int, Dictionary <int, JamPlayerEffectiveness> > jpe,
                                                                                            Dictionary <int, Dictionary <int, JamTeamData> > jamData,
                                                                                            Dictionary <int, Team> teams,
                                                                                            Dictionary <int, Bout> bouts,
                                                                                            Dictionary <int, Dictionary <int, List <Penalty> > > penalties,
                                                                                            IList <PenaltyGroup> pgs,
                                                                                            AveragePenaltyCostPerJam avgPenCost,
                                                                                            Dictionary <FoulComparison, float> medians,
                                                                                            Dictionary <int, double> groupPenaltyCostMap,
                                                                                            Dictionary <int, double> jamTotalPortionMap)
        {
            Dictionary <int, PlayerPerformance> pps = new Dictionary <int, PlayerPerformance>();

            foreach (Jam jam in jams)
            {
                var pe = jpe[jam.ID];
                foreach (var eff in pe.Values)
                {
                    // get/set PlayerPerformance object
                    if (!pps.ContainsKey(eff.PlayerID))
                    {
                        pps[eff.PlayerID] = new PlayerPerformance
                        {
                            Player = players[eff.PlayerID][eff.TeamID],
                            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().BoutDate != bout.BoutDate ||
                        curPP.Bouts.Last().HomeTeamName != teams[bout.HomeTeamID].Name ||
                        curPP.Bouts.Last().AwayTeamName != teams[bout.AwayTeamID].Name)
                    {
                        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][eff.TeamID];
                    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 = pps[p.PlayerID].Bouts.SelectMany(b => b.Jams).Where(j => j.JamID == p.JamID).First();
                    jp.PenaltyCost += groupPenaltyCostMap[pg.GroupID];
                }
            }

            Parallel.ForEach(pps.Values, pp =>
            {
                RollUpPlayerPerformance(avgPenCost, jamTotalPortionMap, pp);
            });

            return(pps);
        }
        private static Dictionary <int, PlayerPerformance> GeneratePlayerPerformanceIteration(Dictionary <int, PlayerPerformance> previousIteration,
                                                                                              IOrderedEnumerable <Jam> jams,
                                                                                              Dictionary <int, Dictionary <int, JamTeamData> > jamData,
                                                                                              Dictionary <int, double> jamTotalPortionMap,
                                                                                              Dictionary <int, Dictionary <int, JamPlayerEffectiveness> > jpe,
                                                                                              AveragePenaltyCostPerJam avgPenCost)
        {
            Dictionary <int, PlayerPerformance> pps = new Dictionary <int, PlayerPerformance>();

            foreach (Jam jam in jams)
            {
                var pe           = jpe[jam.ID];
                var grouped      = pe.Values.GroupBy(p => p.TeamID);
                var team1Players = grouped.First().Select(p => previousIteration[p.PlayerID]);
                var team2Players = grouped.Last().Select(p => previousIteration[p.PlayerID]);
                IEnumerable <JamPlayerEffectiveness> jammers = pe.Values.Where(eff => eff.IsJammer);
                double team1Score = CalculateExpectedScore(team1Players, jammers, jam.BoutID);
                int    team1ID    = grouped.First().Key;
                double team2Score = CalculateExpectedScore(team2Players, jammers, jam.BoutID);

                foreach (var eff in pe.Values)
                {
                    var previousPerformance = previousIteration[eff.PlayerID];
                    // get/set PlayerPerformance object
                    if (!pps.ContainsKey(eff.PlayerID))
                    {
                        pps[eff.PlayerID] = new PlayerPerformance
                        {
                            Player = previousPerformance.Player,
                            Bouts  = new List <BoutPerformance>()
                        };
                    }
                    PlayerPerformance curPP = pps[eff.PlayerID];

                    // get/set BoutPerformance object
                    var             prevBout = previousPerformance.Bouts.First(b => b.BoutID == jam.BoutID);
                    BoutPerformance bp       = null;
                    if (!curPP.Bouts.Any() ||
                        curPP.Bouts.Last().BoutID != prevBout.BoutID)
                    {
                        bp = new BoutPerformance
                        {
                            BoutID       = prevBout.BoutID,
                            AwayTeamName = prevBout.AwayTeamName,
                            HomeTeamName = prevBout.HomeTeamName,
                            BoutDate     = prevBout.BoutDate,
                            Jams         = new List <JamPerformance>()
                        };
                        if (prevBout.BlockerPerformance != null)
                        {
                            bp.BlockerPerformance = new RolledUpPerformanceData
                            {
                                TotalJamPortions = prevBout.BlockerPerformance.TotalJamPortions,
                                TotalPenalties   = prevBout.BlockerPerformance.TotalPenalties,
                                TotalPenaltyCost = prevBout.BlockerPerformance.TotalPenaltyCost
                            };
                        }
                        if (prevBout.JammerPerformance != null)
                        {
                            bp.JammerPerformance = new RolledUpPerformanceData
                            {
                                TotalJamPortions = prevBout.JammerPerformance.TotalJamPortions,
                                TotalPenalties   = prevBout.JammerPerformance.TotalPenalties,
                                TotalPenaltyCost = prevBout.JammerPerformance.TotalPenaltyCost
                            };
                        }
                        curPP.Bouts.Add(bp);
                    }
                    else
                    {
                        bp = curPP.Bouts.Last();
                    }

                    JamTeamData    jd = jamData[jam.ID][eff.TeamID];
                    JamPerformance prevJamPerformance = prevBout.Jams.First(j => j.JamID == jam.ID);
                    double         pointDifferential  = 0;
                    var            playerPerf         = prevJamPerformance.JammerJamPercentage > 0 ? previousPerformance.JammerPerformance : previousPerformance.BlockerPerformance;
                    double         playerScore        = playerPerf.TotalPointsVersusMedian / playerPerf.TotalJamPortions;
                    if (curPP.Player.TeamID == team1ID)
                    {
                        pointDifferential = jd.PointDelta - team1Score + team2Score + playerScore;
                    }
                    else
                    {
                        pointDifferential = jd.PointDelta - team2Score + team1Score + playerScore;
                    }
                    JamPerformance jp = new JamPerformance
                    {
                        BlockerJamPercentage = prevJamPerformance.BlockerJamPercentage,
                        DeltaPercentile      = prevJamPerformance.DeltaPercentile,
                        IsFirstHalf          = prevJamPerformance.IsFirstHalf,
                        JamID = prevJamPerformance.JamID,
                        JammerJamPercentage      = prevJamPerformance.JammerJamPercentage,
                        JamNumber                = prevJamPerformance.JamNumber,
                        JamPenalties             = prevJamPerformance.JamPenalties,
                        MedianDelta              = prevJamPerformance.MedianDelta,
                        PenaltyCost              = prevJamPerformance.PenaltyCost,
                        PointDelta               = jd.PointDelta,
                        DeltaPortionVersusMedian = pointDifferential
                                                   //PlayerValue
                    };
                    bp.Jams.Add(jp);
                }
            }

            Parallel.ForEach(pps.Values, pp =>
            {
                RollUpIteratedPlayerPerformance(avgPenCost, jamTotalPortionMap, pp);
            });

            return(pps);
        }
        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());
        }
예제 #10
0
        private double DetermineQualityWithoutPenalty(JamTeamData jamData, bool isJammer)
        {
            // figure out the foul differential if this team did not commit fouls of this time this jam
            int            jammerPenaltyDiff  = (isJammer ? 0 : jamData.JammerBoxTime) - jamData.OppJammerBoxTime;
            int            blockerPenaltyDiff = (isJammer ? jamData.BlockerBoxTime : 0) - jamData.OppBlockerBoxTime;
            double         jammerBoxComp      = Math.Round(jammerPenaltyDiff / 15.0, MidpointRounding.AwayFromZero) / 2.0;
            double         blockerBoxComp     = Math.Round(blockerPenaltyDiff / 15.0, MidpointRounding.AwayFromZero) / 2.0;
            FoulComparison foul = new FoulComparison
            {
                Year = jamData.Year,
                JammerBoxComparison  = jammerBoxComp,
                BlockerBoxComparison = blockerBoxComp
            };

            if (!_sss.ContainsKey(foul))
            {
                // lacking anything better, sum the distance of each factor from the percentile of the base
                JamTeamData baseJamData = new JamTeamData
                {
                    Year              = jamData.Year,
                    BlockerBoxTime    = 0,
                    JammerBoxTime     = 0,
                    OppBlockerBoxTime = 0,
                    OppJammerBoxTime  = 0,
                    PointDelta        = jamData.PointDelta
                };
                double baseQuality = DetermineQualityWithoutPenalty(baseJamData, isJammer);

                // pull team 1 values
                baseJamData.BlockerBoxTime = isJammer ? jamData.BlockerBoxTime : 0;
                baseJamData.JammerBoxTime  = isJammer ? 0 : jamData.JammerBoxTime;
                if (baseJamData.FoulComparison.Equals(foul))
                {
                    return(0.5);
                }
                double quality1 = DetermineQualityWithoutPenalty(baseJamData, isJammer) - baseQuality;

                // pull team 2 blocker
                baseJamData.BlockerBoxTime    = 0;
                baseJamData.JammerBoxTime     = 0;
                baseJamData.OppBlockerBoxTime = jamData.OppBlockerBoxTime;
                if (baseJamData.FoulComparison.Equals(foul))
                {
                    return(0.5);
                }
                double quality2 = DetermineQualityWithoutPenalty(baseJamData, isJammer) - baseQuality;

                // pull team 2 jammer
                baseJamData.OppBlockerBoxTime = 0;
                baseJamData.OppJammerBoxTime  = jamData.OppJammerBoxTime;
                if (baseJamData.FoulComparison.Equals(foul))
                {
                    return(0.5);
                }
                double quality3 = DetermineQualityWithoutPenalty(baseJamData, isJammer) - baseQuality;

                return(baseQuality + quality1 + quality2 + quality3);
            }
            else if (!_sss[foul].ContainsKey(jamData.PointDelta))
            {
                // extrapolate from the points we do have
                var    bottomList       = _sss[foul].Keys.Where(k => k < jamData.PointDelta);
                int    bottom           = bottomList.Any() ? bottomList.Max() : -55;
                double bottomPercentile = bottomList.Any() ?  _sss[foul][bottom] : 0;

                var    topList       = _sss[foul].Keys.Where(k => k > jamData.PointDelta);
                int    top           = topList.Any() ? topList.Min() : 55;
                double topPercentile = topList.Any() ? _sss[foul][top] : 1;
                int    distance      = top - bottom;
                int    portion       = jamData.PointDelta - bottom;
                double ratio         = ((double)portion) / distance;
                return(bottomPercentile + ((topPercentile - bottomPercentile) * ratio));
            }
            else
            {
                return(_sss[foul][jamData.PointDelta]);
            }
        }