From 4143180b42fe54b3e11a1821a6c3fdc98e7c5492 Mon Sep 17 00:00:00 2001 From: runebaas Date: Sat, 11 May 2019 01:18:22 +0200 Subject: [PATCH] Add a better random number generator --- Geekbot.net/Commands/Games/Roll.cs | 7 ++- Geekbot.net/Commands/Randomness/Ship.cs | 7 ++- Geekbot.net/Commands/Rpg/Cookies.cs | 7 ++- Geekbot.net/Commands/Utils/Dice/Dice.cs | 10 +++- Geekbot.net/Commands/Utils/Quote/Quote.cs | 7 ++- .../IRandomNumberGenerator.cs | 7 +++ .../RandomNumberGenerator.cs | 46 +++++++++++++++++++ Geekbot.net/Program.cs | 3 ++ 8 files changed, 85 insertions(+), 9 deletions(-) create mode 100644 Geekbot.net/Lib/RandomNumberGenerator/IRandomNumberGenerator.cs create mode 100644 Geekbot.net/Lib/RandomNumberGenerator/RandomNumberGenerator.cs diff --git a/Geekbot.net/Commands/Games/Roll.cs b/Geekbot.net/Commands/Games/Roll.cs index 8db295c..ac9279a 100644 --- a/Geekbot.net/Commands/Games/Roll.cs +++ b/Geekbot.net/Commands/Games/Roll.cs @@ -8,6 +8,7 @@ using Geekbot.net.Lib.AlmostRedis; using Geekbot.net.Lib.ErrorHandling; using Geekbot.net.Lib.Extensions; using Geekbot.net.Lib.Localization; +using Geekbot.net.Lib.RandomNumberGenerator; using StackExchange.Redis; namespace Geekbot.net.Commands.Games @@ -18,12 +19,14 @@ namespace Geekbot.net.Commands.Games private readonly IAlmostRedis _redis; private readonly ITranslationHandler _translation; private readonly DatabaseContext _database; + private readonly IRandomNumberGenerator _randomNumberGenerator; - public Roll(IAlmostRedis redis, IErrorHandler errorHandler, ITranslationHandler translation, DatabaseContext database) + public Roll(IAlmostRedis redis, IErrorHandler errorHandler, ITranslationHandler translation, DatabaseContext database, IRandomNumberGenerator randomNumberGenerator) { _redis = redis; _translation = translation; _database = database; + _randomNumberGenerator = randomNumberGenerator; _errorHandler = errorHandler; } @@ -33,7 +36,7 @@ namespace Geekbot.net.Commands.Games { try { - var number = new Random().Next(1, 100); + var number = _randomNumberGenerator.Next(1, 100); var guess = 1000; int.TryParse(stuff, out guess); var transDict = await _translation.GetDict(Context); diff --git a/Geekbot.net/Commands/Randomness/Ship.cs b/Geekbot.net/Commands/Randomness/Ship.cs index 45956b6..3d876ef 100644 --- a/Geekbot.net/Commands/Randomness/Ship.cs +++ b/Geekbot.net/Commands/Randomness/Ship.cs @@ -7,18 +7,21 @@ using Geekbot.net.Database; using Geekbot.net.Database.Models; using Geekbot.net.Lib.ErrorHandling; using Geekbot.net.Lib.Extensions; +using Geekbot.net.Lib.RandomNumberGenerator; namespace Geekbot.net.Commands.Randomness { public class Ship : ModuleBase { private readonly IErrorHandler _errorHandler; + private readonly IRandomNumberGenerator _randomNumberGenerator; private readonly DatabaseContext _database; - public Ship(DatabaseContext database, IErrorHandler errorHandler) + public Ship(DatabaseContext database, IErrorHandler errorHandler, IRandomNumberGenerator randomNumberGenerator) { _database = database; _errorHandler = errorHandler; + _randomNumberGenerator = randomNumberGenerator; } [Command("Ship", RunMode = RunMode.Async)] @@ -38,7 +41,7 @@ namespace Geekbot.net.Commands.Randomness var shippingRate = 0; if (dbval == null) { - shippingRate = new Random().Next(1, 100); + shippingRate = _randomNumberGenerator.Next(1, 100); _database.Ships.Add(new ShipsModel() { FirstUserId = userKeys.Item1, diff --git a/Geekbot.net/Commands/Rpg/Cookies.cs b/Geekbot.net/Commands/Rpg/Cookies.cs index 3e3e98c..594dd5e 100644 --- a/Geekbot.net/Commands/Rpg/Cookies.cs +++ b/Geekbot.net/Commands/Rpg/Cookies.cs @@ -9,6 +9,7 @@ using Geekbot.net.Lib.CommandPreconditions; using Geekbot.net.Lib.ErrorHandling; using Geekbot.net.Lib.Extensions; using Geekbot.net.Lib.Localization; +using Geekbot.net.Lib.RandomNumberGenerator; namespace Geekbot.net.Commands.Rpg { @@ -19,12 +20,14 @@ namespace Geekbot.net.Commands.Rpg private readonly DatabaseContext _database; private readonly IErrorHandler _errorHandler; private readonly ITranslationHandler _translation; + private readonly IRandomNumberGenerator _randomNumberGenerator; - public Cookies(DatabaseContext database, IErrorHandler errorHandler, ITranslationHandler translation) + public Cookies(DatabaseContext database, IErrorHandler errorHandler, ITranslationHandler translation , IRandomNumberGenerator randomNumberGenerator) { _database = database; _errorHandler = errorHandler; _translation = translation; + _randomNumberGenerator = randomNumberGenerator; } [Command("get", RunMode = RunMode.Async)] @@ -114,7 +117,7 @@ namespace Geekbot.net.Commands.Rpg return; } - var amount = new Random().Next(1, 5); + var amount = _randomNumberGenerator.Next(1, 5); actor.Cookies -= amount; await SetUser(actor); diff --git a/Geekbot.net/Commands/Utils/Dice/Dice.cs b/Geekbot.net/Commands/Utils/Dice/Dice.cs index 7733476..8b23fe6 100644 --- a/Geekbot.net/Commands/Utils/Dice/Dice.cs +++ b/Geekbot.net/Commands/Utils/Dice/Dice.cs @@ -4,11 +4,19 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Discord.Commands; +using Geekbot.net.Lib.RandomNumberGenerator; namespace Geekbot.net.Commands.Utils.Dice { public class Dice : ModuleBase { + private readonly IRandomNumberGenerator _randomNumberGenerator; + + public Dice(IRandomNumberGenerator randomNumberGenerator) + { + _randomNumberGenerator = randomNumberGenerator; + } + [Command("dice", RunMode = RunMode.Async)] [Summary("Roll a dice.")] public async Task RollCommand([Remainder] [Summary("diceType")] string diceType = "1d20") @@ -66,7 +74,7 @@ namespace Geekbot.net.Commands.Utils.Dice var results = new List(); for (var i = 0; i < dice.Times; i++) { - var roll = new Random().Next(1, dice.Sides); + var roll = _randomNumberGenerator.Next(1, dice.Sides); total += roll; results.Add(roll); if (roll == dice.Sides) extraText = "**Critical Hit!**"; diff --git a/Geekbot.net/Commands/Utils/Quote/Quote.cs b/Geekbot.net/Commands/Utils/Quote/Quote.cs index e2456e7..a6f3ec9 100644 --- a/Geekbot.net/Commands/Utils/Quote/Quote.cs +++ b/Geekbot.net/Commands/Utils/Quote/Quote.cs @@ -9,6 +9,7 @@ using Geekbot.net.Lib.CommandPreconditions; using Geekbot.net.Lib.ErrorHandling; using Geekbot.net.Lib.Extensions; using Geekbot.net.Lib.Polyfills; +using Geekbot.net.Lib.RandomNumberGenerator; namespace Geekbot.net.Commands.Utils.Quote { @@ -18,11 +19,13 @@ namespace Geekbot.net.Commands.Utils.Quote { private readonly IErrorHandler _errorHandler; private readonly DatabaseContext _database; + private readonly IRandomNumberGenerator _randomNumberGenerator; - public Quote(IErrorHandler errorHandler, DatabaseContext database) + public Quote(IErrorHandler errorHandler, DatabaseContext database, IRandomNumberGenerator randomNumberGenerator) { _errorHandler = errorHandler; _database = database; + _randomNumberGenerator = randomNumberGenerator; } [Command] @@ -39,7 +42,7 @@ namespace Geekbot.net.Commands.Utils.Quote return; } - var random = new Random().Next(s.Count()); + var random = _randomNumberGenerator.Next(0, s.Count()); var quote = s[random]; var embed = QuoteBuilder(quote); diff --git a/Geekbot.net/Lib/RandomNumberGenerator/IRandomNumberGenerator.cs b/Geekbot.net/Lib/RandomNumberGenerator/IRandomNumberGenerator.cs new file mode 100644 index 0000000..32c6285 --- /dev/null +++ b/Geekbot.net/Lib/RandomNumberGenerator/IRandomNumberGenerator.cs @@ -0,0 +1,7 @@ +namespace Geekbot.net.Lib.RandomNumberGenerator +{ + public interface IRandomNumberGenerator + { + int Next(int minValue, int maxExclusiveValue); + } +} \ No newline at end of file diff --git a/Geekbot.net/Lib/RandomNumberGenerator/RandomNumberGenerator.cs b/Geekbot.net/Lib/RandomNumberGenerator/RandomNumberGenerator.cs new file mode 100644 index 0000000..79b4620 --- /dev/null +++ b/Geekbot.net/Lib/RandomNumberGenerator/RandomNumberGenerator.cs @@ -0,0 +1,46 @@ +using System; +using System.Security.Cryptography; + +namespace Geekbot.net.Lib.RandomNumberGenerator +{ + public class RandomNumberGenerator : IRandomNumberGenerator + { + readonly RNGCryptoServiceProvider csp; + + public RandomNumberGenerator() + { + csp = new RNGCryptoServiceProvider(); + } + + public int Next(int minValue, int maxExclusiveValue) + { + if (minValue >= maxExclusiveValue) + { + throw new ArgumentOutOfRangeException("minValue must be lower than maxExclusiveValue"); + } + + var diff = (long)maxExclusiveValue - minValue; + var upperBound = uint.MaxValue / diff * diff; + + uint ui; + do + { + ui = GetRandomUInt(); + } while (ui >= upperBound); + return (int)(minValue + (ui % diff)); + } + + private uint GetRandomUInt() + { + var randomBytes = GenerateRandomBytes(sizeof(uint)); + return BitConverter.ToUInt32(randomBytes, 0); + } + + private byte[] GenerateRandomBytes(int bytesNumber) + { + var buffer = new byte[bytesNumber]; + csp.GetBytes(buffer); + return buffer; + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Program.cs b/Geekbot.net/Program.cs index 7b00055..43c16d1 100755 --- a/Geekbot.net/Program.cs +++ b/Geekbot.net/Program.cs @@ -19,6 +19,7 @@ using Geekbot.net.Lib.Levels; using Geekbot.net.Lib.Localization; using Geekbot.net.Lib.Logger; using Geekbot.net.Lib.Media; +using Geekbot.net.Lib.RandomNumberGenerator; using Geekbot.net.Lib.ReactionListener; using Geekbot.net.Lib.UserRepository; using Microsoft.EntityFrameworkCore; @@ -124,6 +125,7 @@ namespace Geekbot.net var mtgManaConverter = new MtgManaConverter(); var wikipediaClient = new WikipediaClient(); var audioUtils = new AudioUtils(); + var randomNumberGenerator = new RandomNumberGenerator(); _highscoreManager = new HighscoreManager(_databaseInitializer.Initialize(), _userRepository); _services.AddSingleton(_redis); @@ -137,6 +139,7 @@ namespace Geekbot.net _services.AddSingleton(mtgManaConverter); _services.AddSingleton(wikipediaClient); _services.AddSingleton(audioUtils); + _services.AddSingleton(randomNumberGenerator); _services.AddSingleton(_highscoreManager); _services.AddSingleton(_globalSettings); _services.AddTransient((e) => _databaseInitializer.Initialize());