public override void Calculate(LeagueDbContext dbContext) { if (ScoringTable == null) { return; } // Get standings var standings = ScoringTable.GetSeasonStandings(dbContext); // Get all connected scorings var scorings = ScoringTable.Scorings; // Get all scored races var scoredRaces = scorings.SelectMany(x => x.GetAllSessions().Where(y => y.SessionResult != null).Select(y => new { x, y })).GroupBy(x => x.x, x => x.y); // Get races that need recalculation and recalculate results scoredRaces.ForEach(x => x.Where(y => y.SessionResult.RequiresRecalculation).ForEach(y => x.Key.CalculateResults(y.SessionId, dbContext))); // Get all scored resultrows and group by driver var scoredResultsRows = scorings.SelectMany(x => x.ScoredResults).SelectMany(x => x.FinalResults).OrderBy(x => x.ResultRow.Date).GroupBy(x => x.ResultRow.Member); if (DriverStatistic == null) { DriverStatistic = new List <DriverStatisticRowEntity>(); } List <DriverStatisticRowEntity> removeDriverStatisticRows = DriverStatistic.ToList(); // Calculate common season statistics FinishedRaces = scoredRaces.Count(); IsSeasonFinished = Season.Finished; // Calculate statistics per driver foreach (var memberResultRows in scoredResultsRows) { var member = memberResultRows.Key; var memberStandingsRow = standings.StandingsRows.SingleOrDefault(x => x.Member.MemberId == member.MemberId); DriverStatisticRowEntity driverStatRow; if (DriverStatistic.Any(x => x.Member == member)) { driverStatRow = DriverStatistic.SingleOrDefault(x => x.Member == member); driverStatRow.ResetStatistic(); removeDriverStatisticRows.Remove(driverStatRow); } else { driverStatRow = new DriverStatisticRowEntity() { Member = member }; DriverStatistic.Add(driverStatRow); } if (memberResultRows.Count() == 0) { continue; } driverStatRow.CurrentSeasonPosition = (standings.StandingsRows.SingleOrDefault(x => x.Member.MemberId == member.MemberId)?.Position).GetValueOrDefault(99999); // Calculate accumulative statistics foreach (var resultRow in memberResultRows) { var result = resultRow.ResultRow.Result; driverStatRow.CompletedLaps += resultRow.ResultRow.CompletedLaps; driverStatRow.DrivenKm += resultRow.ResultRow.CompletedLaps * resultRow.ResultRow.Result.IRSimSessionDetails?.KmDistPerLap ?? 0; driverStatRow.FastestLaps += resultRow.ScoredResult.FastestLapDriver == member ? 1 : 0; driverStatRow.Incidents += resultRow.ResultRow.Incidents; driverStatRow.LeadingKm += resultRow.ResultRow.LeadLaps * resultRow.ResultRow.Result.IRSimSessionDetails?.KmDistPerLap ?? 0; driverStatRow.LeadingLaps += resultRow.ResultRow.LeadLaps; driverStatRow.PenaltyPoints += resultRow.PenaltyPoints; driverStatRow.Poles += resultRow.ResultRow.StartPosition == 1 ? 1 : 0; driverStatRow.Races += 1; driverStatRow.RacesCompleted += resultRow.ResultRow.Status == iRLeagueManager.Enums.RaceStatusEnum.Running ? 1 : 0; driverStatRow.RacesInPoints += resultRow.RacePoints > 0 ? 1 : 0; driverStatRow.Top10 += resultRow.FinalPosition <= 10 ? 1 : 0; driverStatRow.Top15 += resultRow.FinalPosition <= 15 ? 1 : 0; driverStatRow.Top20 += resultRow.FinalPosition <= 20 ? 1 : 0; driverStatRow.Top25 += resultRow.FinalPosition <= 25 ? 1 : 0; driverStatRow.Top3 += resultRow.FinalPosition <= 3 ? 1 : 0; driverStatRow.Top5 += resultRow.FinalPosition <= 5 ? 1 : 0; driverStatRow.Wins += resultRow.FinalPosition == 1 ? 1 : 0; driverStatRow.RacePoints += resultRow.RacePoints; driverStatRow.TotalPoints += resultRow.TotalPoints; driverStatRow.BonusPoints += resultRow.BonusPoints; driverStatRow.HardChargerAwards += resultRow.ScoredResult.HardChargers.Contains(member) ? 1 : 0; driverStatRow.CleanestDriverAwards += resultRow.ScoredResult.CleanestDrivers.Contains(member) ? 1 : 0; driverStatRow.IncidentsWithPenalty += (resultRow.ReviewPenalties?.Count).GetValueOrDefault(); } // Quick fix for penalty points // driverStatRow.PenaltyPoints = driverStatRow.RacePoints + driverStatRow.BonusPoints - driverStatRow.TotalPoints; // Calculate min/max statistics driverStatRow.BestFinalPosition = memberResultRows.Min(x => x.FinalPosition); driverStatRow.BestFinishPosition = memberResultRows.Min(x => x.ResultRow.FinishPosition); driverStatRow.BestStartPosition = memberResultRows.Min(x => x.ResultRow.StartPosition); driverStatRow.WorstFinalPosition = memberResultRows.Max(x => x.FinalPosition); driverStatRow.WorstFinishPosition = memberResultRows.Max(x => x.ResultRow.FinishPosition); driverStatRow.WorstStartPosition = memberResultRows.Max(x => x.ResultRow.StartPosition); // Calculate start/end statistics var firstResult = memberResultRows.First(); var lastResult = memberResultRows.Last(); driverStatRow.FirstResult = firstResult; driverStatRow.LastResult = lastResult; driverStatRow.FirstRace = memberResultRows.Select(x => x.ScoredResult.Result.Session).OfType <RaceSessionEntity>().FirstOrDefault(); driverStatRow.FirstRaceDate = driverStatRow.FirstRace?.Date; driverStatRow.FirstRaceFinalPosition = firstResult.FinalPosition; driverStatRow.FirstRaceFinishPosition = firstResult.ResultRow.FinishPosition; driverStatRow.FirstRaceStartPosition = firstResult.ResultRow.StartPosition; driverStatRow.FirstSession = memberResultRows.Select(x => x.ScoredResult.Result.Session).FirstOrDefault(); driverStatRow.FirstSessionDate = driverStatRow.FirstSession?.Date; driverStatRow.LastRace = memberResultRows.Select(x => x.ScoredResult.Result.Session).OfType <RaceSessionEntity>().LastOrDefault(); driverStatRow.LastRaceDate = driverStatRow.LastRace?.Date; driverStatRow.LastRaceFinalPosition = lastResult.FinalPosition; driverStatRow.LastRaceFinishPosition = lastResult.ResultRow.FinishPosition; driverStatRow.LastRaceStartPosition = lastResult.ResultRow.StartPosition; driverStatRow.LastSession = memberResultRows.Select(x => x.ScoredResult.Result.Session).LastOrDefault(); driverStatRow.LastSessionDate = driverStatRow.LastSession?.Date; driverStatRow.StartIRating = firstResult.ResultRow.OldIRating; driverStatRow.EndIRating = lastResult.ResultRow.NewIRating; driverStatRow.StartSRating = firstResult.ResultRow.OldSafetyRating; driverStatRow.EndSRating = lastResult.ResultRow.NewSafetyRating; driverStatRow.CurrentSeasonPosition = memberStandingsRow?.Position ?? 0; driverStatRow.Titles = IsSeasonFinished && driverStatRow.CurrentSeasonPosition == 1 ? 1 : 0; // Calculate average statistics driverStatRow.AvgFinalPosition = memberResultRows.Average(x => x.FinalPosition); driverStatRow.AvgFinishPosition = memberResultRows.Average(x => x.ResultRow.FinishPosition); driverStatRow.AvgIncidentsPerKm = ((double)driverStatRow.Incidents / driverStatRow.DrivenKm).GetZeroWhenInvalid(); driverStatRow.AvgIncidentsPerLap = ((double)driverStatRow.Incidents / driverStatRow.CompletedLaps).GetZeroWhenInvalid(); driverStatRow.AvgIncidentsPerRace = ((double)driverStatRow.Incidents / driverStatRow.Races).GetZeroWhenInvalid(); driverStatRow.AvgIRating = memberResultRows.Average(x => x.ResultRow.NewIRating); driverStatRow.AvgPenaltyPointsPerKm = ((double)driverStatRow.PenaltyPoints / driverStatRow.DrivenKm).GetZeroWhenInvalid(); driverStatRow.AvgPenaltyPointsPerLap = ((double)driverStatRow.PenaltyPoints / driverStatRow.CompletedLaps).GetZeroWhenInvalid(); driverStatRow.AvgPenaltyPointsPerRace = ((double)driverStatRow.PenaltyPoints / driverStatRow.Races).GetZeroWhenInvalid(); driverStatRow.AvgPointsPerRace = ((double)driverStatRow.TotalPoints / driverStatRow.Races).GetZeroWhenInvalid(); driverStatRow.AvgSRating = memberResultRows.Average(x => x.ResultRow.NewSafetyRating); driverStatRow.AvgStartPosition = memberResultRows.Average(x => x.ResultRow.StartPosition); } // Remove rows of drivers that are not in the current statistic set anymore removeDriverStatisticRows.ForEach(x => DriverStatistic.Remove(x)); }
/// <summary> /// Calculate statistic data based on the current data set. /// <para>Make sure either lazy-loading is enabled on the context or run <see cref="LoadRequiredDataAsync(LeagueDbContext, bool)"/> before execution.</para> /// </summary> /// <param name="dbContext">Database context from EntityFramework</param> public override void Calculate(LeagueDbContext dbContext) { // Fix penalty points sign foreach (var statistic in StatisticSets.OfType <ImportedStatisticSetEntity>()) { statistic.DriverStatistic.Where(x => x.PenaltyPoints < 0).ForEach(x => x.PenaltyPoints *= -1); } // Get all statistic rows and group them by member var seasonStatisticRows = StatisticSets.SelectMany(x => x.DriverStatistic).GroupBy(x => x.Member); List <DriverStatisticRowEntity> removeDriverStatisticRows = DriverStatistic.ToList(); foreach (var memberStatisticRows in seasonStatisticRows) { var member = memberStatisticRows.Key; DriverStatisticRowEntity driverStatRow; if (DriverStatistic.Any(x => x.Member == member)) { driverStatRow = DriverStatistic.SingleOrDefault(x => x.Member == member); driverStatRow.ResetStatistic(); removeDriverStatisticRows.Remove(driverStatRow); } else { driverStatRow = new DriverStatisticRowEntity() { Member = member }; DriverStatistic.Add(driverStatRow); } // Calculate accumulative statistics foreach (var statisticRow in memberStatisticRows) { driverStatRow.CompletedLaps += statisticRow.CompletedLaps; driverStatRow.DrivenKm += statisticRow.DrivenKm; driverStatRow.FastestLaps += statisticRow.FastestLaps; driverStatRow.Incidents += statisticRow.Incidents; driverStatRow.LeadingKm += statisticRow.LeadingKm; driverStatRow.LeadingLaps += statisticRow.LeadingLaps; driverStatRow.PenaltyPoints += statisticRow.PenaltyPoints; driverStatRow.Poles += statisticRow.Poles; driverStatRow.Races += statisticRow.Races; driverStatRow.RacesCompleted += statisticRow.RacesCompleted; driverStatRow.RacesInPoints += statisticRow.RacesInPoints; driverStatRow.Top10 += statisticRow.Top10; driverStatRow.Top15 += statisticRow.Top15; driverStatRow.Top20 += statisticRow.Top20; driverStatRow.Top25 += statisticRow.Top25; driverStatRow.Top3 += statisticRow.Top3; driverStatRow.Top5 += statisticRow.Top5; driverStatRow.Wins += statisticRow.Wins; driverStatRow.RacePoints += statisticRow.RacePoints; driverStatRow.TotalPoints += statisticRow.TotalPoints; driverStatRow.BonusPoints += statisticRow.BonusPoints; driverStatRow.HardChargerAwards += statisticRow.HardChargerAwards; driverStatRow.CleanestDriverAwards += statisticRow.CleanestDriverAwards; driverStatRow.Titles += statisticRow.Titles; } // Calculate min/max statistics driverStatRow.BestFinalPosition = memberStatisticRows.Min(x => x.BestFinalPosition); driverStatRow.BestFinishPosition = memberStatisticRows.Min(x => x.BestFinishPosition); driverStatRow.BestStartPosition = memberStatisticRows.Min(x => x.BestStartPosition); driverStatRow.WorstFinalPosition = memberStatisticRows.Max(x => x.WorstFinalPosition); driverStatRow.WorstFinishPosition = memberStatisticRows.Max(x => x.WorstFinishPosition); driverStatRow.WorstStartPosition = memberStatisticRows.Max(x => x.WorstStartPosition); // Calculate start/end statistics var firstResultRow = memberStatisticRows.OrderBy(x => x.FirstRaceDate).FirstOrDefault(); var lastResultRow = memberStatisticRows.OrderBy(x => x.LastRaceDate).LastOrDefault(); driverStatRow.FirstResult = firstResultRow.FirstResult; driverStatRow.LastResult = lastResultRow.LastResult; driverStatRow.FirstRace = firstResultRow.FirstRace; driverStatRow.FirstRaceDate = memberStatisticRows.Min(x => x.FirstRaceDate); driverStatRow.FirstRaceFinalPosition = firstResultRow.FirstRaceFinalPosition; driverStatRow.FirstRaceFinishPosition = firstResultRow.FirstRaceFinishPosition; driverStatRow.FirstRaceStartPosition = firstResultRow.FirstRaceStartPosition; driverStatRow.FirstSession = memberStatisticRows.Select(x => x.FirstSession).Where(x => x != null).OrderBy(x => x.Date).FirstOrDefault(); driverStatRow.FirstSessionDate = memberStatisticRows.Min(x => x.FirstSessionDate); driverStatRow.LastRace = lastResultRow.LastRace; driverStatRow.LastRaceDate = memberStatisticRows.Max(x => x.LastRaceDate); driverStatRow.LastRaceFinalPosition = lastResultRow.LastRaceFinalPosition; driverStatRow.LastRaceFinishPosition = lastResultRow.LastRaceFinishPosition; driverStatRow.LastRaceStartPosition = lastResultRow.LastRaceStartPosition; driverStatRow.LastSession = memberStatisticRows.Select(x => x.LastSession).Where(x => x != null).LastOrDefault(); driverStatRow.LastSessionDate = memberStatisticRows.Max(x => x.LastSessionDate); driverStatRow.StartIRating = firstResultRow.StartIRating; driverStatRow.EndIRating = lastResultRow.EndIRating; driverStatRow.StartSRating = firstResultRow.StartSRating; driverStatRow.EndSRating = lastResultRow.EndSRating; driverStatRow.CurrentSeasonPosition = lastResultRow.CurrentSeasonPosition; // Calculate average statistics driverStatRow.AvgFinalPosition = memberStatisticRows.WeightedAverage(x => x.AvgFinalPosition, x => x.Races); driverStatRow.AvgFinishPosition = memberStatisticRows.WeightedAverage(x => x.AvgFinishPosition, x => x.Races); driverStatRow.AvgIncidentsPerKm = (driverStatRow.Incidents / driverStatRow.DrivenKm).GetZeroWhenInvalid(); driverStatRow.AvgIncidentsPerLap = ((double)driverStatRow.Incidents / driverStatRow.CompletedLaps).GetZeroWhenInvalid(); driverStatRow.AvgIncidentsPerRace = ((double)driverStatRow.Incidents / driverStatRow.Races).GetZeroWhenInvalid(); driverStatRow.AvgIRating = memberStatisticRows.WeightedAverage(x => x.AvgIRating, x => x.Races); driverStatRow.AvgPenaltyPointsPerKm = (driverStatRow.PenaltyPoints / driverStatRow.DrivenKm).GetZeroWhenInvalid(); driverStatRow.AvgPenaltyPointsPerLap = ((double)driverStatRow.PenaltyPoints / driverStatRow.CompletedLaps).GetZeroWhenInvalid(); driverStatRow.AvgPenaltyPointsPerRace = ((double)driverStatRow.PenaltyPoints / driverStatRow.Races).GetZeroWhenInvalid(); driverStatRow.AvgPointsPerRace = ((double)driverStatRow.TotalPoints / driverStatRow.Races).GetZeroWhenInvalid(); driverStatRow.AvgSRating = memberStatisticRows.WeightedAverage(x => x.AvgSRating, x => x.Races); driverStatRow.AvgStartPosition = memberStatisticRows.WeightedAverage(x => x.AvgStartPosition, x => x.Races); } // Calculate current champ var seasonStatisticSets = StatisticSets.OfType <SeasonStatisticSetEntity>().Where(x => x.IsSeasonFinished); var importedStatisticSets = StatisticSets.OfType <ImportedStatisticSetEntity>(); var lastSeasonStatistic = seasonStatisticSets.OrderBy(x => x.Season.SeasonEnd).LastOrDefault(); var lastImportedStatistic = importedStatisticSets.OrderBy(x => x.LastDate).LastOrDefault(); if (lastSeasonStatistic?.Season.SeasonEnd >= lastImportedStatistic?.LastDate) { CurrentChamp = lastSeasonStatistic?.DriverStatistic?.SingleOrDefault(x => x.CurrentSeasonPosition == 1)?.Member; } else { CurrentChamp = lastImportedStatistic?.DriverStatistic?.SingleOrDefault(x => x.CurrentSeasonPosition == 1)?.Member; } DriverStatistic.Remove(removeDriverStatisticRows); }