// Gets the full game ranking entries private async Task <List <RankingDto> > GetFullGameRankingAsync(RankingRequest request) { var rankingEntries = new ConcurrentBag <RankingDto>(); var tasks = new List <Task>(); foreach (var stage in request.Game.GetStages()) { tasks.Add(Task.Run(async() => { foreach (var level in SystemExtensions.Enumerate <Level>()) { if (!request.SkipStages.Contains(stage)) { var stageLevelRankings = await GetStageLevelRankingAsync(request, stage, level) .ConfigureAwait(false); rankingEntries.AddRange(stageLevelRankings); } } })); } await Task.WhenAll(tasks).ConfigureAwait(false); return(rankingEntries.ToList()); }
private async Task <IActionResult> SimulateRankingInternalAsync( Game game, DateTime?rankingDate, long?playerId = null, int?monthsPrior = null, Stage[] skipStages = null, bool?excludeWinners = false, int?engine = null) { return(await DoAndCatchAsync( RankingViewName, "The GoldenEye/PerfectDark World Records and Rankings SIMULATOR", async() => { var rankingEntries = await GetRankingsWithParamsAsync(game, rankingDate ?? DateTime.Now, playerId, monthsPrior, skipStages, excludeWinners, engine).ConfigureAwait(false); var pointsRankingEntries = rankingEntries .Where(r => r.Rank <= MaxRankDisplay) .Select(r => r.ToPointsRankingItemData()) .ToList(); // this does not manage equality between two global times // ie one player will be ranked above/below the other one int rank = 1; var timeRankingEntries = rankingEntries .OrderBy(x => x.CumuledTime) .Take(MaxRankDisplay) .Select(r => r.ToTimeRankingItemData(rank++)) .ToList(); var secondsLevel = SystemExtensions.Enumerate <Level>().ToDictionary(l => l, l => 0); var stageWorldRecordEntries = game.GetStages() .Select(s => s.ToStageWorldRecordItemData(rankingEntries, secondsLevel, StageImagePath)) .ToList(); return new SimulatedRankingViewData { CombinedTime = new TimeSpan(0, 0, secondsLevel.Values.Sum()), EasyCombinedTime = new TimeSpan(0, 0, secondsLevel[Level.Easy]), MediumCombinedTime = new TimeSpan(0, 0, secondsLevel[Level.Medium]), HardCombinedTime = new TimeSpan(0, 0, secondsLevel[Level.Hard]), PointsRankingEntries = pointsRankingEntries, TimeRankingEntries = timeRankingEntries, StageWorldRecordEntries = stageWorldRecordEntries }; }).ConfigureAwait(false)); }
public async Task <IActionResult> GetRankingByEngineAsync( [FromRoute] Game game, [FromQuery] DateTime?rankingDate, [FromQuery] int engine) { if (!Enum.TryParse(typeof(Game), game.ToString(), out _)) { return(BadRequest()); } if (!SystemExtensions.Enumerate <Engine>().Any(e => engine == (int)e)) { return(BadRequest()); } return(await SimulateRankingInternalAsync(game, rankingDate, engine : engine) .ConfigureAwait(false)); }
private Dictionary <Level, List <long> > ExtractEntryIdListFromJsonContent(IReadOnlyCollection <IReadOnlyCollection <object> > stageJsonContent, List <string> logs) { var entryIdListByLevel = new Dictionary <Level, List <long> >(); const int positionOfId = 7; const int positionOfStart = 4; int m = 0; foreach (IReadOnlyCollection <object> jsonLevelEntries in stageJsonContent) { var entryIdList = new List <long>(); entryIdListByLevel.Add(SystemExtensions.Enumerate <Level>().ElementAt(m), entryIdList); int j = positionOfStart; foreach (object jsonEntry in jsonLevelEntries) { if (j % positionOfId == 0) { if (jsonEntry == null) { logs.Add("The JSON entry was null."); } else if (!long.TryParse(jsonEntry.ToString(), out long entryId)) { logs.Add($"The JSON entry was not a long - value: {jsonEntry}"); } else { entryIdList.Add(entryId); } } j++; } m++; } return(entryIdListByLevel); }
private async Task <EntryWebDto> ExtractTimeLinkDetailsAsync(HtmlNode link, bool withEngine) { const char linkSeparator = '-'; const string playerUrlPrefix = "/~"; string[] linkParts = CleanString(link.InnerText) .Split(linkSeparator, StringSplitOptions.RemoveEmptyEntries) .Select(s => s.Trim()) .ToArray(); if (linkParts.Length < 2) { return(null); } DateTime?date = ExtractAndCheckDate(link, out bool exit); if (exit) { return(null); } string stageName = linkParts[0].ToLowerInvariant().Replace(" ", string.Empty); if (!Extensions.StageFormatedNames.ContainsKey(stageName)) { if (stageName != Extensions.PerfectDarkDuelStageFormatedName) { throw new FormatException($"Unable to extract the stage ID."); } return(null); } string playerUrl = link .ParentNode .ParentNode .ChildNodes[3] .ChildNodes .First() .Attributes["href"] .Value .Replace(playerUrlPrefix, string.Empty) .Replace("+", " "); if (string.IsNullOrWhiteSpace(playerUrl)) { return(null); } Level?level = SystemExtensions .Enumerate <Level>() .Select(l => (Level?)l) .FirstOrDefault(l => l.Value.GetLabel(Game.GoldenEye).Equals(linkParts[1], StringComparison.InvariantCultureIgnoreCase) || l.Value.GetLabel(Game.PerfectDark).Equals(linkParts[1], StringComparison.InvariantCultureIgnoreCase)); if (!level.HasValue) { return(null); } long?time = ExtractTime(linkParts[2], out bool failToExtractTime); if (failToExtractTime || !time.HasValue) { return(null); } return(new EntryWebDto { Date = date, Level = level.Value, PlayerUrlName = playerUrl, Stage = Extensions.StageFormatedNames[stageName], Engine = withEngine ? await ExtractTimeEntryEngineAsync(link).ConfigureAwait(false) : Engine.UNK, Time = time.Value }); }
/// <inheritdoc /> public async Task <IReadOnlyCollection <StageSweep> > GetSweepsAsync( Game game, bool untied, DateTime?startDate, DateTime?endDate, Stage?stage) { if (startDate > endDate) { throw new ArgumentOutOfRangeException(nameof(startDate), startDate, $"{nameof(startDate)} is greater than {nameof(endDate)}."); } var fullEntries = new List <EntryDto>(); foreach (var locStage in game.GetStages()) { var entries = await _readRepository .GetEntriesAsync(locStage) .ConfigureAwait(false); fullEntries.AddRange(entries); } var entriesGroups = fullEntries .Where(e => e.Date.HasValue) .GroupBy(e => (e.Stage, e.Level)) .ToDictionary(e => e.Key, e => e.ToList()); var playerKeys = await GetPlayersInternalAsync().ConfigureAwait(false); var sweepsRaw = new ConcurrentBag <(long playerId, DateTime date, Stage stage)>(); var dates = SystemExtensions .LoopBetweenDates( startDate ?? Extensions.GetEliteFirstDate(game), endDate ?? ServiceProviderAccessor.ClockProvider.Now, DateStep.Day) .GroupBy(d => d.DayOfWeek) .ToDictionary(d => d.Key, d => d); var tasks = new List <Task>(); foreach (var dow in SystemExtensions.Enumerate <DayOfWeek>()) { tasks.Add(Task.Run(() => { foreach (var currentDate in dates[dow]) { foreach (var stg in game.GetStages()) { if (stage == null || stg == stage) { sweepsRaw.AddRange( GetPotentialSweeps(untied, entriesGroups, currentDate, stg)); } } } })); } await Task.WhenAll(tasks).ConfigureAwait(false); var finalSweeps = new List <StageSweep>(); foreach (var(playerId, date, locStage) in sweepsRaw.OrderBy(f => f.date)) { var sweepMatch = finalSweeps.SingleOrDefault(s => s.Player.Id == playerId && s.Stage == locStage && s.EndDate == date); if (sweepMatch == null) { sweepMatch = new StageSweep(date, locStage, playerKeys[playerId]); finalSweeps.Add(sweepMatch); } sweepMatch.AddDay(); } return(finalSweeps); }
/// <inheritdoc /> public async Task <IReadOnlyCollection <Standing> > GetLongestStandingsAsync( Game game, DateTime?endDate, StandingType standingType, bool?stillOngoing) { var standings = new List <Standing>(); var wrs = await GetWorldRecordsAsync(game, endDate).ConfigureAwait(false); foreach (var stage in game.GetStages()) { foreach (var level in SystemExtensions.Enumerate <Level>()) { var locWrs = wrs .Where(wr => wr.Stage == stage && wr.Level == level) .OrderBy(wr => wr.Date) .ThenByDescending(wr => wr.Time); Standing currentStanding = null; foreach (var locWr in locWrs) { switch (standingType) { case StandingType.Unslayed: standings.AddRange(locWr.Holders.Select(_ => new Standing(locWr.Time) { Slayer = locWr.SlayPlayer, EndDate = locWr.SlayDate, StartDate = _.Item2, Author = _.Item1, Level = level, Stage = stage })); break; case StandingType.UnslayedExceptSelf: var slayer = locWr.SlayPlayer; var holders = locWr.Holders.ToList(); if (currentStanding != null) { currentStanding.AddTime(locWr.Time); holders.RemoveAll(_ => _.Item1.Id == currentStanding.Author.Id); if (slayer == null || slayer.Id != currentStanding.Author.Id) { currentStanding.Slayer = slayer; currentStanding.EndDate = locWr.SlayDate; currentStanding = null; } } foreach (var holder in holders) { var locCurrentStanding = new Standing(locWr.Time) { StartDate = holder.Item2, Author = holder.Item1, Level = level, Stage = stage }; standings.Add(locCurrentStanding); if (slayer == null || slayer.Id != locCurrentStanding.Author.Id) { locCurrentStanding.Slayer = slayer; locCurrentStanding.EndDate = locWr.SlayDate; } else { currentStanding = locCurrentStanding; } } break; case StandingType.Untied: standings.Add(new Standing(locWr.Time) { Slayer = locWr.UntiedSlayPlayer ?? locWr.SlayPlayer, EndDate = locWr.UntiedSlayDate ?? locWr.SlayDate, StartDate = locWr.Date, Author = locWr.Player, Level = level, Stage = stage }); break; case StandingType.UntiedExceptSelf: if (currentStanding == null) { currentStanding = new Standing(locWr.Time) { StartDate = locWr.Date, Author = locWr.Player, Level = level, Stage = stage }; standings.Add(currentStanding); } currentStanding.AddTime(locWr.Time); var untiedSlayer = locWr.UntiedSlayPlayer ?? locWr.SlayPlayer; if (untiedSlayer == null || untiedSlayer.Id != currentStanding.Author.Id) { currentStanding.Slayer = untiedSlayer; currentStanding.EndDate = locWr.UntiedSlayDate ?? locWr.SlayDate; currentStanding = null; } break; case StandingType.BetweenTwoTimes: for (var i = 0; i < locWr.Holders.Count; i++) { var holder = locWr.Holders.ElementAt(i); var isLast = i == locWr.Holders.Count - 1; standings.Add(new Standing(locWr.Time) { Slayer = isLast ? locWr.SlayPlayer : locWr.Holders.ElementAt(i + 1).Item1, EndDate = isLast ? locWr.SlayDate : locWr.Holders.ElementAt(i + 1).Item2, StartDate = holder.Item2, Author = holder.Item1, Level = level, Stage = stage }); } break; } } } } var now = ServiceProviderAccessor.ClockProvider.Now; return(standings .Where(x => stillOngoing == true ? !x.EndDate.HasValue : (stillOngoing == false ? x.EndDate.HasValue : true)) .OrderByDescending(x => x.WithDays(now).Days) .ToList()); }