From ec11cf44963c2ddf342248426e4535ef965934b5 Mon Sep 17 00:00:00 2001 From: Andriy <30056636+West14@users.noreply.github.com> Date: Wed, 18 Jan 2023 02:07:48 +0200 Subject: [PATCH] [entertainment] add guess game --- Core/Cache/ICacheStorage.cs | 1 + Core/Cache/MemoryCache.cs | 11 ++ modules/Entertainment/Entertainment.cs | 13 ++- modules/Entertainment/Handler/Guess.cs | 112 +++++++++++++++++++++ modules/Entertainment/Handler/GuessData.cs | 9 ++ 5 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 modules/Entertainment/Handler/Guess.cs create mode 100644 modules/Entertainment/Handler/GuessData.cs diff --git a/Core/Cache/ICacheStorage.cs b/Core/Cache/ICacheStorage.cs index 0983354..aeca6a1 100644 --- a/Core/Cache/ICacheStorage.cs +++ b/Core/Cache/ICacheStorage.cs @@ -6,5 +6,6 @@ namespace Kruzya.TelegramBot.Core.Cache { public bool TryGetValue(TKey key, out TValue value); public void SetValue(TKey key, TValue value, int timeToLive); + public TValue GetOr(TKey key, TValue value); } } \ No newline at end of file diff --git a/Core/Cache/MemoryCache.cs b/Core/Cache/MemoryCache.cs index baf063f..a81a62a 100644 --- a/Core/Cache/MemoryCache.cs +++ b/Core/Cache/MemoryCache.cs @@ -72,6 +72,17 @@ namespace Kruzya.TelegramBot.Core.Cache return true; } + public TValue GetOr(TKey key, TValue defValue = default) + { + var doesExist = TryGetValue(key, out var value); + if (!doesExist) + { + value = defValue; + } + + return value; + } + public void SetValue(TKey key, TValue value) { SetValue(key, value, _defaultTtl); diff --git a/modules/Entertainment/Entertainment.cs b/modules/Entertainment/Entertainment.cs index a0134a1..d184b4b 100644 --- a/modules/Entertainment/Entertainment.cs +++ b/modules/Entertainment/Entertainment.cs @@ -1,9 +1,20 @@ -using Kruzya.TelegramBot.Core; +global using IGuessCache = Kruzya.TelegramBot.Core.Cache.ICacheStorage>; +global using GuessCache = Kruzya.TelegramBot.Core.Cache.MemoryCache>; + + +using Kruzya.TelegramBot.Core; +using Microsoft.Extensions.DependencyInjection; + namespace West.Entertainment { public class Entertainment : Module { public Entertainment(Core core) : base(core) { } + + public override void ConfigureServices(IServiceCollection services) + { + services.AddSingleton(); + } } } \ No newline at end of file diff --git a/modules/Entertainment/Handler/Guess.cs b/modules/Entertainment/Handler/Guess.cs new file mode 100644 index 0000000..fbef62f --- /dev/null +++ b/modules/Entertainment/Handler/Guess.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Concurrent; +using System.Linq; +using System.Threading.Tasks; +using BotFramework; +using BotFramework.Attributes; +using BotFramework.Enums; +using Kruzya.TelegramBot.Core; +using Kruzya.TelegramBot.Core.Data; +using Kruzya.TelegramBot.Core.Extensions; +using Kruzya.TelegramBot.Core.Service; +using Telegram.Bot; + +namespace West.Entertainment.Handler; + +public class Guess : CommonHandler +{ + private readonly IGuessCache _guessCache; + private readonly ThreadSafeRandom _rng; + private readonly IReputation _reputationService; + private readonly CoreContext _db; + + public Guess(IGuessCache guessCache, ThreadSafeRandom rng, IReputation reputationService, CoreContext db) : base(db) + { + _guessCache = guessCache; + _rng = rng; + _reputationService = reputationService; + _db = db; + } + + [Command(InChat.Public, "guess", CommandParseMode.Both)] + public async Task HandleGuess() + { + var guessDict = _guessCache.GetOr(Chat.Id, new ConcurrentDictionary()); + + var cooldownOption = await _db.UserValues.FindOrCreateOption(Chat.Id, From.Id, "guessCooldown"); + var cooldown = cooldownOption.GetValue(); + if (cooldown > DateTime.Now) + { + await Reply($"Следующее использование через {cooldown - DateTime.Now:hh\\:mm\\:ss}."); + return; + } + + var doesExist = guessDict.Any(pair => pair.Value.UserId == From.Id); + if (doesExist) + { + await Bot.SendTextMessageAsync(Chat, "Вы уже запустили игру."); + return; + } + + var messageId = RawUpdate.Message!.MessageId; + var guessedNumber = _rng.Next(1, 4); + Console.WriteLine(guessedNumber); + var guessData = new GuessData + { + Number = guessedNumber, + UserId = From.Id + }; + + var message = await Bot.SendTextMessageAsync(Chat.Id, "Выберите число от 1 до 3.", replyToMessageId: messageId); + if (!guessDict.TryAdd(message.MessageId, guessData)) + { + return; + } + _guessCache.SetValue(Chat.Id, guessDict, -1); + } + + [Message(InChat.Public, MessageFlag.IsReply)] + public async Task HandleGuessResponse() + { + var guessDict = _guessCache.GetOr(Chat.Id, new ConcurrentDictionary()); + var messageId = RawUpdate.Message!.ReplyToMessage!.MessageId; + if (!guessDict.TryGetValue(messageId, out var data)) + { + return; + } + + if (From.Id != data.UserId) + { + return; + } + + if (!int.TryParse(RawUpdate.Message!.Text, out var responseNumber)) + { + return; + } + + guessDict.TryRemove(messageId, out _); + _guessCache.SetValue(Chat.Id, guessDict, -1); + + var nextUse = DateTime.Now.AddHours(1); + var postFix = $"\nСледующая попытка через: {nextUse - DateTime.Now:hh\\:mm\\:ss}"; + + string message; + if (responseNumber == data.Number) + { + await _reputationService.IncrementReputationAsync(Chat, From, 20); + message = "Вы угадали! Вам начислено 20 кармы."; + } + else + { + message = "Вы не угадали!"; + } + + await Bot.SendTextMessageAsync(Chat, message + postFix); + + var cooldownOption = await _db.UserValues.FindOrCreateOption(Chat.Id, From.Id, "guessCooldown"); + cooldownOption.SetValue(nextUse); + + _db.AddOrUpdate(cooldownOption); + } +} \ No newline at end of file diff --git a/modules/Entertainment/Handler/GuessData.cs b/modules/Entertainment/Handler/GuessData.cs new file mode 100644 index 0000000..b0059ac --- /dev/null +++ b/modules/Entertainment/Handler/GuessData.cs @@ -0,0 +1,9 @@ +using Telegram.Bot.Types; + +namespace West.Entertainment.Handler; + +public class GuessData +{ + public long UserId { get; set; } + public int Number { get; set; } +} \ No newline at end of file