Skip to content

Instantly share code, notes, and snippets.

@archer884
Last active August 29, 2015 14:10
Show Gist options
  • Save archer884/1a427c0b4fc102041927 to your computer and use it in GitHub Desktop.
Save archer884/1a427c0b4fc102041927 to your computer and use it in GitHub Desktop.
Dice rolling program
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);
}
}
}
@archer884
Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment