Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Linq;
- using System.Security.Cryptography;
- using System.Text;
- using System.Threading.Tasks;
- namespace ShuffleTests
- {
- class Program
- {
- static Random rnd = new Random();
- static void Main(string[] args)
- {
- while (true)
- {
- Console.WriteLine(new string('-', 10));
- Func<ulong[][]> generateTestData = () => Enumerable.Range(0, 1000).Select(_ => Enumerable.Range(1, 1000).Select(__ => (ulong)__).ToArray()).ToArray();
- Func<ulong, ulong, ulong> agg = (x, y) => x + y;
- Func<ulong[], string> aggToString = aggArray =>
- {
- var result = "";
- result = aggArray.Select(ag => Math.Abs(1 - ((double)ag / (double)aggArray.Sum(_ => (decimal)_) * aggArray.Length))).Sum().ToString("P");
- //foreach (var a in aggArray.Select(ag => ((double)ag/(double)aggArray.Sum() * aggArray.Length).ToString("P"))) result += a + ", ";
- return result;
- };
- var tests = new Dictionary<string, Func<ulong[], ulong[]>>
- {
- {"Orderby RNG", a => a.OrderBy(_ => rnd.Next()).ToArray()},
- {"Orderby CRNG", a => a.OrderBy(_ => Helper.CryptoRandomNumber(0,int.MaxValue)).ToArray()},
- {"Shuffle RNG", a => a.Shuffle(secure: false).ToArray()},
- {"Shuffle CRNG", a => a.Shuffle().ToArray()}
- };
- foreach (var test in tests)
- BenchmarkShuffle(test.Key, generateTestData, test.Value, agg, aggToString);
- Console.ReadLine();
- }
- /*var bjd = new BJDeck();
- bjd.cards.ForEach(c => { Console.WriteLine(c.rank + " of " + c.suit); System.Threading.Thread.Sleep(100); });
- Console.ReadLine();*/
- }
- static void BenchmarkShuffle<T>(string name, Func<T[][]> testDataGenerator, Func<T[], T[]> shuffler, Func<T, T, T> aggregator, Func<T[], String> AggToString)
- {
- Console.Write("Starting Test {0}", name);
- var sw = Stopwatch.StartNew();
- var testData = testDataGenerator();
- foreach (var t in testData) if (t.Length != testData[0].Length) throw new Exception("All test data arrays must be of the same length!");
- sw.Stop();
- Console.WriteLine(" -- Test Data Generated in {0}ms", sw.ElapsedMilliseconds);
- T[] aggregatedData = new T[testData[0].Length];
- sw.Restart();
- foreach (var shuffled in testData.Select(x => shuffler(x)))
- for (int i = 0; i < shuffled.Length; i++)
- aggregatedData[i] = aggregator(shuffled[i], aggregatedData[i]);
- sw.Stop();
- Console.WriteLine("Finished Shuffing in {0}ms!", sw.ElapsedMilliseconds);
- Console.WriteLine(AggToString(aggregatedData));
- Console.WriteLine();
- }
- }
- public static class Helper
- {
- static Random rnd = new Random();
- /// <summary>
- /// Shuffles a list using the Fisher–Yates method. Returns source to be fluid.
- /// </summary>
- public static IList<T> Shuffle<T>(this IList<T> source, bool secure = true)
- {
- for (int i = source.Count - 1; i > 0; i--)
- {
- var rndInt = secure ? CryptoRandomNumber(0, i + 1) : rnd.Next(i + 1);
- T temp = source[rndInt];
- source[rndInt] = source[i];
- source[i] = temp;
- }
- return source;
- }
- static byte[] randNumBuffer = new byte[4];
- private static RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider();
- /// <summary>
- /// Generates a number between start [Inc] and end [Excl]
- /// </summary>
- /// <param name="start">Inslusive</param>
- /// <param name="end">Exclusive</param>
- public static int CryptoRandomNumber(int start, int end)
- {
- int range = end - start;
- if (range < 1 || range > int.MaxValue) throw new ArgumentOutOfRangeException("Range is below 1 or bigger than int.MaxValue");
- int randomNumber = -1;
- for (; !IsFullSet(randomNumber, range); randomNumber = BitConverter.ToInt32(randNumBuffer, 0)) rngCsp.GetBytes(randNumBuffer);
- return (randomNumber % range) + start;
- }
- private static bool IsFullSet(int roll, int range)
- {
- int fullSetsOfValues = int.MaxValue / range;
- return roll < range * fullSetsOfValues && roll >= 0;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement