Пример #1
0
 /// <summary>
 /// Adds another score to this one
 /// </summary>
 /// <param name="other"></param>
 public void CombineWith(GameResults other)
 {
     foreach (var score in other.Scores)
     {
         if (Scores.ContainsKey(score.Key))
         {
             Scores[score.Key] += score.Value;
         }
         else
         {
             Scores.Add(score.Key, score.Value);
         }
     }
 }
        /// <summary>
        /// Listen to messages coming from users, and end as soon as someone types the correct answer, or the question
        /// times out.
        /// When someone gets the correct answer, has a 1 second grace period so that multiple people guessing the
        /// answer at the same time will all get points.
        /// </summary>
        /// <param name="chat"></param>
        /// <param name="maxDuration"></param>
        /// <returns>A list of users and how many points they got,</returns>
        public async Task <GameResults> ExecuteQuestion(IObservable <DiscordMessage> chat, TimeSpan maxDuration)
        {
            if (maxDuration.TotalSeconds < 2)
            {
                throw new InvalidOperationException($"The timespan must be greater than 2 seconds, but was {maxDuration.TotalSeconds} seconds");
            }

            var result     = new GameResults();
            var waitHandle = new SemaphoreSlim(1);
            var cancellationTokenSource = new CancellationTokenSource();

            bool phase1 = true;           // When this is true the round ends when the first person gets the question right,
                                          // when it is false we are in the 1 second grace period

            await waitHandle.WaitAsync(); // Take the wait handle and wait for the observable to release it

            // Subscribe to incoming answers from users
            _subscription = chat.ObserveOn(_scheduler).Subscribe(message =>
            {
                if (IsAnswerCorrect(message.MessageText))
                {
                    // Someone was correct,
                    result.AddScore(message.UserName, Points);

                    if (phase1)
                    {
                        cancellationTokenSource.Cancel();
                        waitHandle.Release();
                    }
                }
            });

            //PHASE 1 - get the first correct answer and end

            //Release the lock after the time has run out
            Task doAfter = TimerUtils.TimerUtils.DoAfter(() => waitHandle.Release(),
                                                         (int)maxDuration.Subtract(TimeSpan.FromSeconds(1)).TotalMilliseconds,
                                                         cancellationTokenSource.Token);
            await waitHandle.WaitAsync();

            phase1 = false;

            //PHASE 2 - always lasts for 1 second and add all answers
            await Task.Delay(1);

            return(result);
        }