/// <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); }