public async Task GetTeamWithPercentileAsync(double rank, DivisionWithCategory?divAndCat = null, Tier?tier = null)
        {
            using (Context.Channel.EnterTypingState())
            {
                if (rank < 1)
                {
                    throw new ArgumentOutOfRangeException(nameof(rank));
                }

                var teams = await ScoreRetrievalService.GetScoreboardAsync(new ScoreboardFilterInfo(divAndCat?.Division, tier, divAndCat?.Category, null)).ConfigureAwait(false);

                // teams list in descending order
                int expectedIndex           = ((int)Math.Round(((100 - rank) / 100) * teams.TeamList.Count)).Clamp(0, teams.TeamList.Count);
                ScoreboardDetails teamScore = await ScoreRetrievalService.GetDetailsAsync(teams.TeamList[expectedIndex].TeamId).ConfigureAwait(false);

                if (teamScore == null)
                {
                    throw new Exception("Error obtaining team score.");
                }

                await ReplyAsync(string.Empty,
                                 embed : ScoreEmbedBuilder.CreateTeamDetailsEmbed(teamScore,
                                                                                  completeScoreboard : await ScoreRetrievalService.GetScoreboardAsync(new ScoreboardFilterInfo(null, null)).ConfigureAwait(false),
                                                                                  peerFilter : CompetitionRoundLogicService.GetPeerFilter(ScoreRetrievalService.Round, teamScore.Summary),
                                                                                  timeZone : await Preferences.GetTimeZoneAsync(Context.Guild, Context.User).ConfigureAwait(false)).Build()).ConfigureAwait(false);
            }
        }
        public async Task ExportSummaryCommandAsync()
        {
            using (Context.Channel.EnterTypingState())
            {
                var scoreboardTask = ScoreRetrievalService.GetScoreboardAsync(ScoreboardFilterInfo.NoFilter);

                var targetWriter = new System.IO.StringWriter();
                await targetWriter.WriteLineAsync("TeamId,Division,Category,Location,Tier,ImageCount,PlayTime,Score,Warnings").ConfigureAwait(false);

                CompleteScoreboardSummary scoreboard = await scoreboardTask.ConfigureAwait(false);

                foreach (var team in scoreboard.TeamList)
                {
                    await targetWriter.WriteLineAsync($"{team.TeamId},{team.Division.ToStringCamelCaseToSpace()},{(!team.Category.HasValue ? string.Empty : team.Category.Value.ToCanonicalName())},{team.Location},{(team.Tier.HasValue ? team.Tier.Value.ToString() : string.Empty)},{team.ImageCount},{team.PlayTime.ToHoursMinutesSecondsString()},{ScoreRetrievalService.Metadata.FormattingOptions.FormatScore(team.TotalScore)},{team.Warnings.ToConciseString()}").ConfigureAwait(false);
                }

                TimeZoneInfo tz = await Preferences.GetTimeZoneAsync(Context.Guild, Context.User).ConfigureAwait(false);

                string         tzAbbr            = tz.GetAbbreviations().Generic;
                DateTimeOffset snapshotTimestamp = TimeZoneInfo.ConvertTime(scoreboard.SnapshotTimestamp, tz);
                using (var targetStream = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(targetWriter.GetStringBuilder().ToString())))
                {
                    await Context.Channel.SendFileAsync(targetStream, "scoreboard.csv", $"Scoreboard summary CSV export\nScore timestamp: {snapshotTimestamp:g} {tzAbbr}\nExported: {TimeZoneInfo.ConvertTime(DateTimeOffset.UtcNow, tz):g} {tzAbbr}").ConfigureAwait(false);
                }
            }
        }
        public async Task GenerateHistogramAsync(DivisionWithCategory?divisionWithCategory, Tier?tier, string imageName, string locCode)
        {
            using (Context.Channel.EnterTypingState())
            {
                if (imageName != null && !ScoreRetrievalService.Metadata.SupportsInexpensiveDetailQueries)
                {
                    throw new InvalidOperationException("Per-image histograms are not supported on online score providers. Use the `datasource` command to select an offline score provider.");
                }

                CompleteScoreboardSummary scoreboard = await ScoreRetrievalService.GetScoreboardAsync(new ScoreboardFilterInfo(divisionWithCategory?.Division, tier)).ConfigureAwait(false);

                decimal[] data = await scoreboard.TeamList
                                 .Conditionally(locCode != null, tle => tle.Where(t => t.Location == locCode))
                                 .Conditionally(divisionWithCategory?.Category != null, tle => tle.Where(t => t.Category == divisionWithCategory.Value.Category))
                                 .TernaryAsync(imageName == null,
                                               x => x.Select(datum => (decimal)datum.TotalScore).ToAsyncEnumerable(),
                                               x => x.Select(t => ScoreRetrievalService.GetDetailsAsync(t.TeamId))
                                               .ToTaskResultEnumerable()
                                               .Select(t => t.Images.SingleOrDefault(i => i.ImageName == imageName))
                                               .Where(i => i != null)
                                               .Select(i => (decimal)i.Score))
                                 .ToArrayAsync().ConfigureAwait(false);

                Array.Sort(data);

                Models.User userSettings = await Preferences.Database.FindOneAsync <Models.User>(u => u.Id == Context.User.Id).ConfigureAwait(false);

                ColorPresets.HistogramColorPreset histogramColorScheme = (userSettings?.DiscordTheme ?? "dark") == "light" ? ColorPresets.DiscordLight : ColorPresets.DiscordDark;

                using (var memStr = new System.IO.MemoryStream())
                {
                    await GraphProvider.WriteHistogramPngAsync(data, "Score", "Frequency", datum => datum.ToString("0.0#"), histogramColorScheme, memStr).ConfigureAwait(false);

                    memStr.Position = 0;

                    var histogramEmbed = new EmbedBuilder()
                                         .WithTitle("CyberPatriot Score Analysis")
                                         .WithDescription(Utilities.JoinNonNullNonEmpty(" | ",
                                                                                        imageName.AppendPrependIfNonEmpty("`"),
                                                                                        divisionWithCategory?.Division.ToStringCamelCaseToSpace(),
                                                                                        tier,
                                                                                        divisionWithCategory?.Category?.ToCanonicalName(),
                                                                                        LocationResolutionService.GetFullNameOrNull(locCode))
                                                          .CoalesceBlank("All Teams"))
                                         .AddInlineField("Teams", data.Length)
                                         .AddInlineField("Mean", $"{data.Average():0.##}")
                                         .AddInlineField("Standard Deviation", $"{data.StandardDeviation():0.##}")
                                         .AddInlineField("First Quartile", $"{data.Take(data.Length / 2).ToArray().Median():0.##}")
                                         .AddInlineField("Median", $"{data.Median():0.##}")
                                         .AddInlineField("Third Quartile", $"{data.Skip(data.Length / 2).ToArray().Median():0.##}")
                                         .AddInlineField("Min Score", $"{data.Min()}")
                                         .AddInlineField("Max Score", $"{data.Max()}")
                                         .WithTimestamp(scoreboard.SnapshotTimestamp)
                                         .WithFooter(ScoreRetrievalService.Metadata.StaticSummaryLine)
                                         .WithImageUrl("attachment://histogram.png"); // Discord API requirement to use the uploaded histogram

                    await Context.Channel.SendFileAsync(memStr, "histogram.png", embed : histogramEmbed.Build()).ConfigureAwait(false);
                }
            }
        }
