Last active
August 29, 2015 14:10
-
-
Save archer884/1a427c0b4fc102041927 to your computer and use it in GitHub Desktop.
Dice rolling program
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Security.Cryptography; | |
namespace Dice | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var prng = new CryptoRandom(); | |
var rolls = args | |
.Select(RollParameters.Parse) | |
.Where(NotNull); | |
foreach (var roll in rolls) | |
{ | |
var values = roll.Execute(max => prng.Next(max) + 1); | |
Console.WriteLine(RollString(values)); | |
} | |
} | |
static string RollString(ICollection<int> values) | |
{ | |
return String.Format("{0} ({1})", values.Sum(), String.Join(", ", values)); | |
} | |
static bool NotNull(object instance) | |
{ | |
return instance != null; | |
} | |
} | |
class RollParameters | |
{ | |
int _dice; | |
int _range; | |
private RollParameters(int dice, int range) | |
{ | |
_dice = dice; | |
_range = range; | |
} | |
public static RollParameters Parse(string input) | |
{ | |
var data = input.Split('d'); | |
if (data.Length != 2) | |
return null; | |
return new RollParameters( | |
Math.Abs(Int32.Parse(data[0])), | |
Math.Abs(Int32.Parse(data[1]))); | |
} | |
public ICollection<int> Execute(Func<int, int> prng) | |
{ | |
return Enumerable.Range(0, _dice).Select(_ => prng(_range)).ToList(); | |
} | |
} | |
// from: http://msdn.microsoft.com/en-us/magazine/cc163367.aspx | |
// credit to Stephen Toub and Shawn Farkas | |
// Microsoft Limited Public License | |
public class CryptoRandom : Random | |
{ | |
private RNGCryptoServiceProvider _rng = new RNGCryptoServiceProvider(); | |
private byte[] _uint32Buffer = new byte[4]; | |
public CryptoRandom() { } | |
public CryptoRandom(Int32 ignoredSeed) { } | |
public override Int32 Next() | |
{ | |
_rng.GetBytes(_uint32Buffer); | |
return BitConverter.ToInt32(_uint32Buffer, 0) & 0x7FFFFFFF; | |
} | |
public override Int32 Next(Int32 maxValue) | |
{ | |
if (maxValue < 0) | |
throw new ArgumentOutOfRangeException("maxValue"); | |
return Next(0, maxValue); | |
} | |
public override Int32 Next(Int32 minValue, Int32 maxValue) | |
{ | |
if (minValue > maxValue) | |
throw new ArgumentOutOfRangeException("minValue"); | |
if (minValue == maxValue) | |
return minValue; | |
Int64 diff = maxValue - minValue; | |
while (true) | |
{ | |
_rng.GetBytes(_uint32Buffer); | |
UInt32 rand = BitConverter.ToUInt32(_uint32Buffer, 0); | |
Int64 max = (1 + (Int64)UInt32.MaxValue); | |
Int64 remainder = max % diff; | |
if (rand < max - remainder) | |
{ | |
return (Int32)(minValue + (rand % diff)); | |
} | |
} | |
} | |
public override double NextDouble() | |
{ | |
_rng.GetBytes(_uint32Buffer); | |
UInt32 rand = BitConverter.ToUInt32(_uint32Buffer, 0); | |
return rand / (1.0 + UInt32.MaxValue); | |
} | |
public override void NextBytes(byte[] buffer) | |
{ | |
if (buffer == null) throw new ArgumentNullException("buffer"); | |
_rng.GetBytes(buffer); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
As you can see, I have lifted a bit of code from MSDN to finish this out. You may be wondering why I'm using a cryptographic-quality (weapons-grade! :P) pseudo-random number generator for a piece of software that effectively replaces six dollars' worth of dice... Well,
System.Random
would have been more than adequate on Windows, but I found its performance to be abysmal on Linux, on the Mono runtime. (Like, fully fifty percent of all 2d* rolls resulted in doubles).The CryptoRandom class above exhibits no such misbehavior.