mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-11 01:38:27 -04:00
Hangman Rewrite
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NadekoBot.Common;
|
||||
using NadekoBot.Common.Yml;
|
||||
using Serilog;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Hangman
|
||||
{
|
||||
public sealed class DefaultHangmanSource : IHangmanSource
|
||||
{
|
||||
private IReadOnlyDictionary<string, HangmanTerm[]> _terms = new Dictionary<string, HangmanTerm[]>();
|
||||
private readonly Random _rng;
|
||||
|
||||
public DefaultHangmanSource()
|
||||
{
|
||||
_rng = new NadekoRandom();
|
||||
Reload();
|
||||
}
|
||||
|
||||
public void Reload()
|
||||
{
|
||||
if (!Directory.Exists("data/hangman"))
|
||||
{
|
||||
Log.Error("Hangman game won't work. Folder 'data/hangman' is missing.");
|
||||
return;
|
||||
}
|
||||
|
||||
var qs = new Dictionary<string, HangmanTerm[]>();
|
||||
foreach (var file in Directory.EnumerateFiles("data/hangman/", "*.yml"))
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = Yaml.Deserializer.Deserialize<HangmanTerm[]>(File.ReadAllText(file));
|
||||
qs[Path.GetFileNameWithoutExtension(file).ToLowerInvariant()] = data;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Loading {HangmanFile} failed.", file);
|
||||
}
|
||||
}
|
||||
|
||||
_terms = qs;
|
||||
|
||||
Log.Information("Loaded {HangmanCategoryCount} hangman categories.", qs.Count);
|
||||
}
|
||||
|
||||
public IReadOnlyCollection<string> GetCategories()
|
||||
=> _terms.Keys.ToList();
|
||||
|
||||
public bool GetTerm(string? category, [NotNullWhen(true)] out HangmanTerm? term)
|
||||
{
|
||||
if (category is null)
|
||||
{
|
||||
var cats = GetCategories();
|
||||
category = cats.ElementAt(_rng.Next(0, cats.Count));
|
||||
}
|
||||
|
||||
if (_terms.TryGetValue(category, out var terms))
|
||||
{
|
||||
term = terms[_rng.Next(0, terms.Length)];
|
||||
return true;
|
||||
}
|
||||
|
||||
term = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,19 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Common.Hangman.Exceptions
|
||||
{
|
||||
public class TermNotFoundException : Exception
|
||||
{
|
||||
public TermNotFoundException() : base("Term of that type couldn't be found")
|
||||
{
|
||||
}
|
||||
|
||||
public TermNotFoundException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public TermNotFoundException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,170 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Extensions;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Common.Hangman
|
||||
{
|
||||
public sealed class Hangman : IDisposable
|
||||
{
|
||||
public string TermType { get; }
|
||||
public TermPool TermPool { get; }
|
||||
public HangmanObject Term { get; }
|
||||
|
||||
public string ScrambledWord => "`" + String.Concat(Term.Word.Select(c =>
|
||||
{
|
||||
if (c == ' ')
|
||||
return " \u2000";
|
||||
if (!(char.IsLetter(c) || char.IsDigit(c)))
|
||||
return $" {c}";
|
||||
|
||||
c = char.ToLowerInvariant(c);
|
||||
return _previousGuesses.Contains(c) ? $" {c}" : " ◯";
|
||||
})) + "`";
|
||||
|
||||
private Phase _currentPhase = Phase.Active;
|
||||
public Phase CurrentPhase
|
||||
{
|
||||
get => _currentPhase;
|
||||
set
|
||||
{
|
||||
if (value == Phase.Ended)
|
||||
_endingCompletionSource.TrySetResult(true);
|
||||
|
||||
_currentPhase = value;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly SemaphoreSlim _locker = new SemaphoreSlim(1, 1);
|
||||
|
||||
private readonly HashSet<ulong> _recentUsers = new HashSet<ulong>();
|
||||
|
||||
public uint Errors { get; private set; } = 0;
|
||||
public uint MaxErrors { get; } = 6;
|
||||
|
||||
public event Func<Hangman, string, ulong, Task> OnGameEnded = delegate { return Task.CompletedTask; };
|
||||
public event Func<Hangman, string, char, Task> OnLetterAlreadyUsed = delegate { return Task.CompletedTask; };
|
||||
public event Func<Hangman, string, char, Task> OnGuessFailed = delegate { return Task.CompletedTask; };
|
||||
public event Func<Hangman, string, char, Task> OnGuessSucceeded = delegate { return Task.CompletedTask; };
|
||||
|
||||
private readonly HashSet<char> _previousGuesses = new HashSet<char>();
|
||||
public ImmutableArray<char> PreviousGuesses => _previousGuesses.ToImmutableArray();
|
||||
|
||||
private readonly TaskCompletionSource<bool> _endingCompletionSource = new TaskCompletionSource<bool>();
|
||||
|
||||
public Task EndedTask => _endingCompletionSource.Task;
|
||||
|
||||
public Hangman(string type, TermPool tp = null)
|
||||
{
|
||||
this.TermType = type.Trim().ToLowerInvariant().ToTitleCase();
|
||||
this.TermPool = tp ?? new TermPool();
|
||||
this.Term = this.TermPool.GetTerm(type);
|
||||
}
|
||||
|
||||
private void AddError()
|
||||
{
|
||||
if (++Errors > MaxErrors)
|
||||
{
|
||||
var _ = OnGameEnded(this, null, 0);
|
||||
CurrentPhase = Phase.Ended;
|
||||
}
|
||||
}
|
||||
|
||||
public string GetHangman() => $@". ┌─────┐
|
||||
.┃...............┋
|
||||
.┃...............┋
|
||||
.┃{(Errors > 0 ? ".............😲" : "")}
|
||||
.┃{(Errors > 1 ? "............./" : "")} {(Errors > 2 ? "|" : "")} {(Errors > 3 ? "\\" : "")}
|
||||
.┃{(Errors > 4 ? "............../" : "")} {(Errors > 5 ? "\\" : "")}
|
||||
/-\";
|
||||
|
||||
public async Task Input(ulong userId, string userName, string input)
|
||||
{
|
||||
if (CurrentPhase == Phase.Ended)
|
||||
return;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
return;
|
||||
|
||||
input = input.Trim().ToLowerInvariant();
|
||||
|
||||
await _locker.WaitAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
if (CurrentPhase == Phase.Ended)
|
||||
return;
|
||||
|
||||
if (input.Length > 1) // tried to guess the whole word
|
||||
{
|
||||
if (input != Term.Word) // failed
|
||||
return;
|
||||
|
||||
var _ = OnGameEnded?.Invoke(this, userName, userId);
|
||||
CurrentPhase = Phase.Ended;
|
||||
return;
|
||||
}
|
||||
|
||||
var ch = input[0];
|
||||
|
||||
if (!char.IsLetterOrDigit(ch))
|
||||
return;
|
||||
|
||||
if (!_recentUsers.Add(userId)) // don't let a single user spam guesses
|
||||
return;
|
||||
|
||||
if (!_previousGuesses.Add(ch)) // that letter was already guessed
|
||||
{
|
||||
var _ = OnLetterAlreadyUsed?.Invoke(this, userName, ch);
|
||||
}
|
||||
else if (!Term.Word.Contains(ch)) // guessed letter doesn't exist
|
||||
{
|
||||
var _ = OnGuessFailed?.Invoke(this, userName, ch);
|
||||
AddError();
|
||||
}
|
||||
else if (Term.Word.All(x => _previousGuesses.IsSupersetOf(Term.Word.ToLowerInvariant()
|
||||
.Where(char.IsLetterOrDigit))))
|
||||
{
|
||||
var _ = OnGameEnded.Invoke(this, userName, userId); // if all letters are guessed
|
||||
CurrentPhase = Phase.Ended;
|
||||
}
|
||||
else // guessed but not last letter
|
||||
{
|
||||
var _ = OnGuessSucceeded?.Invoke(this, userName, ch);
|
||||
_recentUsers.Remove(userId); // he can guess again right away
|
||||
return;
|
||||
}
|
||||
|
||||
var clearSpam = Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(3000).ConfigureAwait(false); // remove the user from the spamlist after 5 seconds
|
||||
_recentUsers.Remove(userId);
|
||||
});
|
||||
}
|
||||
finally { _locker.Release(); }
|
||||
}
|
||||
|
||||
public async Task Stop()
|
||||
{
|
||||
await _locker.WaitAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
CurrentPhase = Phase.Ended;
|
||||
}
|
||||
finally { _locker.Release(); }
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
OnGameEnded = null;
|
||||
OnGuessFailed = null;
|
||||
OnGuessSucceeded = null;
|
||||
OnLetterAlreadyUsed = null;
|
||||
_previousGuesses.Clear();
|
||||
_recentUsers.Clear();
|
||||
// _locker.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
122
src/NadekoBot/Modules/Games/Common/Hangman/HangmanGame.cs
Normal file
122
src/NadekoBot/Modules/Games/Common/Hangman/HangmanGame.cs
Normal file
@@ -0,0 +1,122 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AngleSharp.Text;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Hangman
|
||||
{
|
||||
public sealed class HangmanGame
|
||||
{
|
||||
public enum Phase { Running, Ended }
|
||||
public enum GuessResult { NoAction, AlreadyTried, Incorrect, Guess, Win }
|
||||
|
||||
public record State(
|
||||
int Errors,
|
||||
Phase Phase,
|
||||
string Word,
|
||||
GuessResult GuessResult,
|
||||
List<char> missedLetters,
|
||||
string ImageUrl)
|
||||
{
|
||||
public bool Failed => Errors > 5;
|
||||
}
|
||||
|
||||
private Phase CurrentPhase { get; set; }
|
||||
|
||||
private readonly HashSet<char> _incorrect = new();
|
||||
private readonly HashSet<char> _correct = new();
|
||||
private readonly HashSet<char> _remaining = new();
|
||||
|
||||
private readonly string _word;
|
||||
private readonly string _imageUrl;
|
||||
|
||||
public HangmanGame(HangmanTerm term)
|
||||
{
|
||||
_word = term.Word;
|
||||
_imageUrl = term.ImageUrl;
|
||||
|
||||
_remaining = _word
|
||||
.ToLowerInvariant()
|
||||
.Where(x => x.IsLetter())
|
||||
.Select(char.ToLowerInvariant)
|
||||
.ToHashSet();
|
||||
}
|
||||
|
||||
public State GetState(GuessResult guessResult = GuessResult.NoAction)
|
||||
=> new State(_incorrect.Count,
|
||||
CurrentPhase,
|
||||
CurrentPhase == Phase.Ended
|
||||
? _word
|
||||
: GetScrambledWord(),
|
||||
guessResult,
|
||||
_incorrect.ToList(),
|
||||
CurrentPhase == Phase.Ended
|
||||
? _imageUrl
|
||||
: string.Empty);
|
||||
|
||||
private string GetScrambledWord()
|
||||
{
|
||||
Span<char> output = stackalloc char[_word.Length * 2];
|
||||
for (var i = 0; i < _word.Length; i++)
|
||||
{
|
||||
var ch = _word[i];
|
||||
if (ch == ' ')
|
||||
output[i*2] = ' ';
|
||||
if (!ch.IsLetter() || !_remaining.Contains(char.ToLowerInvariant(ch)))
|
||||
output[i*2] = ch;
|
||||
else
|
||||
output[i*2] = '_';
|
||||
|
||||
output[i * 2 + 1] = ' ';
|
||||
}
|
||||
|
||||
return new(output);
|
||||
}
|
||||
|
||||
// todo lock
|
||||
public State Guess(string guess)
|
||||
{
|
||||
if (CurrentPhase != Phase.Running)
|
||||
return GetState(GuessResult.NoAction);
|
||||
|
||||
guess = guess.Trim();
|
||||
if (guess.Length > 1)
|
||||
{
|
||||
if (guess.Equals(_word, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
CurrentPhase = Phase.Ended;
|
||||
return GetState(GuessResult.Win);
|
||||
}
|
||||
|
||||
return GetState(GuessResult.NoAction);
|
||||
}
|
||||
|
||||
var charGuess = guess[0];
|
||||
if (!char.IsLetter(charGuess))
|
||||
return GetState(GuessResult.NoAction);
|
||||
|
||||
if (_incorrect.Contains(charGuess) || _correct.Contains(charGuess))
|
||||
return GetState(GuessResult.AlreadyTried);
|
||||
|
||||
if (_remaining.Remove(charGuess))
|
||||
{
|
||||
if (_remaining.Count == 0)
|
||||
{
|
||||
CurrentPhase = Phase.Ended;
|
||||
return GetState(GuessResult.Win);
|
||||
}
|
||||
|
||||
return GetState(GuessResult.Guess);
|
||||
}
|
||||
|
||||
_incorrect.Add(charGuess);
|
||||
if (_incorrect.Count > 5)
|
||||
{
|
||||
CurrentPhase = Phase.Ended;
|
||||
return GetState(GuessResult.Incorrect);
|
||||
}
|
||||
|
||||
return GetState(GuessResult.Incorrect);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,17 +0,0 @@
|
||||
using NadekoBot.Extensions;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Common.Hangman
|
||||
{
|
||||
public class HangmanObject
|
||||
{
|
||||
public string Word { get; set; }
|
||||
public string ImageUrl { get; set; }
|
||||
|
||||
public string GetWord()
|
||||
{
|
||||
var term = Word.ToTitleCase();
|
||||
|
||||
return $"[{term}](https://en.wikipedia.org/wiki/{term.Replace(' ', '_')})";
|
||||
}
|
||||
}
|
||||
}
|
147
src/NadekoBot/Modules/Games/Common/Hangman/HangmanService.cs
Normal file
147
src/NadekoBot/Modules/Games/Common/Hangman/HangmanService.cs
Normal file
@@ -0,0 +1,147 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Games.Services;
|
||||
using NadekoBot.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Hangman
|
||||
{
|
||||
public sealed class HangmanService : IHangmanService, ILateExecutor
|
||||
{
|
||||
private readonly ConcurrentDictionary<ulong, HangmanGame> _hangmanGames = new();
|
||||
private readonly IHangmanSource _source;
|
||||
private readonly IEmbedBuilderService _eb;
|
||||
private readonly GamesConfigService _gcs;
|
||||
private readonly ICurrencyService _cs;
|
||||
private readonly IMemoryCache _cdCache;
|
||||
private readonly object _locker = new();
|
||||
|
||||
public HangmanService(IHangmanSource source, IEmbedBuilderService eb, GamesConfigService gcs,
|
||||
ICurrencyService cs, IMemoryCache cdCache)
|
||||
{
|
||||
_source = source;
|
||||
_eb = eb;
|
||||
_gcs = gcs;
|
||||
_cs = cs;
|
||||
_cdCache = cdCache;
|
||||
}
|
||||
|
||||
public bool StartHangman(
|
||||
ulong channelId,
|
||||
string? category,
|
||||
[NotNullWhen(true)] out HangmanGame.State? state)
|
||||
{
|
||||
state = null;
|
||||
if (!_source.GetTerm(category, out var term))
|
||||
return false;
|
||||
|
||||
|
||||
var game = new HangmanGame(term);
|
||||
lock (_locker)
|
||||
{
|
||||
var hc = _hangmanGames.GetOrAdd(channelId, game);
|
||||
if (hc == game)
|
||||
{
|
||||
state = hc.GetState();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public ValueTask<bool> StopHangman(ulong channelId)
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
if (_hangmanGames.TryRemove(channelId, out var game))
|
||||
{
|
||||
return new(true);
|
||||
}
|
||||
}
|
||||
|
||||
return new(false);
|
||||
}
|
||||
|
||||
public IReadOnlyCollection<string> GetHangmanTypes()
|
||||
=> _source.GetCategories();
|
||||
|
||||
public async Task LateExecute(IGuild guild, IUserMessage msg)
|
||||
{
|
||||
if (_hangmanGames.ContainsKey(msg.Channel.Id))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(msg.Content))
|
||||
return;
|
||||
|
||||
if (_cdCache.TryGetValue(msg.Author.Id, out _))
|
||||
return;
|
||||
|
||||
HangmanGame.State state;
|
||||
long rew = 0;
|
||||
lock (_locker)
|
||||
{
|
||||
if (!_hangmanGames.TryGetValue(msg.Channel.Id, out var game))
|
||||
return;
|
||||
|
||||
state = game.Guess(msg.Content.ToLowerInvariant());
|
||||
|
||||
if (state.GuessResult == HangmanGame.GuessResult.NoAction)
|
||||
return;
|
||||
|
||||
if (state.GuessResult == HangmanGame.GuessResult.Incorrect
|
||||
|| state.GuessResult == HangmanGame.GuessResult.AlreadyTried)
|
||||
{
|
||||
_cdCache.Set(msg.Author.Id, string.Empty, new MemoryCacheEntryOptions()
|
||||
{
|
||||
AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(3)
|
||||
});
|
||||
}
|
||||
|
||||
if (state.Phase == HangmanGame.Phase.Ended)
|
||||
if (_hangmanGames.TryRemove(msg.Channel.Id, out _))
|
||||
rew = _gcs.Data.Hangman.CurrencyReward;
|
||||
}
|
||||
|
||||
if (rew > 0)
|
||||
await _cs.AddAsync(msg.Author, "hangman win", rew, gamble: true);
|
||||
|
||||
await SendState((ITextChannel)msg.Channel, msg.Author, msg.Content, state);
|
||||
}
|
||||
}
|
||||
|
||||
private Task<IUserMessage> SendState(ITextChannel channel, IUser user, string content, HangmanGame.State state)
|
||||
{
|
||||
var embed = Games.HangmanCommands.GetEmbed(_eb, state);
|
||||
if (state.GuessResult == HangmanGame.GuessResult.Guess)
|
||||
embed.WithDescription($"{user} guessed the letter {content}!")
|
||||
.WithOkColor();
|
||||
else if (state.GuessResult == HangmanGame.GuessResult.Incorrect && state.Failed)
|
||||
embed.WithDescription($"{user} Letter {content} doesn't exist! Game over!")
|
||||
.WithErrorColor();
|
||||
else if (state.GuessResult == HangmanGame.GuessResult.Incorrect)
|
||||
embed.WithDescription($"{user} Letter {content} doesn't exist!")
|
||||
.WithErrorColor();
|
||||
else if (state.GuessResult == HangmanGame.GuessResult.AlreadyTried)
|
||||
embed.WithDescription($"{user} Letter {content} has already been used.")
|
||||
.WithPendingColor();
|
||||
else if (state.GuessResult == HangmanGame.GuessResult.Win)
|
||||
embed.WithDescription($"{user} won!")
|
||||
.WithOkColor();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(state.ImageUrl)
|
||||
&& Uri.IsWellFormedUriString(state.ImageUrl, UriKind.Absolute))
|
||||
{
|
||||
embed.WithImageUrl(state.ImageUrl);
|
||||
}
|
||||
|
||||
return channel.EmbedAsync(embed);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
namespace NadekoBot.Modules.Games.Hangman
|
||||
{
|
||||
public sealed class HangmanTerm
|
||||
{
|
||||
public string Word { get; set; }
|
||||
public string ImageUrl { get; set; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Hangman
|
||||
{
|
||||
public interface IHangmanService
|
||||
{
|
||||
bool StartHangman(ulong channelId, string? category, [NotNullWhen(true)] out HangmanGame.State? hangmanController);
|
||||
ValueTask<bool> StopHangman(ulong channelId);
|
||||
IReadOnlyCollection<string> GetHangmanTypes();
|
||||
}
|
||||
}
|
14
src/NadekoBot/Modules/Games/Common/Hangman/IHangmanSource.cs
Normal file
14
src/NadekoBot/Modules/Games/Common/Hangman/IHangmanSource.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using NadekoBot.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Hangman
|
||||
{
|
||||
public interface IHangmanSource : INService
|
||||
{
|
||||
public IReadOnlyCollection<string> GetCategories();
|
||||
public void Reload();
|
||||
public bool GetTerm(string? category, [NotNullWhen(true)] out HangmanTerm? term);
|
||||
}
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
namespace NadekoBot.Modules.Games.Common.Hangman
|
||||
{
|
||||
public enum Phase
|
||||
{
|
||||
Active,
|
||||
Ended,
|
||||
}
|
||||
}
|
@@ -1,50 +0,0 @@
|
||||
using NadekoBot.Common;
|
||||
using NadekoBot.Modules.Games.Common.Hangman.Exceptions;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Serilog;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Common.Hangman
|
||||
{
|
||||
public class TermPool
|
||||
{
|
||||
const string termsPath = "data/hangman.json";
|
||||
|
||||
public IReadOnlyDictionary<string, HangmanObject[]> Data { get; } = new Dictionary<string, HangmanObject[]>();
|
||||
public TermPool()
|
||||
{
|
||||
try
|
||||
{
|
||||
Data = JsonConvert.DeserializeObject<Dictionary<string, HangmanObject[]>>(File.ReadAllText(termsPath));
|
||||
Data = Data.ToDictionary(
|
||||
x => x.Key.ToLowerInvariant(),
|
||||
x => x.Value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning(ex, "Error loading Hangman Term pool");
|
||||
}
|
||||
}
|
||||
|
||||
public HangmanObject GetTerm(string type)
|
||||
{
|
||||
type = type?.Trim().ToLowerInvariant();
|
||||
var rng = new NadekoRandom();
|
||||
|
||||
if (type == "random")
|
||||
{
|
||||
type = Data.Keys.ToArray()[rng.Next(0, Data.Keys.Count())];
|
||||
}
|
||||
if (!Data.TryGetValue(type, out var termTypes) || termTypes.Length == 0)
|
||||
throw new TermNotFoundException();
|
||||
|
||||
var obj = termTypes[rng.Next(0, termTypes.Length)];
|
||||
|
||||
obj.Word = obj.Word.Trim().ToLowerInvariant();
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,14 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Common.Hangman
|
||||
{
|
||||
[Flags]
|
||||
public enum TermTypes
|
||||
{
|
||||
Countries = 0,
|
||||
Movies = 1,
|
||||
Animals = 2,
|
||||
Things = 4,
|
||||
Random = 8,
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user