Exemplo n.º 4
0
        public async Task GetServiceLeaderboardImplementationAsync(string category, Tier?tier, int pageNumber)
        {
            using (Context.Channel.EnterTypingState())
            {
                CompleteScoreboardSummary teamScore = await ScoreRetrievalService.GetScoreboardAsync(new ScoreboardFilterInfo(Division.AllService, tier)).ConfigureAwait(false);

                if (teamScore == null)
                {
                    throw new Exception("Error obtaining scoreboard.");
                }

                // validate category
                string realCategory = teamScore.TeamList.Where(t => CategoryEquals(t, category)).Select(t => t.Category).Distinct().SingleIfOne();
                if (realCategory == null)
                {
                    throw new ArgumentException("The given category was not found - it was either ambiguous or invalid.", nameof(category));
                }

                await ReplyAsync(ScoreEmbedBuilder.CreateTopLeaderboardEmbed(teamScore, pageNumber: pageNumber, customFilter: new ScoreboardMessageBuilderService.CustomFiltrationInfo()
                {
                    Predicate         = t => t.Category == realCategory,
                    FilterDescription = realCategory
                }, timeZone: await Preferences.GetTimeZoneAsync(Context.Guild, Context.User).ConfigureAwait(false))).ConfigureAwait(false);
            }
        }
