public void TestBuildAllAndCompare()
        {
            var minCars = 4;
            var maxCars = 50;
            var minRounds = 1;
            var maxRounds = 2;

            var builder = new PartialPerfectNGenerator();

            for (var rounds = minRounds; rounds <= maxRounds; rounds++)
            {
                for (var cars = minCars; cars <= maxCars; cars++)
                {
                    try
                    {
                        var races = builder.Build(cars, rounds);
                        if (cars == 23 && rounds == 2)
                        {
                            Console.Write("");
                        }
                        var raceList = GetRaceList(cars);
                        foreach (var race in races)
                        {
                            for (int i = 0; i < race.Length; i++)
                            {
                                for (int j = 0; j < race.Length; j++)
                                {
                                    if (i != j)
                                    {
                                        var key = Key(race[i], race[j]);
                                        if (!raceList.ContainsKey(key))
                                        {
                                            Console.Write("");
                                        }
                                        raceList[key]++;
                                    }
                                }
                            }
                        }
                        var min = raceList.MinR(l => l.Value);
                        var max = raceList.MaxR(l => l.Value);
                        if (max.Value - min.Value > 1)
                        {
                            Console.WriteLine("Race {0}x{1} has a min|max of {2}|{3}", cars, rounds, string.Join("-", min.Key, min.Value), string.Join("-", max.Key, max.Value));
                        }
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine("Error building {0}x{1}\n{2}", cars, rounds, e);
                    }

                }
            }
        }
        public void TestBuildAllAndCompare()
        {
            var minCars   = 4;
            var maxCars   = 50;
            var minRounds = 1;
            var maxRounds = 2;

            var builder = new PartialPerfectNGenerator();

            for (var rounds = minRounds; rounds <= maxRounds; rounds++)
            {
                for (var cars = minCars; cars <= maxCars; cars++)
                {
                    try
                    {
                        var races = builder.Build(cars, rounds);
                        if (cars == 23 && rounds == 2)
                        {
                            Console.Write("");
                        }
                        var raceList = GetRaceList(cars);
                        foreach (var race in races)
                        {
                            for (int i = 0; i < race.Length; i++)
                            {
                                for (int j = 0; j < race.Length; j++)
                                {
                                    if (i != j)
                                    {
                                        var key = Key(race[i], race[j]);
                                        if (!raceList.ContainsKey(key))
                                        {
                                            Console.Write("");
                                        }
                                        raceList[key]++;
                                    }
                                }
                            }
                        }
                        var min = raceList.MinR(l => l.Value);
                        var max = raceList.MaxR(l => l.Value);
                        if (max.Value - min.Value > 1)
                        {
                            Console.WriteLine("Race {0}x{1} has a min|max of {2}|{3}", cars, rounds, string.Join("-", min.Key, min.Value), string.Join("-", max.Key, max.Value));
                        }
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine("Error building {0}x{1}\n{2}", cars, rounds, e);
                    }
                }
            }
        }
        private void BuildAndWrite(int cars, int rounds)
        {
            var builder = new PartialPerfectNGenerator();
            var races   = builder.Build(cars, rounds);

            var ints = 1.To(cars);

            foreach (var r in races)
            {
                Console.WriteLine(string.Join("\t", r));
            }
            Console.WriteLine("\t" + string.Join("\t", ints));
            foreach (var i in ints)
            {
                var racesWithI = races.Where(r => r.Contains(i));
                Console.WriteLine(i + "\t" + string.Join("\t", ints.Select(r1 => racesWithI.Count(r => r.Contains(r1)))));
            }
        }
        private void Optimize(int cars, int rounds, int[] seedA = null)
        {
            var bestXSquared = int.MaxValue;
            var test         = new[] { 0, 0, 0 };
            var best         = test;

            var builder = new PartialPerfectNGenerator();

            var testCases = BuildTestCases(test, cars);
            var total     = Math.Pow(cars - 1, test.Length).ToInt();
            var counter   = 0;

            seedA = seedA ?? new[] { 2, 3, 4 };
            foreach (var testCase in testCases)
            {
                counter++;
                if (counter % 100 == 0)
                {
                    Console.WriteLine("Running test {0} of {1}", counter.ToString("N0"), total.ToString("N0"));
                    Console.WriteLine("Current leader {0} with {1}", string.Join(",", best), bestXSquared);
                }
                var seedB = new[] { testCase[0], testCase[1], testCase[2] };
                var races = builder.GetRaces(cars, rounds, seedA, seedB);

                var ints = 1.To(cars);

                var xSquared = 0;
                foreach (var i in ints)
                {
                    var racesWithI = races.Where(r => r.Contains(i));
                    var counts     = ints.Where(r1 => r1 != i).Select(r1 => racesWithI.Count(r => r.Contains(r1)));
                    foreach (var count in counts)
                    {
                        xSquared += Math.Pow(count - 1, 2).ToInt();
                    }
                }
                if (xSquared < bestXSquared)
                {
                    bestXSquared = xSquared;
                    best         = testCase;
                }
            }
            Console.WriteLine(JsonConvert.SerializeObject(best));
        }
        private void BuildAndWrite(int cars, int rounds)
        {
            var builder = new PartialPerfectNGenerator();
            var races = builder.Build(cars, rounds);

            var ints = 1.To(cars);

            foreach (var r in races)
            {
                Console.WriteLine(string.Join("\t", r));
            }
            Console.WriteLine("\t"+string.Join("\t", ints));
            foreach (var i in ints)
            {
                var racesWithI = races.Where(r => r.Contains(i));
                Console.WriteLine(i+"\t"+string.Join("\t", ints.Select(r1 => racesWithI.Count(r => r.Contains(r1)))));
            }
        }
        private void Optimize(int cars, int rounds, int[] seedA = null)
        {
            var bestXSquared = int.MaxValue;
            var test = new[] {0, 0, 0};
            var best = test;

            var builder = new PartialPerfectNGenerator();

            var testCases = BuildTestCases(test, cars);
            var total = Math.Pow(cars-1, test.Length).ToInt();
            var counter = 0;
            seedA = seedA ?? new[] { 2, 3, 4 };
            foreach (var testCase in testCases)
            {
                counter++;
                if (counter%100 == 0)
                {
                    Console.WriteLine("Running test {0} of {1}", counter.ToString("N0"), total.ToString("N0"));
                    Console.WriteLine("Current leader {0} with {1}", string.Join(",", best), bestXSquared);
                }
                var seedB = new[] {testCase[0], testCase[1], testCase[2]};
                var races = builder.GetRaces(cars, rounds, seedA, seedB);

                var ints = 1.To(cars);

                var xSquared = 0;
                foreach (var i in ints)
                {
                    var racesWithI = races.Where(r => r.Contains(i));
                    var counts = ints.Where(r1 => r1 != i).Select(r1 => racesWithI.Count(r => r.Contains(r1)));
                    foreach (var count in counts)
                    {
                        xSquared += Math.Pow(count-1, 2).ToInt();
                    }
                }
                if (xSquared < bestXSquared)
                {
                    bestXSquared = xSquared;
                    best = testCase;
                }
            }
            Console.WriteLine(JsonConvert.SerializeObject(best));
        }