public async Task GetGameReportAsync()
        {
            if (!this.Manager.TryGet(this.Context.Channel.Id, out GameState currentGame) ||
                currentGame?.ReaderId == null ||
                !(this.Context.Channel is IGuildChannel guildChannel))
            {
                return;
            }

            IEnumerable <PhaseScore> phaseScores = await currentGame.GetPhaseScores();

            // If there's been no buzzes in the last question, don't show it in the report (could be end of the packet)
            PhaseScore lastQuestion = phaseScores.LastOrDefault();

            if (lastQuestion?.ScoringSplitsOnActions?.Any() != true)
            {
                phaseScores = phaseScores.SkipLast(1);
            }

            IEnumerable <ScoringSplit> splits = phaseScores
                                                .SelectMany(pairs => pairs.ScoringSplitsOnActions.Select(pair => pair.Split));
            HighestPointsLevel highestPointsLevel = FindHighestPointLevel(splits);

            // Because we only have the scoring splits here, we have to rely on buzzes having a team ID
            bool hasTeams = phaseScores
                            .Any(scoresInPhase => scoresInPhase.ScoringSplitsOnActions.Any(pair => pair.Action.Buzz.TeamId != null));
            IReadOnlyDictionary <string, string> teamIdToName = await currentGame.TeamManager.GetTeamIdToNames();

            int scoresByQuestionCount = phaseScores.Count();
            int questionsReported     = await this.Context.Channel.SendAllEmbeds(
                phaseScores,
                () => new EmbedBuilder()
            {
                Title = GameReportTitle,
                Color = Color.Gold
            },
                (phaseScore, index) =>
                GetEmbedFieldForPhase(
                    currentGame, phaseScore, teamIdToName, highestPointsLevel, index, index == scoresByQuestionCount - 1));

            if (questionsReported > 0)
            {
                return;
            }

            EmbedBuilder embedBuilder = new EmbedBuilder()
            {
                Title       = GameReportTitle,
                Color       = Color.Gold,
                Description = "No questions read or answered yet."
            };

            await this.Context.Channel.SendMessageAsync(embed : embedBuilder.Build());
        }