Exemplo n.º 5
0
        public async Task GetTeamAsync(TeamId teamId)
        {
            using (Context.Channel.EnterTypingState())
            {
                ScoreboardDetails teamScore = await ScoreRetrievalService.GetDetailsAsync(teamId).ConfigureAwait(false);

                if (teamScore == null)
                {
                    throw new Exception("Error obtaining team score.");
                }
                await ReplyAsync(string.Empty, embed : ScoreEmbedBuilder.CreateTeamDetailsEmbed(teamScore, CompetitionRoundLogicService.GetRankingInformation(ScoreRetrievalService.Round, await ScoreRetrievalService.GetScoreboardAsync(new ScoreboardFilterInfo(teamScore.Summary.Division, null)).ConfigureAwait(false), teamScore.Summary)).Build()).ConfigureAwait(false);
            }
        }
Exemplo n.º 6
0
        public async Task GetLeaderboardAsync(Division division, Tier tier, int pageNumber = 1)
        {
            using (Context.Channel.EnterTypingState())
            {
                CompleteScoreboardSummary teamScore = await ScoreRetrievalService.GetScoreboardAsync(new ScoreboardFilterInfo(division, tier)).ConfigureAwait(false);

                if (teamScore == null)
                {
                    throw new Exception("Error obtaining scoreboard.");
                }
                await ReplyAsync(ScoreEmbedBuilder.CreateTopLeaderboardEmbed(teamScore, pageNumber: pageNumber, timeZone: await Preferences.GetTimeZoneAsync(Context.Guild, Context.User).ConfigureAwait(false))).ConfigureAwait(false);
            }
        }
        public async Task GetImageLeaderboardImplementationAsync(string image, string location, ServiceCategory?category, Division?division, Tier?tier, int pageNumber)
        {
            using (Context.Channel.EnterTypingState())
            {
                if (!ScoreRetrievalService.Metadata.SupportsInexpensiveDetailQueries)
                {
                    throw new InvalidOperationException("Image-specific queries cannot be performed on online score providers. Please use datasource to specify an offline score provider.");
                }

                System.Collections.Generic.IEnumerable <ScoreboardSummaryEntry> teams = (await ScoreRetrievalService.GetScoreboardAsync(new ScoreboardFilterInfo(division, tier)).ConfigureAwait(false))?.TeamList;
                if (teams == null)
                {
                    throw new Exception("Error obtaining scoreboard.");
                }

                if (category.HasValue)
                {
                    var catVal = category.Value;
                    teams = teams.Where(t => t.Category == catVal);
                }

                if (location != null)
                {
                    teams = teams.Where(t => t.Location == location);
                }

                string filterDesc = Utilities.JoinNonNullNonEmpty(", ",
                                                                  !division.HasValue ? null : division.Value.ToStringCamelCaseToSpace() + " Division",
                                                                  !tier.HasValue ? null : tier.Value.ToStringCamelCaseToSpace() + " Tier",
                                                                  !category.HasValue ? null : category.Value.ToCanonicalName(),
                                                                  LocationResolutionService.GetFullNameOrNull(location));

                var downloadTasks = teams.Select(t => ScoreRetrievalService.GetDetailsAsync(t.TeamId)).ToArray();

                try
                {
                    await Task.WhenAll(downloadTasks).ConfigureAwait(false);
                }
                catch
                {
                    // oh well?
                }

                await ReplyAsync(
                    message : ScoreEmbedBuilder.CreateImageLeaderboardEmbed(downloadTasks.Where(t => t.IsCompletedSuccessfully).Select(
                                                                                t => new System.Collections.Generic.KeyValuePair <ScoreboardSummaryEntry, ScoreboardImageDetails>(t.Result.Summary,
                                                                                                                                                                                  t.Result.Images.SingleOrDefault(i => i.ImageName.Equals(image, StringComparison.InvariantCultureIgnoreCase))))
                                                                            .Where(kvp => kvp.Value != null).OrderByDescending(kvp => kvp.Value.Score).ThenBy(kvp => kvp.Value.PlayTime),
                                                                            filterDescription: filterDesc, pageNumber: pageNumber)).ConfigureAwait(false);
            }
        }
        public async Task GetTeamAsync(TeamId teamId)
        {
            using (Context.Channel.EnterTypingState())
            {
                ScoreboardDetails teamScore = await ScoreRetrievalService.GetDetailsAsync(teamId).ConfigureAwait(false);

                if (teamScore == null)
                {
                    throw new Exception("Error obtaining team score.");
                }
                await ReplyAsync(string.Empty, embed : ScoreEmbedBuilder.CreateTeamDetailsEmbed(teamScore,
                                                                                                completeScoreboard : await ScoreRetrievalService.GetScoreboardAsync(ScoreboardFilterInfo.NoFilter).ConfigureAwait(false),
                                                                                                peerFilter : CompetitionRoundLogicService.GetPeerFilter(ScoreRetrievalService.Round, teamScore.Summary),
                                                                                                timeZone : await Preferences.GetTimeZoneAsync(Context.Guild, Context.User).ConfigureAwait(false)).Build()).ConfigureAwait(false);
            }
        }
        public async Task GeneratePeerLeaderboardAsync(TeamId team)
        {
            using (Context.Channel.EnterTypingState())
            {
                ScoreboardDetails teamDetails = await ScoreRetrievalService.GetDetailsAsync(team).ConfigureAwait(false);

                if (teamDetails == null)
                {
                    throw new Exception("Error obtaining team score.");
                }

                CompleteScoreboardSummary peerScoreboard = await ScoreRetrievalService.GetScoreboardAsync(CompetitionRoundLogicService.GetPeerFilter(ScoreRetrievalService.Round, teamDetails.Summary)).ConfigureAwait(false);

                await ReplyAsync(ScoreEmbedBuilder.CreatePeerLeaderboardEmbed(teamDetails.TeamId, peerScoreboard, timeZone: await Preferences.GetTimeZoneAsync(Context.Guild, Context.User).ConfigureAwait(false))).ConfigureAwait(false);
            }
        }
