public void TestSolveAsync1()
        {
            var seed = new NumberPlaceMatrix(new int[] {
                0, 6, 0, 8, 0, 0, 0, 0, 0,
                0, 2, 0, 4, 0, 0, 0, 7, 5,
                0, 0, 0, 0, 0, 3, 0, 0, 0,
                0, 0, 6, 0, 7, 0, 0, 9, 3,
                0, 0, 0, 5, 0, 1, 0, 0, 0,
                8, 3, 0, 0, 6, 0, 1, 0, 0,
                0, 0, 0, 1, 0, 0, 0, 0, 0,
                5, 7, 0, 0, 0, 9, 0, 6, 0,
                0, 0, 0, 0, 0, 7, 0, 2, 0
            });

            var solver = new NumberPlaceSolver();
            var results = solver.Solve(seed);

            Assert.AreEqual(1, results.Count());

            var expected = new int[] { 
                7, 6, 1, 8, 9, 5, 2, 3, 4,
                3, 2, 8, 4, 1, 6, 9, 7, 5,
                9, 4, 5, 7, 2, 3, 6, 1, 8,
                1, 5, 6, 2, 7, 8, 4, 9, 3,
                2, 9, 4, 5, 3, 1, 7, 8, 6,
                8, 3, 7, 9, 6, 4, 1, 5, 2,
                6, 8, 9, 1, 5, 2, 3, 4, 7,
                5, 7, 2, 3, 4, 9, 8, 6, 1,
                4, 1, 3, 6, 8, 7, 5, 2, 9
            };

            Assert.IsTrue(results.First().GetCells().Select(x => x.Value).ToArray().SequenceEqual(expected));
        }
        public void TestIsValidTrue()
        {
            var matrix = new NumberPlaceMatrix(new int[] { 
                7, 6, 1, 8, 9, 5, 2, 3, 4,
                3, 2, 8, 4, 1, 6, 9, 7, 5,
                9, 4, 5, 7, 2, 3, 6, 1, 8,
                1, 5, 6, 2, 7, 8, 4, 9, 3,
                2, 9, 4, 5, 3, 1, 7, 8, 6,
                8, 3, 7, 9, 6, 4, 1, 5, 2,
                6, 8, 9, 1, 5, 2, 3, 4, 7,
                5, 7, 2, 3, 4, 9, 8, 6, 1,
                4, 1, 3, 6, 8, 7, 5, 2, 9
            });

            Assert.IsTrue(matrix.IsValid());
        }
        public void TestIsValidFalse3()
        {
            var matrix = new NumberPlaceMatrix(new int[] { 
                1, 2, 3, 1, 2, 3, 1, 2, 3, 
                4, 5, 6, 4, 5, 6, 4, 5, 6, 
                7, 8, 9, 7, 8, 9, 7, 8, 9, 
                1, 2, 3, 1, 2, 3, 1, 2, 3, 
                4, 5, 6, 4, 5, 6, 4, 5, 6, 
                7, 8, 9, 7, 8, 9, 7, 8, 9, 
                1, 2, 3, 1, 2, 3, 1, 2, 3, 
                4, 5, 6, 4, 5, 6, 4, 5, 6, 
                7, 8, 9, 7, 8, 9, 7, 8, 9, 
            });

            Assert.IsFalse(matrix.IsValid());
        }
        public IEnumerable<NumberPlaceMatrix> Solve(NumberPlaceMatrix seed)
        {
            var candidates = seed.GetCells().ToDictionary(
                x => x,
                x => (x.Value == 0 ? Enumerable.Repeat(true, seed.Size) : new bool[seed.Size]).ToList());
            var sizeRange = Enumerable.Range(0, seed.Size);
            var blockRowRange = Enumerable.Range(0, seed.BlockRowSize);
            var blockColumnRange = Enumerable.Range(0, seed.BlockColumnCount);
            var blockRange = blockRowRange.SelectMany(r => blockColumnRange.Select(c => new { BlockRowIndex = r, BlockColumnIndex = c }));

            while (true)
            {
                var unsolvedCount = seed.GetCells().Count(x => x.Value == 0);
                if (unsolvedCount == 0)
                {
                    break;
                }

                for (int r = 0; r < seed.Size; r++)
                {
                    var values = seed.GetRow(r).Where(x => x.Value > 0).Select(x => x.Value).ToArray();
                    for (int c = 0; c < seed.Size; c++)
                    {
                        foreach (var value in values)
                        {
                            candidates.Single(x => x.Key.RowIndex == r && x.Key.ColumnIndex == c).Value[value - 1] = false;
                        }
                    }
                }

                for (int c = 0; c < seed.Size; c++)
                {
                    var values = seed.GetColumn(c).Where(x => x.Value > 0).Select(x => x.Value).ToArray();
                    for (int r = 0; r < seed.Size; r++)
                    {
                        foreach (var value in values)
                        {
                            candidates.Single(x => x.Key.ColumnIndex == c && x.Key.RowIndex == r).Value[value - 1] = false;
                        }
                    }
                }

                foreach (var b in blockRange)
                {
                    var values = seed.GetBlock(b.BlockRowIndex, b.BlockColumnIndex).Where(x => x.Value > 0).Select(x => x.Value).ToArray();
                    for (int r = b.BlockRowIndex * seed.BlockRowSize; r < (b.BlockRowIndex + 1) * seed.BlockRowSize; r++)
                    {
                        for (int c = b.BlockColumnIndex * seed.BlockColumnSize; c < (b.BlockColumnIndex + 1) * seed.BlockRowSize; c++)
                        {
                            foreach (var value in values)
                            {
                                candidates.Single(x => x.Key.RowIndex == r && x.Key.ColumnIndex == c).Value[value - 1] = false;
                            }
                        }
                    }
                }

                var solvedCells = candidates.Where(x => x.Key.Value == 0 && x.Value.Count(b => b) == 1).ToArray();
                if (solvedCells.Any())
                {
                    foreach (var solvedCell in solvedCells)
                    {
                        seed[solvedCell.Key.RowIndex, solvedCell.Key.ColumnIndex] = solvedCell.Value.FindIndex(b => b) + 1;
                    }
                }
                else
                {
                    var minCount = candidates.Where(x => x.Key.Value == 0).Min(x => x.Value.Count(b => b));
                    var unsolvedCell = candidates.Where(x => x.Key.Value == 0 && x.Value.Count(b => b) == minCount).First();
                }
            }

            yield return seed;
        }
        public void TestIsValidFalse1()
        {
            var matrix = new NumberPlaceMatrix();

            Assert.IsFalse(matrix.IsValid());
        }