예제 #1
0
        // 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
            });
        }
예제 #6
0
        /// <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);
        }
예제 #7
0
        /// <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());
        }