Exemplo n.º 10
0
        public async Task GetLocationLeaderboardImplementationAsync(string location, ScoreboardFilterInfo filterInfo, int pageNumber)
        {
            using (Context.Channel.EnterTypingState())
            {
                CompleteScoreboardSummary teamScore = await ScoreRetrievalService.GetScoreboardAsync(filterInfo).ConfigureAwait(false);

                if (teamScore == null)
                {
                    throw new Exception("Error obtaining scoreboard.");
                }

                await ReplyAsync(ScoreEmbedBuilder.CreateTopLeaderboardEmbed(teamScore, pageNumber: pageNumber, customFilter: new ScoreboardMessageBuilderService.CustomFiltrationInfo()
                {
                    Predicate         = t => t.Location == location,
                    FilterDescription = location // TODO full name of state?
                }, timeZone: await Preferences.GetTimeZoneAsync(Context.Guild, Context.User).ConfigureAwait(false))).ConfigureAwait(false);
            }
        }
Exemplo n.º 11
0
        public async Task GetTeamWithRankAsync(int rank, Division?division = null, Tier?tier = null)
        {
            using (Context.Channel.EnterTypingState())
            {
                if (rank < 1)
                {
                    throw new ArgumentOutOfRangeException(nameof(rank));
                }

                var teams = await ScoreRetrievalService.GetScoreboardAsync(new ScoreboardFilterInfo(division, tier)).ConfigureAwait(false);

                var team = teams.TeamList[rank - 1];
                ScoreboardDetails teamScore = await ScoreRetrievalService.GetDetailsAsync(team.TeamId).ConfigureAwait(false);

                if (teamScore == null)
                {
                    throw new Exception("Error obtaining team score.");
                }
                await ReplyAsync(string.Empty, embed : ScoreEmbedBuilder.CreateTeamDetailsEmbed(teamScore, CompetitionRoundLogicService.GetRankingInformation(ScoreRetrievalService.Round, await ScoreRetrievalService.GetScoreboardAsync(new ScoreboardFilterInfo(teamScore.Summary.Division, null)).ConfigureAwait(false), teamScore.Summary)).Build()).ConfigureAwait(false);
            }
        }
        public async Task GetTeamWithRankAsync(int rank, string location, DivisionWithCategory?divisionAndCat, Tier?tier)
        {
            using (Context.Channel.EnterTypingState())
            {
                if (rank < 1)
                {
                    throw new ArgumentOutOfRangeException(nameof(rank));
                }

                var filter = new ScoreboardFilterInfo(divisionAndCat?.Division, tier, divisionAndCat?.Category, location);

                var teams = await ScoreRetrievalService.GetScoreboardAsync(filter).ConfigureAwait(false);

                System.Collections.Generic.IEnumerable <ScoreboardSummaryEntry> teamList = teams.TeamList;


                var team = teamList.Skip(rank - 1).First();
                ScoreboardDetails teamScore = await ScoreRetrievalService.GetDetailsAsync(team.TeamId).ConfigureAwait(false);

                if (teamScore == null)
                {
                    throw new Exception("Error obtaining team score.");
                }

                string classSpec = Utilities.JoinNonNullNonEmpty(", ",
                                                                 LocationResolutionService.GetFullNameOrNull(location),
                                                                 filter.Division.HasValue ? (filter.Division.Value.ToStringCamelCaseToSpace() + " Division") : null,
                                                                 filter.Category?.ToCanonicalName(),
                                                                 tier.HasValue ? (tier.Value.ToStringCamelCaseToSpace() + " Tier") : null);

                await ReplyAsync(
                    "**" + Utilities.AppendOrdinalSuffix(rank) + " place " + (classSpec.Length == 0 ? "overall" : "in " + classSpec) + ": " + team.TeamId + "**",
                    embed : ScoreEmbedBuilder.CreateTeamDetailsEmbed(teamScore,
                                                                     completeScoreboard : await ScoreRetrievalService.GetScoreboardAsync(new ScoreboardFilterInfo(null, null)).ConfigureAwait(false),
                                                                     peerFilter : CompetitionRoundLogicService.GetPeerFilter(ScoreRetrievalService.Round, team),
                                                                     timeZone : await Preferences.GetTimeZoneAsync(Context.Guild, Context.User).ConfigureAwait(false)).Build()).ConfigureAwait(false);
            }
        }
