Advertisement
NPSF3000

Shuffler

Mar 27th, 2013
331
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 4.77 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Linq;
  5. using System.Security.Cryptography;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8.  
  9. namespace ShuffleTests
  10. {
  11.     class Program
  12.     {
  13.         static Random rnd = new Random();
  14.         static void Main(string[] args)
  15.         {
  16.             while (true)
  17.             {
  18.  
  19.                 Console.WriteLine(new string('-', 10));
  20.                 Func<ulong[][]> generateTestData = () => Enumerable.Range(0, 1000).Select(_ => Enumerable.Range(1, 1000).Select(__ => (ulong)__).ToArray()).ToArray();
  21.                 Func<ulong, ulong, ulong> agg = (x, y) => x + y;
  22.                 Func<ulong[], string> aggToString = aggArray =>
  23.                 {
  24.                     var result = "";
  25.                     result = aggArray.Select(ag => Math.Abs(1 - ((double)ag / (double)aggArray.Sum(_ => (decimal)_) * aggArray.Length))).Sum().ToString("P");
  26.                     //foreach (var a in aggArray.Select(ag => ((double)ag/(double)aggArray.Sum() * aggArray.Length).ToString("P"))) result += a + ", ";
  27.                     return result;
  28.                 };
  29.  
  30.                 var tests = new Dictionary<string, Func<ulong[], ulong[]>>
  31.                 {
  32.                     {"Orderby RNG",  a => a.OrderBy(_ => rnd.Next()).ToArray()},
  33.                     {"Orderby CRNG", a => a.OrderBy(_ => Helper.CryptoRandomNumber(0,int.MaxValue)).ToArray()},
  34.                     {"Shuffle RNG", a => a.Shuffle(secure: false).ToArray()},
  35.                     {"Shuffle CRNG",  a => a.Shuffle().ToArray()}
  36.                 };
  37.  
  38.                 foreach (var test in tests)
  39.                     BenchmarkShuffle(test.Key, generateTestData, test.Value, agg, aggToString);
  40.                 Console.ReadLine();
  41.             }
  42.             /*var bjd = new BJDeck();
  43.             bjd.cards.ForEach(c => { Console.WriteLine(c.rank + " of " + c.suit); System.Threading.Thread.Sleep(100); });
  44.             Console.ReadLine();*/
  45.         }
  46.  
  47.         static void BenchmarkShuffle<T>(string name, Func<T[][]> testDataGenerator, Func<T[], T[]> shuffler, Func<T, T, T> aggregator, Func<T[], String> AggToString)
  48.         {
  49.             Console.Write("Starting Test {0}", name);
  50.             var sw = Stopwatch.StartNew();
  51.             var testData = testDataGenerator();
  52.             foreach (var t in testData) if (t.Length != testData[0].Length) throw new Exception("All test data arrays must be of the same length!");
  53.             sw.Stop();
  54.             Console.WriteLine("  --  Test Data Generated in {0}ms", sw.ElapsedMilliseconds);
  55.  
  56.             T[] aggregatedData = new T[testData[0].Length];
  57.  
  58.             sw.Restart();
  59.  
  60.             foreach (var shuffled in testData.Select(x => shuffler(x)))
  61.                 for (int i = 0; i < shuffled.Length; i++)
  62.                     aggregatedData[i] = aggregator(shuffled[i], aggregatedData[i]);
  63.  
  64.             sw.Stop();
  65.  
  66.             Console.WriteLine("Finished Shuffing in {0}ms!", sw.ElapsedMilliseconds);
  67.             Console.WriteLine(AggToString(aggregatedData));
  68.  
  69.             Console.WriteLine();
  70.         }
  71.  
  72.     }
  73.  
  74.     public static class Helper
  75.     {
  76.         static Random rnd = new Random();
  77.  
  78.         /// <summary>
  79.         /// Shuffles a list using the Fisher–Yates method.  Returns source to be fluid.
  80.         /// </summary>
  81.         public static IList<T> Shuffle<T>(this IList<T> source, bool secure = true)
  82.         {
  83.             for (int i = source.Count - 1; i > 0; i--)
  84.             {
  85.                 var rndInt = secure ? CryptoRandomNumber(0, i + 1) : rnd.Next(i + 1);
  86.                 T temp = source[rndInt];
  87.                 source[rndInt] = source[i];
  88.                 source[i] = temp;
  89.             }
  90.             return source;
  91.         }
  92.  
  93.         static byte[] randNumBuffer = new byte[4];
  94.         private static RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider();
  95.         /// <summary>
  96.         /// Generates a number between start [Inc] and end [Excl]
  97.         /// </summary>
  98.         /// <param name="start">Inslusive</param>
  99.         /// <param name="end">Exclusive</param>
  100.         public static int CryptoRandomNumber(int start, int end)
  101.         {
  102.             int range = end - start;
  103.             if (range < 1 || range > int.MaxValue) throw new ArgumentOutOfRangeException("Range is below 1 or bigger than int.MaxValue");
  104.  
  105.             int randomNumber = -1;
  106.             for (; !IsFullSet(randomNumber, range); randomNumber = BitConverter.ToInt32(randNumBuffer, 0)) rngCsp.GetBytes(randNumBuffer);
  107.             return (randomNumber % range) + start;
  108.         }
  109.  
  110.         private static bool IsFullSet(int roll, int range)
  111.         {
  112.             int fullSetsOfValues = int.MaxValue / range;
  113.             return roll < range * fullSetsOfValues && roll >= 0;
  114.         }
  115.     }
  116. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement