Trivia converted, removed currency reward
This commit is contained in:
parent
8a7ae9339e
commit
d6465fb6af
@ -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 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;
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user