Beispiel #2
0
        protected override IResult <IEnumerable <ValueRange> > GetUpdateRangesForBonus(
            PhaseScore phaseScore, string[] teamIds, string sheetName, int row, int phasesCount)
        {
            Verify.IsNotNull(phaseScore, nameof(phaseScore));

            List <ValueRange> ranges = new List <ValueRange>();

            if (phaseScore.BonusScores?.Any() == true)
            {
                int bonusScoresIndex = Array.IndexOf(teamIds, phaseScore.BonusTeamId);
                if (bonusScoresIndex < 0)
                {
                    return(new FailureResult <IEnumerable <ValueRange> >(
                               $"Unknown bonus team in phase {row - this.FirstPhaseRow + 1}. Cannot accurately create a scoresheet."));
                }

                int bonusTotal = phaseScore.BonusScores.Sum();
                if (bonusTotal != 0 && bonusTotal != 10 && bonusTotal != 20 && bonusTotal != 30)
                {
                    return(new FailureResult <IEnumerable <ValueRange> >(
                               $"Invalid bonus value in phase {row - this.FirstPhaseRow + 1}. Value must be 0/10/20/30, but it was {bonusTotal}"));
                }

                SpreadsheetColumn bonusColumn = this.BonusColumns.Span[bonusScoresIndex];
                ranges.Add(CreateUpdateSingleCellRequest(sheetName, bonusColumn, row, bonusTotal));
            }
            else if (row != this.FirstPhaseRow + phasesCount - 1 || phaseScore.ScoringSplitsOnActions.Any())
            {
                // We need to find if anyone got it correct, and if so, what team they are on. Fill that bonus
                // column with 0.
                ScoringSplitOnScoreAction split = phaseScore.ScoringSplitsOnActions
                                                  .FirstOrDefault(split => split.Action.Score > 0);
                if (split != null)
                {
                    // TODO: See if there's a better way to get the individual's team (add it when we add the buzz?)
                    // Risk is if there's a team name that is the same as someone's ID
                    // If it's an individual who is a team, then the teamId will be null, but their user ID may be a
                    // team ID.
                    int bonusIndex = Array.IndexOf(
                        teamIds,
                        split.Action.Buzz.TeamId ?? split.Action.Buzz.UserId.ToString(CultureInfo.InvariantCulture));
                    if (bonusIndex < 0 || bonusIndex >= 2)
                    {
                        return(new FailureResult <IEnumerable <ValueRange> >(
                                   $"Unknown bonus team in phase {row - this.FirstPhaseRow + 1}. Cannot accurately create a scoresheet."));
                    }

                    ranges.Add(CreateUpdateSingleCellRequest(sheetName, this.BonusColumns.Span[bonusIndex], row, 0));
                }
            }

            return(new SuccessResult <IEnumerable <ValueRange> >(ranges));
        }
        protected override IResult <IEnumerable <ValueRange> > GetUpdateRangesForBonus(
            PhaseScore phaseScore, string[] teamIds, string sheetName, int row, int phasesCount)
        {
            Verify.IsNotNull(phaseScore, nameof(phaseScore));

            List <ValueRange> ranges = new List <ValueRange>();

            if (phaseScore.BonusScores?.Any() == true)
            {
                int bonusPartCount = phaseScore.BonusScores.Count();
                if (bonusPartCount != 3)
                {
                    return(new FailureResult <IEnumerable <ValueRange> >(
                               $"Non-three part bonus in phase {row - this.FirstPhaseRow + 1}. Number of parts: {bonusPartCount}. These aren't supported for the scoresheet."));
                }

                int bonusScoresIndex = Array.IndexOf(teamIds, phaseScore.BonusTeamId);
                if (bonusScoresIndex < 0)
                {
                    return(new FailureResult <IEnumerable <ValueRange> >(
                               $"Unknown bonus team in phase {row - this.FirstPhaseRow + 1}. Cannot accurately create a scoresheet."));
                }

                SpreadsheetColumn bonusColumn = this.BonusColumns.Span[bonusScoresIndex];
                ranges.Add(CreateUpdateCellsAlongRowRequest(
                               sheetName, bonusColumn, row, phaseScore.BonusScores.Select(score => score > 0).ToArray()));

                SpreadsheetColumn otherBonusColumn = this.BonusColumns.Span[this.BonusColumns.Length - bonusScoresIndex - 1];
                ranges.Add(CreateUpdateCellsAlongRowRequest(
                               sheetName, otherBonusColumn, row, ClearedBonusArray));
            }
            else
            {
                // Clear the bonus columns
                for (int i = 0; i < this.BonusColumns.Span.Length; i++)
                {
                    ranges.Add(CreateUpdateCellsAlongRowRequest(
                                   sheetName, this.BonusColumns.Span[i], row, ClearedBonusArray));
                }
            }

            return(new SuccessResult <IEnumerable <ValueRange> >(ranges));
        }
Beispiel #4
0
        protected override IResult <IEnumerable <ValueRange> > GetAdditionalUpdateRangesForTossup(
            PhaseScore phaseScore, string[] teamIds, string sheetName, int row, int phasesCount)
        {
            Verify.IsNotNull(phaseScore, nameof(phaseScore));

            if (row == this.FirstPhaseRow + phasesCount - 1 && !phaseScore.ScoringSplitsOnActions.Any())
            {
                // We're in the last phase, and nothing has happened, so it's a placeholder phase for any future
                // scoring actions. This shouldn't be put into the scoresheet.
                return(new SuccessResult <IEnumerable <ValueRange> >(Enumerable.Empty <ValueRange>()));
            }

            // If the question went dead, put in "DT" in the first bonus column to indicate that the question was read
            if (phaseScore.ScoringSplitsOnActions.All(split => split.Action.Score <= 0))
            {
                List <ValueRange> ranges = new List <ValueRange>();
                ranges.Add(CreateUpdateSingleCellRequest(sheetName, this.BonusColumns.Span[0], row, "DT"));
                return(new SuccessResult <IEnumerable <ValueRange> >(ranges));
            }

            return(new SuccessResult <IEnumerable <ValueRange> >(Enumerable.Empty <ValueRange>()));
        }
Beispiel #5
0
 protected abstract IResult <IEnumerable <ValueRange> > GetAdditionalUpdateRangesForTossup(
     PhaseScore phaseScore, string[] teamIds, string sheetName, int row, int phasesCount);
 protected override IResult <IEnumerable <ValueRange> > GetAdditionalUpdateRangesForTossup(
     PhaseScore phaseScore, string[] teamIds, string sheetName, int row, int phasesCount)
 {
     return(new SuccessResult <IEnumerable <ValueRange> >(Enumerable.Empty <ValueRange>()));
 }