private string GetImageLeaderboardEntry(ScoreboardSummaryEntry team, ScoreboardImageDetails image, int friendlyIndex, bool useAbbreviatedDivision = false, string prefix = "#") { string divisionFormatString = useAbbreviatedDivision ? "{0,6}" : " {0,-10}"; string vulnPenString = new string(' ', 10); if (ScoreFormattingOptions.EvaluateNumericDisplay(ScoreRetrieverMetadata.FormattingOptions.VulnerabilityDisplay, image.VulnerabilitiesFound, image.VulnerabilitiesRemaining)) { vulnPenString = $"{image.VulnerabilitiesFound,5}v {image.Penalties,2}p"; } return($"{prefix}{friendlyIndex,-5}{team.TeamId,-7}{team.Location,4}" + string.Format(divisionFormatString, AbbreviateDivision(team)) + $"{team.Tier,10}" + $"{ScoreRetrieverMetadata.FormattingOptions.FormatScoreForLeaderboard(image.Score),13}" + vulnPenString + $"{(ScoreFormattingOptions.EvaluateNumericDisplay(ScoreRetrieverMetadata.FormattingOptions.TimeDisplay, image.PlayTime) ? image.PlayTime.ToHoursMinutesSecondsString() : ""),7}" + $"{image.Warnings.ToConciseString(),4}"); }
public EmbedBuilder CreateTeamDetailsEmbed(ScoreboardDetails teamScore, TeamDetailRankingInformation rankingData = null) { if (teamScore == null) { throw new ArgumentNullException(nameof(teamScore)); } var builder = new EmbedBuilder() .WithTimestamp(teamScore.SnapshotTimestamp) .WithTitle("Team " + teamScore.TeamId) .WithDescription(Utilities.JoinNonNullNonEmpty(" | ", CompetitionLogic.GetEffectiveDivisionDescriptor(teamScore.Summary), teamScore.Summary.Tier, teamScore.Summary.Location)) .WithFooter(ScoreRetrieverMetadata.StaticSummaryLine); if (!string.IsNullOrWhiteSpace(teamScore.Comment)) { builder.Description += "\n"; builder.Description += teamScore.Comment; } // scoreboard link if (teamScore.OriginUri != null) { builder.Url = teamScore.OriginUri.ToString(); } // location -> flag in thumbnail string flagUrl = FlagProvider.GetFlagUri(teamScore.Summary.Location); if (flagUrl != null) { builder.ThumbnailUrl = flagUrl; } // tier -> color on side // colors borrowed from AFA's spreadsheet if (teamScore.Summary.Tier.HasValue) { switch (teamScore.Summary.Tier.Value) { case Tier.Platinum: // tweaked from AFA spreadsheet to be more distinct from silver // AFA original is #DAE3F3 builder.WithColor(183, 201, 243); break; case Tier.Gold: builder.WithColor(0xFF, 0xE6, 0x99); break; case Tier.Silver: builder.WithColor(0xF2, 0xF2, 0xF2); break; } } // TODO image lookup for location? e.g. thumbnail with flag? foreach (var item in teamScore.Images) { string penaltyAppendage = item.Penalties != 0 ? " - " + Utilities.Pluralize("penalty", item.Penalties) : string.Empty; bool overtime = (item.Warnings & ScoreWarnings.TimeOver) == ScoreWarnings.TimeOver; bool multiimage = (item.Warnings & ScoreWarnings.MultiImage) == ScoreWarnings.MultiImage; string warningAppendage = string.Empty; const string multiImageStr = "**M**ulti-image"; const string overTimeStr = "**T**ime"; if (overtime || multiimage) { warningAppendage = " Penalties: "; } if (overtime && multiimage) { warningAppendage += multiImageStr + ", " + overTimeStr; } else if (overtime || multiimage) { warningAppendage += multiimage ? multiImageStr : overTimeStr; } string vulnsString = ScoreFormattingOptions.EvaluateNumericDisplay(ScoreRetrieverMetadata.FormattingOptions.VulnerabilityDisplay, item.VulnerabilitiesFound, item.VulnerabilitiesRemaining + item.VulnerabilitiesFound) ? $" ({item.VulnerabilitiesFound}/{item.VulnerabilitiesFound + item.VulnerabilitiesRemaining} vulns{penaltyAppendage})" : string.Empty; string playTimeStr = ScoreFormattingOptions.EvaluateNumericDisplay(ScoreRetrieverMetadata.FormattingOptions.TimeDisplay, item.PlayTime) ? $" in {item.PlayTime:hh\\:mm}" : string.Empty; builder.AddField('`' + item.ImageName + $": {ScoreRetrieverMetadata.FormattingOptions.FormatScore(item.Score)}pts`", $"{ScoreRetrieverMetadata.FormattingOptions.FormatScore(item.Score)} points{vulnsString}{playTimeStr}{warningAppendage}"); } string totalScoreTimeAppendage = string.Empty; if (ScoreFormattingOptions.EvaluateNumericDisplay(ScoreRetrieverMetadata.FormattingOptions.TimeDisplay, teamScore.Summary.PlayTime)) { totalScoreTimeAppendage = $" in {teamScore.Summary.PlayTime:hh\\:mm}"; } string totalPointsAppendage = string.Empty; if (teamScore.Images.All(i => i.PointsPossible != -1)) { totalPointsAppendage = "\n" + ScoreRetrieverMetadata.FormattingOptions.FormatScore(teamScore.Images.Sum(i => i.PointsPossible)) + " points possible"; } builder.AddInlineField("Total Score", $"{ScoreRetrieverMetadata.FormattingOptions.FormatScore(teamScore.Summary.TotalScore)} points" + totalScoreTimeAppendage + totalPointsAppendage); if (rankingData != null) { int myIndexInPeerList = rankingData.PeerIndex; double rawPercentile = 1.0 - ((myIndexInPeerList + 1.0) / rankingData.PeerCount); int multipliedPercentile = (int)Math.Round(rawPercentile * 1000); int intPart = multipliedPercentile / 10; int floatPart = multipliedPercentile % 10; builder.AddInlineField("Rank", $"{Utilities.AppendOrdinalSuffix(myIndexInPeerList + 1)} place\n{(floatPart == 0 ? Utilities.AppendOrdinalSuffix(intPart) : $"{intPart}.{Utilities.AppendOrdinalSuffix(floatPart)}")} percentile"); StringBuilder marginBuilder = new StringBuilder(); if (myIndexInPeerList > 0) { int marginUnderFirst = rankingData.Peers[0].TotalScore - teamScore.Summary.TotalScore; marginBuilder.AppendLine($"{ScoreRetrieverMetadata.FormattingOptions.FormatLabeledScoreDifference(marginUnderFirst)} under 1st place"); } if (myIndexInPeerList >= 2) { int marginUnderAbove = rankingData.Peers[myIndexInPeerList - 1].TotalScore - teamScore.Summary.TotalScore; marginBuilder.AppendLine($"{ScoreRetrieverMetadata.FormattingOptions.FormatLabeledScoreDifference(marginUnderAbove)} under {Utilities.AppendOrdinalSuffix(myIndexInPeerList)} place"); } if (myIndexInPeerList < rankingData.PeerCount - 1) { int marginAboveUnder = teamScore.Summary.TotalScore - rankingData.Peers[myIndexInPeerList + 1].TotalScore; marginBuilder.AppendLine($"{ScoreRetrieverMetadata.FormattingOptions.FormatLabeledScoreDifference(marginAboveUnder)} above {Utilities.AppendOrdinalSuffix(myIndexInPeerList + 2)} place"); } // TODO division- and round-specific margins builder.AddInlineField("Margin", marginBuilder.ToString()); StringBuilder standingFieldBuilder = new StringBuilder(); standingFieldBuilder.AppendLine(Utilities.AppendOrdinalSuffix(myIndexInPeerList + 1) + " of " + Utilities.Pluralize("peer team", rankingData.PeerCount)); // non-peer rankings use parentheticals - peer rankings are used for the rest of the logic // if peer teams != div+tier teams if (rankingData.PeerCount != rankingData.TierCount) { // tier ranking, differing from peer ranking standingFieldBuilder.AppendLine(Utilities.AppendOrdinalSuffix(rankingData.TierIndex + 1) + " of " + Utilities.Pluralize("team", rankingData.TierCount) + " in tier"); } if (rankingData.PeerCount != rankingData.DivisionCount) { // division ranking, differing from peer ranking standingFieldBuilder.AppendLine(Utilities.AppendOrdinalSuffix(rankingData.DivisionIndex + 1) + " of " + Utilities.Pluralize("team", rankingData.DivisionCount) + " in division"); } builder.AddInlineField("Standing", standingFieldBuilder.ToString()); }
public EmbedBuilder CreateTeamDetailsEmbed(ScoreboardDetails teamScore, CompleteScoreboardSummary completeScoreboard = null, ScoreboardFilterInfo peerFilter = default(ScoreboardFilterInfo), TimeZoneInfo timeZone = null) { if (teamScore == null) { throw new ArgumentNullException(nameof(teamScore)); } var builder = new EmbedBuilder() .WithTimestamp(teamScore.SnapshotTimestamp) .WithTitle("Team " + teamScore.TeamId) .WithDescription(Utilities.JoinNonNullNonEmpty(" | ", CompetitionLogic.GetEffectiveDivisionDescriptor(teamScore.Summary), teamScore.Summary.Tier, LocationResolution.GetFullName(teamScore.Summary.Location))) .WithFooter(ScoreRetrieverMetadata.StaticSummaryLine); if (!string.IsNullOrWhiteSpace(teamScore.Comment)) { builder.Description += "\n"; builder.Description += teamScore.Comment; } // scoreboard link if (teamScore.OriginUri != null) { builder.Url = teamScore.OriginUri.ToString(); } // location -> flag in thumbnail Uri flagUrl = LocationResolution?.GetFlagUriOrNull(teamScore.Summary.Location); if (flagUrl != null) { builder.ThumbnailUrl = flagUrl.ToString(); } // tier -> color on side // colors borrowed from AFA's spreadsheet if (teamScore.Summary.Tier.HasValue) { switch (teamScore.Summary.Tier.Value) { case Tier.Platinum: // tweaked from AFA spreadsheet to be more distinct from silver // AFA original is #DAE3F3 builder.WithColor(183, 201, 243); break; case Tier.Gold: builder.WithColor(0xFF, 0xE6, 0x99); break; case Tier.Silver: // tweaked from AFA spreadsheet to be more distinct from platinum, and to look less white // AFA original is #F2F2F2 builder.WithColor(0x90, 0x90, 0x90); break; } } // TODO image lookup for location? e.g. thumbnail with flag? foreach (var item in teamScore.Images) { string penaltyAppendage = item.Penalties != 0 ? " - " + Utilities.Pluralize("penalty", item.Penalties) : string.Empty; bool overtime = (item.Warnings & ScoreWarnings.TimeOver) == ScoreWarnings.TimeOver; bool multiimage = (item.Warnings & ScoreWarnings.MultiImage) == ScoreWarnings.MultiImage; string warningAppendage = string.Empty; const string multiImageStr = "**M**ulti-instance"; const string overTimeStr = "**T**ime"; if (overtime || multiimage) { warningAppendage = "\nWarnings: "; } if (overtime && multiimage) { warningAppendage += multiImageStr + ", " + overTimeStr; } else if (overtime || multiimage) { warningAppendage += multiimage ? multiImageStr : overTimeStr; } string vulnsString = ScoreFormattingOptions.EvaluateNumericDisplay(ScoreRetrieverMetadata.FormattingOptions.VulnerabilityDisplay, item.VulnerabilitiesFound, item.VulnerabilitiesRemaining + item.VulnerabilitiesFound) ? $" ({item.VulnerabilitiesFound}/{item.VulnerabilitiesFound + item.VulnerabilitiesRemaining} vulns{penaltyAppendage})" : string.Empty; string playTimeStr = ScoreFormattingOptions.EvaluateNumericDisplay(ScoreRetrieverMetadata.FormattingOptions.TimeDisplay, item.PlayTime) ? $" in {item.PlayTime.ToHoursMinutesSecondsString()}" : string.Empty; builder.AddField('`' + item.ImageName + $": {ScoreRetrieverMetadata.FormattingOptions.FormatScore(item.Score)}pts`", $"{ScoreRetrieverMetadata.FormattingOptions.FormatScore(item.Score)} points{vulnsString}{playTimeStr}{warningAppendage}"); } string totalScoreTimeAppendage = string.Empty; if (ScoreFormattingOptions.EvaluateNumericDisplay(ScoreRetrieverMetadata.FormattingOptions.TimeDisplay, teamScore.Summary.PlayTime)) { totalScoreTimeAppendage = $" in {teamScore.Summary.PlayTime.ToHoursMinutesSecondsString()}"; } string totalPointsAppendage = string.Empty; if (teamScore.Images.All(i => i.PointsPossible != -1)) { totalPointsAppendage = "\n" + ScoreRetrieverMetadata.FormattingOptions.FormatScore(teamScore.Images.Sum(i => i.PointsPossible)) + " points possible"; } builder.AddInlineField("Total Score", $"{ScoreRetrieverMetadata.FormattingOptions.FormatScore(teamScore.Summary.TotalScore)} points" + totalScoreTimeAppendage + totalPointsAppendage); if (teamScore.Summary.Warnings != 0) { string warningsOverview = null; if ((teamScore.Summary.Warnings & ScoreWarnings.MultiImage) == ScoreWarnings.MultiImage) { warningsOverview = "Multiple Instances"; } if ((teamScore.Summary.Warnings & ScoreWarnings.TimeOver) == ScoreWarnings.TimeOver) { if (warningsOverview == null) { warningsOverview = ""; } else { warningsOverview += "\n"; } warningsOverview += "Time Limit Exceeded"; } builder.AddInlineField("Warnings", warningsOverview); } var timingFieldBuilder = new StringBuilder(); if (ScoreFormattingOptions.EvaluateNumericDisplay(ScoreRetrieverMetadata.FormattingOptions.TimeDisplay, teamScore.ScoreTime)) { if (timingFieldBuilder.Length > 0) { timingFieldBuilder.AppendLine(); } timingFieldBuilder.AppendFormat("Score achieved in {0}", teamScore.ScoreTime.ToHoursMinutesSecondsString()); } DateTimeOffset?maxImageTime = null; if (teamScore.ImageScoresOverTime != null) { foreach (var dto in teamScore.ImageScoresOverTime.Select(x => x.Value.Keys.Last())) { if (!maxImageTime.HasValue || dto > maxImageTime.Value) { maxImageTime = dto; } } } if (maxImageTime.HasValue) { if (timingFieldBuilder.Length > 0) { timingFieldBuilder.AppendLine(); } timingFieldBuilder.Append("Score last updated:"); timingFieldBuilder.AppendLine().Append("\u00A0\u00A0"); //NBSP x2 if (DateTimeOffset.UtcNow - maxImageTime.Value < TimeSpan.FromDays(1)) { timingFieldBuilder.Append((DateTimeOffset.UtcNow - maxImageTime.Value).ToLongString(showSeconds: false)).Append(" ago"); } else { DateTimeOffset timestamp = timeZone == null ? maxImageTime.Value : TimeZoneInfo.ConvertTime(maxImageTime.Value, timeZone); timingFieldBuilder.AppendFormat("{0:g} ", timestamp); timingFieldBuilder.Append(TimeZoneNames.TZNames.GetAbbreviationsForTimeZone(timeZone.Id, "en-US").Generic.Replace("UTC Time", "UTC")); } } if (timingFieldBuilder.Length > 0) { builder.AddInlineField("Timing", timingFieldBuilder.ToString()); } if (completeScoreboard != null) { var peerList = completeScoreboard.Clone().WithFilter(peerFilter).TeamList; int myIndexInPeerList = peerList.IndexOfWhere(x => x.TeamId == teamScore.TeamId); double rawPercentile = 1.0 - ((myIndexInPeerList + 1.0) / peerList.Count); int multipliedPercentile = (int)Math.Round(rawPercentile * 1000); int intPart = multipliedPercentile / 10; int floatPart = multipliedPercentile % 10; builder.AddInlineField("Rank", $"{Utilities.AppendOrdinalSuffix(myIndexInPeerList + 1)} place\n{(floatPart == 0 ? Utilities.AppendOrdinalSuffix(intPart) : $"{intPart}.{Utilities.AppendOrdinalSuffix(floatPart)}")} percentile"); StringBuilder marginBuilder = new StringBuilder(); if (myIndexInPeerList > 0) { double marginUnderFirst = peerList[0].TotalScore - teamScore.Summary.TotalScore; marginBuilder.AppendLine($"{ScoreRetrieverMetadata.FormattingOptions.FormatLabeledScoreDifference(marginUnderFirst)} under 1st place"); } if (myIndexInPeerList >= 2) { double marginUnderAbove = peerList[myIndexInPeerList - 1].TotalScore - teamScore.Summary.TotalScore; marginBuilder.AppendLine($"{ScoreRetrieverMetadata.FormattingOptions.FormatLabeledScoreDifference(marginUnderAbove)} under {Utilities.AppendOrdinalSuffix(myIndexInPeerList)} place"); } if (myIndexInPeerList < peerList.Count - 1) { double marginAboveUnder = teamScore.Summary.TotalScore - peerList[myIndexInPeerList + 1].TotalScore; marginBuilder.AppendLine($"{ScoreRetrieverMetadata.FormattingOptions.FormatLabeledScoreDifference(marginAboveUnder)} above {Utilities.AppendOrdinalSuffix(myIndexInPeerList + 2)} place"); } // TODO division- and round-specific margins builder.AddInlineField("Margin", marginBuilder.ToString()); StringBuilder standingFieldBuilder = new StringBuilder(); IList <ScoreboardSummaryEntry> subPeer = null; string subPeerLabel = null; if (!peerFilter.Category.HasValue && teamScore.Summary.Category.HasValue) { var myCategory = teamScore.Summary.Category.Value; subPeer = peerList.Where(x => x.Category == myCategory).ToIList(); subPeerLabel = " in category"; } else if (peerFilter.Location == null && teamScore.Summary.Location != null) { var myLocation = teamScore.Summary.Location; subPeer = peerList.Where(x => x.Location == myLocation).ToIList(); subPeerLabel = " in state"; } if (subPeerLabel != null) { standingFieldBuilder.AppendLine(Utilities.AppendOrdinalSuffix(subPeer.IndexOfWhere(x => x.TeamId == teamScore.TeamId) + 1) + " of " + Utilities.Pluralize("peer team", subPeer.Count) + subPeerLabel); } standingFieldBuilder.AppendLine(Utilities.AppendOrdinalSuffix(myIndexInPeerList + 1) + " of " + Utilities.Pluralize("peer team", peerList.Count)); // if peer teams != div+tier teams if ((peerFilter.Category.HasValue || peerFilter.Location != null) && peerFilter.Tier.HasValue) { // tier ranking, differing from peer ranking var tierTeams = completeScoreboard.Clone().WithFilter(new ScoreboardFilterInfo(peerFilter.Division, peerFilter.Tier)).TeamList; standingFieldBuilder.AppendLine(Utilities.AppendOrdinalSuffix(tierTeams.IndexOfWhere(x => x.TeamId == teamScore.TeamId) + 1) + " of " + Utilities.Pluralize("team", tierTeams.Count) + " in tier"); } if (peerFilter.Category.HasValue || peerFilter.Location != null || peerFilter.Tier.HasValue) { // division ranking, differing from peer ranking var divTeams = completeScoreboard.Clone().WithFilter(new ScoreboardFilterInfo(peerFilter.Division, null)).TeamList; standingFieldBuilder.AppendLine(Utilities.AppendOrdinalSuffix(divTeams.IndexOfWhere(x => x.TeamId == teamScore.TeamId) + 1) + " of " + Utilities.Pluralize("team", divTeams.Count) + " in division"); } builder.AddInlineField("Standing", standingFieldBuilder.ToString()); }
private string GetTeamLeaderboardEntry(ScoreboardSummaryEntry team, int friendlyIndex, bool useAbbreviatedDivision = false, string prefix = "#", bool showAdvancement = true) { string divisionFormatString = useAbbreviatedDivision ? "{0,6}" : " {0,-10}"; return($"{prefix}{friendlyIndex,-5}{team.TeamId,-7}{team.Location,4}" + string.Format(divisionFormatString, AbbreviateDivision(team)) + $"{team.Tier,10}{ScoreRetrieverMetadata.FormattingOptions.FormatScoreForLeaderboard(team.TotalScore),16}{((showAdvancement && team.Advancement.HasValue) ? team.Advancement.Value.ToConciseString() : (ScoreFormattingOptions.EvaluateNumericDisplay(ScoreRetrieverMetadata.FormattingOptions.TimeDisplay, team.PlayTime) ? team.PlayTime.ToHoursMinutesSecondsString() : "")),10}{team.Warnings.ToConciseString(),4}"); }
public string CreateImageLeaderboardEmbed(IEnumerable <KeyValuePair <ScoreboardSummaryEntry, ScoreboardImageDetails> > completeImageData, string filterDescription, int teamCount = -1, int pageNumber = 1, int pageSize = 15) { if (pageSize <= 0) { throw new ArgumentOutOfRangeException(nameof(pageSize)); } if (teamCount == -1) { completeImageData = completeImageData.ToIList(); teamCount = completeImageData.Count(); } int pageCount = (int)Math.Ceiling(((double)teamCount) / pageSize); pageNumber--; if (pageNumber < 0 || pageNumber >= pageCount) { throw new ArgumentOutOfRangeException(nameof(pageNumber)); } IList <KeyValuePair <ScoreboardSummaryEntry, ScoreboardImageDetails> > thisPageImageData = completeImageData.Skip(pageNumber * pageSize).Take(pageSize).ToIList(); StringBuilder resultBuilder = new StringBuilder(); resultBuilder.Append("**CyberPatriot Image Scoreboard"); if (!string.IsNullOrWhiteSpace(filterDescription)) { resultBuilder.Append(", ").Append(filterDescription); } if (pageCount > 1) { resultBuilder.Append($" (Page {pageNumber + 1} of {pageCount})"); } resultBuilder.AppendLine("**"); ScoreboardImageDetails canonicalImage = thisPageImageData[0].Value; resultBuilder.AppendFormat("**`{0}`", canonicalImage.ImageName); int vulnCt = canonicalImage.VulnerabilitiesRemaining + canonicalImage.VulnerabilitiesFound; double pts = canonicalImage.PointsPossible; bool displayVulns = ScoreFormattingOptions.EvaluateNumericDisplay(ScoreRetrieverMetadata.FormattingOptions.VulnerabilityDisplay, vulnCt); bool displayPts = ScoreFormattingOptions.EvaluateNumericDisplay(ScoreRetrieverMetadata.FormattingOptions.VulnerabilityDisplay, pts); if (displayVulns || displayPts) { resultBuilder.Append(": "); if (displayVulns) { resultBuilder.Append(Utilities.Pluralize("vulnerability", vulnCt)); if (displayPts) { resultBuilder.Append(", "); } } if (displayPts) { resultBuilder.Append(ScoreRetrieverMetadata.FormattingOptions.FormatScore(pts)).Append(" points possible"); } } resultBuilder.AppendLine("**"); resultBuilder.AppendLine("```"); bool conciseDivision = !thisPageImageData.Any(x => x.Key.Category != null); for (int i = 0; i < thisPageImageData.Count; i++) { var teamScore = thisPageImageData[i]; int friendlyIndex = i + 1 + (pageNumber * pageSize); resultBuilder.AppendLine(GetImageLeaderboardEntry(teamScore.Key, teamScore.Value, friendlyIndex, useAbbreviatedDivision: conciseDivision)); } resultBuilder.AppendLine("```"); return(resultBuilder.ToString()); }