Trivia converted, removed currency reward
This commit is contained in:
		| @@ -9,14 +9,16 @@ using System.Text; | ||||
| using System.Threading; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| // todo rewrite? | ||||
| // todo DB | ||||
| namespace NadekoBot.Modules.Games.Commands.Trivia | ||||
| { | ||||
|     internal class TriviaGame | ||||
|     public class TriviaGame | ||||
|     { | ||||
|         private readonly SemaphoreSlim _guessLock = new SemaphoreSlim(1,1); | ||||
|         private readonly SemaphoreSlim _guessLock = new SemaphoreSlim(1, 1); | ||||
|  | ||||
|         private Server server { get; } | ||||
|         private Channel channel { get; } | ||||
|         private IGuild guild { get; } | ||||
|         private ITextChannel channel { get; } | ||||
|  | ||||
|         private int QuestionDurationMiliseconds { get; } = 30000; | ||||
|         private int HintTimeoutMiliseconds { get; } = 6000; | ||||
| @@ -26,18 +28,18 @@ namespace NadekoBot.Modules.Games.Commands.Trivia | ||||
|         public TriviaQuestion CurrentQuestion { get; private set; } | ||||
|         public HashSet<TriviaQuestion> oldQuestions { get; } = new HashSet<TriviaQuestion>(); | ||||
|  | ||||
|         public ConcurrentDictionary<User, int> Users { get; } = new ConcurrentDictionary<User, int>(); | ||||
|         public ConcurrentDictionary<IGuildUser, int> Users { get; } = new ConcurrentDictionary<IGuildUser, int>(); | ||||
|  | ||||
|         public bool GameActive { get; private set; } = false; | ||||
|         public bool ShouldStopGame { get; private set; } | ||||
|  | ||||
|         public int WinRequirement { get; } = 10; | ||||
|  | ||||
|         public TriviaGame(CommandEventArgs e, bool showHints, int winReq = 10) | ||||
|         public TriviaGame(IGuild guild, ITextChannel channel, bool showHints, int winReq = 10) | ||||
|         { | ||||
|             ShowHints = showHints; | ||||
|             server = e.Server; | ||||
|             channel = e.Channel; | ||||
|             this.guild = guild; | ||||
|             this.channel = channel; | ||||
|             WinRequirement = winReq; | ||||
|             Task.Run(StartGame); | ||||
|         } | ||||
| @@ -53,13 +55,13 @@ namespace NadekoBot.Modules.Games.Commands.Trivia | ||||
|                 CurrentQuestion = TriviaQuestionPool.Instance.GetRandomQuestion(oldQuestions); | ||||
|                 if (CurrentQuestion == null) | ||||
|                 { | ||||
|                     await channel.SendMessage($":exclamation: Failed loading a trivia question").ConfigureAwait(false); | ||||
|                     await channel.SendMessageAsync($":exclamation: Failed loading a trivia question").ConfigureAwait(false); | ||||
|                     await End().ConfigureAwait(false); | ||||
|                     return; | ||||
|                 } | ||||
|                 oldQuestions.Add(CurrentQuestion); //add it to exclusion list so it doesn't show up again | ||||
|                                                    //sendquestion | ||||
|                 await channel.SendMessage($":question: **{CurrentQuestion.Question}**").ConfigureAwait(false); | ||||
|                 await channel.SendMessageAsync($":question: **{CurrentQuestion.Question}**").ConfigureAwait(false); | ||||
|  | ||||
|                 //receive messages | ||||
|                 NadekoBot.Client.MessageReceived += PotentialGuess; | ||||
| @@ -72,7 +74,7 @@ namespace NadekoBot.Modules.Games.Commands.Trivia | ||||
|                     //hint | ||||
|                     await Task.Delay(HintTimeoutMiliseconds, token).ConfigureAwait(false); | ||||
|                     if (ShowHints) | ||||
|                         await channel.SendMessage($":exclamation:**Hint:** {CurrentQuestion.GetHint()}").ConfigureAwait(false); | ||||
|                         await channel.SendMessageAsync($":exclamation:**Hint:** {CurrentQuestion.GetHint()}").ConfigureAwait(false); | ||||
|  | ||||
|                     //timeout | ||||
|                     await Task.Delay(QuestionDurationMiliseconds - HintTimeoutMiliseconds, token).ConfigureAwait(false); | ||||
| @@ -81,7 +83,7 @@ namespace NadekoBot.Modules.Games.Commands.Trivia | ||||
|                 catch (TaskCanceledException) { } //means someone guessed the answer | ||||
|                 GameActive = false; | ||||
|                 if (!triviaCancelSource.IsCancellationRequested) | ||||
|                     await channel.Send($":clock2: :question: **Time's up!** The correct answer was **{CurrentQuestion.Answer}**").ConfigureAwait(false); | ||||
|                     await channel.SendMessageAsync($":clock2: :question: **Time's up!** The correct answer was **{CurrentQuestion.Answer}**").ConfigureAwait(false); | ||||
|                 NadekoBot.Client.MessageReceived -= PotentialGuess; | ||||
|                 // load next question if game is still running | ||||
|                 await Task.Delay(2000).ConfigureAwait(false); | ||||
| @@ -92,46 +94,43 @@ namespace NadekoBot.Modules.Games.Commands.Trivia | ||||
|         private async Task End() | ||||
|         { | ||||
|             ShouldStopGame = true; | ||||
|             await channel.SendMessage("**Trivia game ended**\n" + GetLeaderboard()).ConfigureAwait(false); | ||||
|             TriviaGame throwAwayValue; | ||||
|             TriviaCommands.RunningTrivias.TryRemove(server.Id, out throwAwayValue); | ||||
|             await channel.SendMessageAsync("**Trivia game ended**\n" + GetLeaderboard()).ConfigureAwait(false); | ||||
|         } | ||||
|  | ||||
|         public async Task StopGame() | ||||
|         { | ||||
|             if (!ShouldStopGame) | ||||
|                 await channel.SendMessage(":exclamation: Trivia will stop after this question.").ConfigureAwait(false); | ||||
|                 await channel.SendMessageAsync(":exclamation: Trivia will stop after this question.").ConfigureAwait(false); | ||||
|             ShouldStopGame = true; | ||||
|         } | ||||
|  | ||||
|         private async void PotentialGuess(object sender, MessageEventArgs e) | ||||
|         private async Task PotentialGuess(IMessage imsg) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 if (e.Channel.IsPrivate) return; | ||||
|                 if (e.Server != server) return; | ||||
|                 if (e.User.Id == NadekoBot.Client.CurrentUser.Id) return; | ||||
|                 if (!(imsg.Channel is IGuildChannel && imsg.Channel is ITextChannel)) return; | ||||
|                 if ((imsg.Channel as IGuildChannel).Guild != guild) return; | ||||
|                 if (imsg.Author.Id == (await NadekoBot.Client.GetCurrentUserAsync()).Id) return; | ||||
|  | ||||
|                 var guildUser = imsg.Author as IGuildUser; | ||||
|  | ||||
|                 var guess = false; | ||||
|                 await _guessLock.WaitAsync().ConfigureAwait(false); | ||||
|                 try | ||||
|                 { | ||||
|                     if (GameActive && CurrentQuestion.IsAnswerCorrect(e.Message.Text) && !triviaCancelSource.IsCancellationRequested) | ||||
|                     if (GameActive && CurrentQuestion.IsAnswerCorrect(imsg.Content) && !triviaCancelSource.IsCancellationRequested) | ||||
|                     { | ||||
|                         Users.TryAdd(e.User, 0); //add if not exists | ||||
|                         Users[e.User]++; //add 1 point to the winner | ||||
|                         Users.AddOrUpdate(guildUser, 0, (gu, old) => old++); | ||||
|                         guess = true; | ||||
|                     } | ||||
|                 } | ||||
|                 finally { _guessLock.Release(); } | ||||
|                 if (!guess) return; | ||||
|                 triviaCancelSource.Cancel(); | ||||
|                 await channel.SendMessage($"☑️ {e.User.Mention} guessed it! The answer was: **{CurrentQuestion.Answer}**").ConfigureAwait(false); | ||||
|                 if (Users[e.User] != WinRequirement) return; | ||||
|                 await channel.SendMessageAsync($"☑️ {guildUser.Mention} guessed it! The answer was: **{CurrentQuestion.Answer}**").ConfigureAwait(false); | ||||
|                 if (Users[guildUser] != WinRequirement) return; | ||||
|                 ShouldStopGame = true; | ||||
|                 await channel.Send($":exclamation: We have a winner! It's {e.User.Mention}.").ConfigureAwait(false); | ||||
|                 // add points to the winner | ||||
|                 await FlowersHandler.AddFlowersAsync(e.User, "Won Trivia", 2).ConfigureAwait(false); | ||||
|                 await channel.SendMessageAsync($":exclamation: We have a winner! It's {guildUser.Mention}.").ConfigureAwait(false); | ||||
|             } | ||||
|             catch { } | ||||
|         } | ||||
| @@ -146,7 +145,7 @@ namespace NadekoBot.Modules.Games.Commands.Trivia | ||||
|  | ||||
|             foreach (var kvp in Users.OrderBy(kvp => kvp.Value)) | ||||
|             { | ||||
|                 sb.AppendLine($"**{kvp.Key.Name}** has {kvp.Value} points".ToString().SnPl(kvp.Value)); | ||||
|                 sb.AppendLine($"**{kvp.Key.Username}** has {kvp.Value} points".ToString().SnPl(kvp.Value)); | ||||
|             } | ||||
|  | ||||
|             return sb.ToString(); | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| using NadekoBot.Extensions; | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Text.RegularExpressions; | ||||
|  | ||||
| // THANKS @ShoMinamimoto for suggestions and coding help | ||||
| @@ -28,7 +29,7 @@ namespace NadekoBot.Modules.Games.Commands.Trivia | ||||
|             this.Category = c; | ||||
|         } | ||||
|  | ||||
|         public string GetHint() => Answer.Scramble(); | ||||
|         public string GetHint() => Scramble(Answer); | ||||
|  | ||||
|         public bool IsAnswerCorrect(string guess) | ||||
|         { | ||||
| @@ -80,5 +81,27 @@ namespace NadekoBot.Modules.Games.Commands.Trivia | ||||
|  | ||||
|         public override string ToString() => | ||||
|             "Question: **" + this.Question + "?**"; | ||||
|  | ||||
|         private static string Scramble(string word) | ||||
|         { | ||||
|             var letters = word.ToArray(); | ||||
|             var count = 0; | ||||
|             for (var i = 0; i < letters.Length; i++) | ||||
|             { | ||||
|                 if (letters[i] == ' ') | ||||
|                     continue; | ||||
|  | ||||
|                 count++; | ||||
|                 if (count <= letters.Length / 5) | ||||
|                     continue; | ||||
|  | ||||
|                 if (count % 3 == 0) | ||||
|                     continue; | ||||
|  | ||||
|                 if (letters[i] != ' ') | ||||
|                     letters[i] = '_'; | ||||
|             } | ||||
|             return "`" + string.Join(" ", letters) + "`"; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -9,7 +9,7 @@ namespace NadekoBot.Modules.Games.Commands.Trivia | ||||
|     public class TriviaQuestionPool | ||||
|     { | ||||
|         public static TriviaQuestionPool Instance { get; } = new TriviaQuestionPool(); | ||||
|  | ||||
|         //todo DB | ||||
|         public HashSet<TriviaQuestion> pool = new HashSet<TriviaQuestion>(); | ||||
|  | ||||
|         private Random rng { get; } = new Random(); | ||||
|   | ||||
| @@ -1,76 +0,0 @@ | ||||
| //using Discord.Commands; | ||||
| //using NadekoBot.Classes; | ||||
| //using NadekoBot.Modules.Games.Commands.Trivia; | ||||
| //using System; | ||||
| //using System.Collections.Concurrent; | ||||
| //using System.Linq; | ||||
|  | ||||
| ////todo DB | ||||
| ////todo Rewrite? | ||||
|  | ||||
| //namespace NadekoBot.Modules.Games.Commands | ||||
| //{ | ||||
| //    internal class TriviaCommands : DiscordCommand | ||||
| //    { | ||||
| //        public static ConcurrentDictionary<ulong, TriviaGame> RunningTrivias = new ConcurrentDictionary<ulong, TriviaGame>(); | ||||
|  | ||||
| //        public TriviaCommands(DiscordModule module) : base(module) | ||||
| //        { | ||||
| //        } | ||||
|  | ||||
| //        internal override void Init(CommandGroupBuilder cgb) | ||||
| //        { | ||||
| //            cgb.CreateCommand(Module.Prefix + "t") | ||||
| //                .Description($"Starts a game of trivia. You can add nohint to prevent hints." + | ||||
| //                              "First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question." + | ||||
| //                              $" |`{Module.Prefix}t nohint` or `{Module.Prefix}t 5 nohint`") | ||||
| //                .Parameter("args", ParameterType.Multiple) | ||||
| //                .Do(async e => | ||||
| //                { | ||||
| //                    TriviaGame trivia; | ||||
| //                    if (!RunningTrivias.TryGetValue(e.Server.Id, out trivia)) | ||||
| //                    { | ||||
| //                        var showHints = !e.Args.Contains("nohint"); | ||||
| //                        var number = e.Args.Select(s => | ||||
| //                        { | ||||
| //                            int num; | ||||
| //                            return new Tuple<bool, int>(int.TryParse(s, out num), num); | ||||
| //                        }).Where(t => t.Item1).Select(t => t.Item2).FirstOrDefault(); | ||||
| //                        if (number < 0) | ||||
| //                            return; | ||||
| //                        var triviaGame = new TriviaGame(e, showHints, number == 0 ? 10 : number); | ||||
| //                        if (RunningTrivias.TryAdd(e.Server.Id, triviaGame)) | ||||
| //                            await imsg.Channel.SendMessageAsync($"**Trivia game started! {triviaGame.WinRequirement} points needed to win.**").ConfigureAwait(false); | ||||
| //                        else | ||||
| //                            await triviaGame.StopGame().ConfigureAwait(false); | ||||
| //                    } | ||||
| //                    else | ||||
| //                        await imsg.Channel.SendMessageAsync("Trivia game is already running on this server.\n" + trivia.CurrentQuestion).ConfigureAwait(false); | ||||
| //                }); | ||||
|  | ||||
| //            cgb.CreateCommand(Module.Prefix + "tl") | ||||
| //                .Description($"Shows a current trivia leaderboard. | `{Prefix}tl`") | ||||
| //                .Do(async e => | ||||
| //                { | ||||
| //                    TriviaGame trivia; | ||||
| //                    if (RunningTrivias.TryGetValue(e.Server.Id, out trivia)) | ||||
| //                        await imsg.Channel.SendMessageAsync(trivia.GetLeaderboard()).ConfigureAwait(false); | ||||
| //                    else | ||||
| //                        await imsg.Channel.SendMessageAsync("No trivia is running on this server.").ConfigureAwait(false); | ||||
| //                }); | ||||
|  | ||||
| //            cgb.CreateCommand(Module.Prefix + "tq") | ||||
| //                .Description($"Quits current trivia after current question. | `{Prefix}tq`") | ||||
| //                .Do(async e => | ||||
| //                { | ||||
| //                    TriviaGame trivia; | ||||
| //                    if (RunningTrivias.TryGetValue(e.Server.Id, out trivia)) | ||||
| //                    { | ||||
| //                        await trivia.StopGame().ConfigureAwait(false); | ||||
| //                    } | ||||
| //                    else | ||||
| //                        await imsg.Channel.SendMessageAsync("No trivia is running on this server.").ConfigureAwait(false); | ||||
| //                }); | ||||
| //        } | ||||
| //    } | ||||
| //} | ||||
							
								
								
									
										80
									
								
								src/NadekoBot/Modules/Games/Commands/TriviaCommands.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								src/NadekoBot/Modules/Games/Commands/TriviaCommands.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,80 @@ | ||||
| using Discord; | ||||
| using Discord.Commands; | ||||
| using NadekoBot.Attributes; | ||||
| using NadekoBot.Classes; | ||||
| using NadekoBot.Modules.Games.Commands.Trivia; | ||||
| using System; | ||||
| using System.Collections.Concurrent; | ||||
| using System.Linq; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| //todo DB | ||||
| //todo Rewrite? | ||||
|  | ||||
| namespace NadekoBot.Modules.Games.Commands | ||||
| { | ||||
|     public partial class GamesModule | ||||
|     { | ||||
|  | ||||
|         [Group] | ||||
|         public class TriviaCommands | ||||
|         { | ||||
|             public static ConcurrentDictionary<ulong, TriviaGame> RunningTrivias = new ConcurrentDictionary<ulong, TriviaGame>(); | ||||
|  | ||||
|             [LocalizedCommand, LocalizedDescription, LocalizedSummary] | ||||
|             [RequireContext(ContextType.Guild)] | ||||
|             public async Task Trivia(IMessage imsg, string[] args) | ||||
|             { | ||||
|                 var channel = imsg.Channel as IGuildChannel; | ||||
|  | ||||
|                 TriviaGame trivia; | ||||
|                 if (!RunningTrivias.TryGetValue(channel.Guild.Id, out trivia)) | ||||
|                 { | ||||
|                     var showHints = !args.Contains("nohint"); | ||||
|                     var number = args.Select(s => | ||||
|                     { | ||||
|                         int num; | ||||
|                         return new Tuple<bool, int>(int.TryParse(s, out num), num); | ||||
|                     }).Where(t => t.Item1).Select(t => t.Item2).FirstOrDefault(); | ||||
|                     if (number < 0) | ||||
|                         return; | ||||
|                     var triviaGame = new TriviaGame(channel.Guild, imsg.Channel as ITextChannel, showHints, number == 0 ? 10 : number); | ||||
|                     if (RunningTrivias.TryAdd(channel.Guild.Id, triviaGame)) | ||||
|                         await imsg.Channel.SendMessageAsync($"**Trivia game started! {triviaGame.WinRequirement} points needed to win.**").ConfigureAwait(false); | ||||
|                     else | ||||
|                         await triviaGame.StopGame().ConfigureAwait(false); | ||||
|                 } | ||||
|                 else | ||||
|                     await imsg.Channel.SendMessageAsync("Trivia game is already running on this server.\n" + trivia.CurrentQuestion).ConfigureAwait(false); | ||||
|             } | ||||
|  | ||||
|             [LocalizedCommand, LocalizedDescription, LocalizedSummary] | ||||
|             [RequireContext(ContextType.Guild)] | ||||
|             public async Task Tl(IMessage imsg) | ||||
|             { | ||||
|                 var channel = imsg.Channel as IGuildChannel; | ||||
|  | ||||
|                 TriviaGame trivia; | ||||
|                 if (RunningTrivias.TryGetValue(channel.Guild.Id, out trivia)) | ||||
|                     await imsg.Channel.SendMessageAsync(trivia.GetLeaderboard()).ConfigureAwait(false); | ||||
|                 else | ||||
|                     await imsg.Channel.SendMessageAsync("No trivia is running on this server.").ConfigureAwait(false); | ||||
|             } | ||||
|  | ||||
|             [LocalizedCommand, LocalizedDescription, LocalizedSummary] | ||||
|             [RequireContext(ContextType.Guild)] | ||||
|             public async Task Tq(IMessage imsg) | ||||
|             { | ||||
|                 var channel = imsg.Channel as IGuildChannel; | ||||
|  | ||||
|                 TriviaGame trivia; | ||||
|                 if (RunningTrivias.TryRemove(channel.Guild.Id, out trivia)) | ||||
|                 { | ||||
|                     await trivia.StopGame().ConfigureAwait(false); | ||||
|                 } | ||||
|                 else | ||||
|                     await imsg.Channel.SendMessageAsync("No trivia is running on this server.").ConfigureAwait(false); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -137,5 +137,85 @@ namespace NadekoBot.Extensions | ||||
|             return string.Concat(str.Take(maxLength - 3)) + (hideDots ? "" : "..."); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Removes trailing S or ES (if specified) on the given string if the num is 1 | ||||
|         /// </summary> | ||||
|         /// <param name="str"></param> | ||||
|         /// <param name="num"></param> | ||||
|         /// <param name="es"></param> | ||||
|         /// <returns>String with the correct singular/plural form</returns> | ||||
|         public static string SnPl(this string str, int? num, bool es = false) | ||||
|         { | ||||
|             if (str == null) | ||||
|                 throw new ArgumentNullException(nameof(str)); | ||||
|             if (num == null) | ||||
|                 throw new ArgumentNullException(nameof(num)); | ||||
|             return num == 1 ? str.Remove(str.Length - 1, es ? 2 : 1) : str; | ||||
|         } | ||||
|  | ||||
|         //http://www.dotnetperls.com/levenshtein | ||||
|         public static int LevenshteinDistance(this string s, string t) | ||||
|         { | ||||
|             var n = s.Length; | ||||
|             var m = t.Length; | ||||
|             var d = new int[n + 1, m + 1]; | ||||
|  | ||||
|             // Step 1 | ||||
|             if (n == 0) | ||||
|             { | ||||
|                 return m; | ||||
|             } | ||||
|  | ||||
|             if (m == 0) | ||||
|             { | ||||
|                 return n; | ||||
|             } | ||||
|  | ||||
|             // Step 2 | ||||
|             for (var i = 0; i <= n; d[i, 0] = i++) | ||||
|             { | ||||
|             } | ||||
|  | ||||
|             for (var j = 0; j <= m; d[0, j] = j++) | ||||
|             { | ||||
|             } | ||||
|  | ||||
|             // Step 3 | ||||
|             for (var i = 1; i <= n; i++) | ||||
|             { | ||||
|                 //Step 4 | ||||
|                 for (var j = 1; j <= m; j++) | ||||
|                 { | ||||
|                     // Step 5 | ||||
|                     var cost = (t[j - 1] == s[i - 1]) ? 0 : 1; | ||||
|  | ||||
|                     // Step 6 | ||||
|                     d[i, j] = Math.Min( | ||||
|                         Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1), | ||||
|                         d[i - 1, j - 1] + cost); | ||||
|                 } | ||||
|             } | ||||
|             // Step 7 | ||||
|             return d[n, m]; | ||||
|         } | ||||
|  | ||||
|         public static int KiB(this int value) => value * 1024; | ||||
|         public static int KB(this int value) => value * 1000; | ||||
|  | ||||
|         public static int MiB(this int value) => value.KiB() * 1024; | ||||
|         public static int MB(this int value) => value.KB() * 1000; | ||||
|  | ||||
|         public static int GiB(this int value) => value.MiB() * 1024; | ||||
|         public static int GB(this int value) => value.MB() * 1000; | ||||
|  | ||||
|         public static ulong KiB(this ulong value) => value * 1024; | ||||
|         public static ulong KB(this ulong value) => value * 1000; | ||||
|  | ||||
|         public static ulong MiB(this ulong value) => value.KiB() * 1024; | ||||
|         public static ulong MB(this ulong value) => value.KB() * 1000; | ||||
|  | ||||
|         public static ulong GiB(this ulong value) => value.MiB() * 1024; | ||||
|         public static ulong GB(this ulong value) => value.MB() * 1000; | ||||
|  | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user