Exemplo n.º 13
0
        // [Command(HistogramCommandName), Alias("scoregraph", "scorestats", "statistics"), Summary("Generates a histogram of the given tier's scores for the given image within the given state on the current CyberPatriot leaderboard.")]
        // [Priority(-1)]
        // public Task HistogramCommandAsync([OverrideTypeReader(typeof(LocationTypeReader))] string location, Division div, Tier tier, string imageName) => GenerateHistogramAsync(new ScoreboardFilterInfo(div, tier), imageName, location);


        public async Task GenerateHistogramAsync(ScoreboardFilterInfo filter, string imageName, string locCode)
        {
            using (Context.Channel.EnterTypingState())
            {
                var descBuilder = new System.Text.StringBuilder();
                if (filter.Division.HasValue)
                {
                    descBuilder.Append(' ').Append(filter.Division.Value.ToStringCamelCaseToSpace());
                }
                if (filter.Tier.HasValue)
                {
                    descBuilder.Append(' ').Append(filter.Tier.Value);
                }
                if (imageName != null)
                {
                    throw new NotSupportedException("Per-image histograms are not yet supported.");

                    // unreachable code - not implemented on the data-aggregation/filter side, but this code Should Work:tm: for constructing the title
#pragma warning disable 0162
                    if (descBuilder.Length > 0)
                    {
                        descBuilder.Append(": ");
                    }
                    descBuilder.Append(imageName);
#pragma warning restore 0162
                }

                CompleteScoreboardSummary scoreboard = await ScoreRetrievalService.GetScoreboardAsync(filter).ConfigureAwait(false);

                decimal[] data = scoreboard.TeamList
                                 .Conditionally(locCode != null, tle => tle.Where(t => t.Location == locCode))
                                 // nasty hack
                                 .Select(datum => decimal.TryParse(ScoreRetrievalService.Metadata.FormattingOptions.FormatScore(datum.TotalScore), out decimal d) ? d : datum.TotalScore)
                                 .OrderBy(d => d).ToArray();
                using (var memStr = new System.IO.MemoryStream())
                {
                    await GraphProvider.WriteHistogramPngAsync(data, "Score", "Frequency", datum => datum.ToString("0.0#"), BitmapProvider.Color.Parse("#32363B"), BitmapProvider.Color.Parse("#7289DA"), BitmapProvider.Color.White, BitmapProvider.Color.Gray, memStr).ConfigureAwait(false);

                    memStr.Position = 0;

                    // This shouldn't be necessary, Discord's API supports embedding attached images
                    // BUT discord.net does not, see #796
                    var httpClient       = new System.Net.Http.HttpClient();
                    var imagePostMessage = new System.Net.Http.StreamContent(memStr);
                    imagePostMessage.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/png");
                    Task <System.Net.Http.HttpResponseMessage> uploadUrlResponseTask = httpClient.PutAsync("https://transfer.sh/histogram.png", imagePostMessage);

                    var histogramEmbed = new EmbedBuilder()
                                         .WithTitle("CyberPatriot Score Analysis")
                                         .WithDescription(Utilities.JoinNonNullNonEmpty(" | ", filter.Division?.ToStringCamelCaseToSpace(), filter.Tier, locCode).CoalesceBlank("All Teams"))
                                         .AddInlineField("Teams", data.Length)
                                         .AddInlineField("Mean", $"{data.Average():0.##}")
                                         .AddInlineField("Standard Deviation", $"{data.StandardDeviation():0.##}")
                                         .AddInlineField("First Quartile", $"{data.Take(data.Length / 2).ToArray().Median():0.##}")
                                         .AddInlineField("Median", $"{data.Median():0.##}")
                                         .AddInlineField("Third Quartile", $"{data.Skip(data.Length / 2).ToArray().Median():0.##}")
                                         .AddInlineField("Min Score", $"{data.Min()}")
                                         .AddInlineField("Max Score", $"{data.Max()}")
                                         .WithImageUrl(await(await uploadUrlResponseTask.ConfigureAwait(false)).Content.ReadAsStringAsync().ConfigureAwait(false))
                                         .WithTimestamp(scoreboard.SnapshotTimestamp)
                                         .WithFooter(ScoreRetrievalService.Metadata.StaticSummaryLine);

                    await Context.Channel.SendMessageAsync("", embed : histogramEmbed).ConfigureAwait(false);
                }
            }
        }