Пример #1
0
        //private static Random Random = new Random();

        private CellToChange SelectNextCellToChange(BoardRule rules)
        {
            CellToChange cellWithLessPossibilities = null;

            foreach (var cell in Cells)
            {
                if (!cell.CurrentNumber.HasValue)
                {
                    var possibleNumbers = rules.GetPossibleNumbers(this, cell);

                    if (cellWithLessPossibilities == null || cellWithLessPossibilities.PossibleNumbers.Length > possibleNumbers.Length)
                    {
                        cellWithLessPossibilities = new CellToChange()
                        {
                            Cell            = cell,
                            PossibleNumbers = possibleNumbers
                        };
                    }

                    // Shortcut to not process cells when there's a best one already
                    // Has the drawback of not identifying cells with 0 possibilities if there's a cell with 1 before
                    if (cellWithLessPossibilities.PossibleNumbers.Length <= 1)
                    {
                        return(cellWithLessPossibilities);
                    }
                }
            }

            return(cellWithLessPossibilities);
        }
Пример #2
0
        public IEnumerable <Board> NextBestBoards(BoardRule rules)
        {
            var cellToChange = SelectNextCellToChange(rules);

            foreach (var possibleValue in cellToChange.PossibleNumbers)
            {
                var newBoard = CreateChildBoard(cellToChange.Cell, possibleValue);
                yield return(newBoard);
            }
        }
Пример #3
0
        private IEnumerable <Board> GenerateCompleteBoards(Board board, BoardRule rules, Action <Board> onStep = null)
        {
            if (board.IsComplete())
            {
                yield return(board);
            }
            else
            {
                var combinations = board.NextBestBoards(rules);

                foreach (var combination in combinations)
                {
                    onStep?.Invoke(combination);

                    var nextCompleteBoards = GenerateCompleteBoards(combination, rules, onStep);

                    foreach (var nextCompleteBoard in nextCompleteBoards)
                    {
                        yield return(nextCompleteBoard);
                    }
                }
            }
        }
Пример #4
0
 public Board Solve(Board board, BoardRule rules, Action <Board> onStep = null)
 {
     return(SolveAll(board, rules, onStep).FirstOrDefault());
 }
Пример #5
0
 public IEnumerable <Board> SolveAll(Board board, BoardRule rules, Action <Board> onStep = null)
 {
     return(GenerateCompleteBoards(board, rules, onStep));
 }
Пример #6
0
        static void Main(string[] args)
        {
            Console.WriteLine("Sudoku Solver");
            Console.WriteLine("Paste your board (0 = empty)");

            // Read 9 lines of input
            List <string> rows = new List <string>();

            for (var i = 0; i < 9; i++)
            {
                rows.Add(Console.ReadLine());
            }

            // Convert lines into a board game
            var board = new Board();

            for (var row = 0; row < 9; row++)
            {
                for (var column = 0; column < 9; column++)
                {
                    char c = rows[row][column];

                    if (char.IsNumber(c))
                    {
                        int value = (int)char.GetNumericValue(c);

                        if (value > 0)
                        {
                            board.Cells.FirstOrDefault(x => x.Row == row && x.Column == column).CurrentNumber = (int)char.GetNumericValue(c);
                        }
                    }
                }
            }

            Console.WriteLine();
            Console.WriteLine("------------------------------");
            Console.WriteLine();

            // Set rules
            BoardRule rule = new BoardRule()
                             .ActivateUniqueInsideColumn()
                             .ActivateUniqueInsideRow()

                             .ActivateUniqueInside3x3Blocks();
            //.ActivateCustomAreasForUniqueValues(areas =>
            //{
            //    // Default 9 3x3 areas. No need to activate this + UniqueInside3x3Blocks
            //    areas.RegisterAreasByParsingBoard
            //    (
            //        @"AAABBBCCC",
            //        @"AAABBBCCC",
            //        @"AAABBBCCC",
            //        @"DDDEEEFFF",
            //        @"DDDEEEFFF",
            //        @"DDDEEEFFF",
            //        @"GGGHHHIII",
            //        @"GGGHHHIII",
            //        @"GGGHHHIII"
            //    );
            //
            //    // Custom Aad Van De Wetering sudoku - Example of: https://www.youtube.com/watch?v=f5GWiAIZXGI
            //    // areas.RegisterAreasByParsingBoard
            //    // (
            //    //     @"AAABBBCZC",
            //    //     @"ZAABBBCCC",
            //    //     @"AAAABZCCC",
            //    //     @"DDZDBBCFF",
            //    //     @"DDDDZFFFF",
            //    //     @"DDGHHFZFF",
            //    //     @"GGGZHIIII",
            //    //     @"GGGHHHIIZ",
            //    //     @"GZGHHHIII"
            //    // );
            //
            //    /*
            //    areas.CreateUniqueValuesAreaBuilder(0, 0)
            //        .AddCoordinate(1, 1)
            //        .AddCoordinate(2, 2)
            //        .AddCoordinate(3, 3)
            //        .AddCoordinate(4, 4)
            //        .AddCoordinate(5, 5)
            //        .AddCoordinate(6, 6)
            //        .AddCoordinate(7, 7)
            //        .AddCoordinate(8, 8)
            //        .Build();
            //
            //    areas.CreateUniqueValuesAreaBuilder(0, 8)
            //        .AddCoordinate(1, 7)
            //        .AddCoordinate(2, 6)
            //        .AddCoordinate(3, 5)
            //        .AddCoordinate(4, 4)
            //        .AddCoordinate(5, 3)
            //        .AddCoordinate(6, 2)
            //        .AddCoordinate(7, 1)
            //        .AddCoordinate(8, 0)
            //        .Build();
            //        */
            //});

            //.ActivateUniqueOrthogonallyAdjacent()

            // NonConsecutiveOrthogonallyAdjacent + UniqueOnKnightStep - Example of: https://www.youtube.com/watch?v=QNzltTzv0fc
            //.ActivateNonConsecutiveOrthogonallyAdjacent()
            //.ActivateUniqueOnKnightStep();

            // Thermometers - Example of: https://www.youtube.com/watch?v=KTth49YrQVU
            //.ActivateThermometers(set =>
            //{
            //    set.CreateThermometerBuilder(3, 3)
            //        .AddSequence(2, 3)
            //        .AddSequence(1, 3)
            //        .AddSequence(0, 3)
            //        .AddSequence(0, 2)
            //        .AddSequence(0, 1)
            //        .Build();
            //
            //    set.CreateThermometerBuilder(3, 3)
            //        .AddSequence(3, 2)
            //        .AddSequence(3, 1)
            //        .AddSequence(3, 0)
            //        .AddSequence(2, 0)
            //        .AddSequence(1, 0)
            //        .AddSequence(0, 0)
            //        .Build();
            //
            //    set.CreateThermometerBuilder(0, 5)
            //        .AddSequence(1, 5)
            //        .Build();
            //
            //    set.CreateThermometerBuilder(0, 6)
            //        .AddSequence(0, 7)
            //        .AddSequence(1, 7)
            //        .AddSequence(2, 7)
            //        .AddSequence(2, 6)
            //        .AddSequence(2, 5)
            //        .Build();
            //
            //    set.CreateThermometerBuilder(4, 4)
            //        .AddSequence(4, 5)
            //        .AddSequence(4, 6)
            //        .AddSequence(4, 7)
            //        .AddSequence(4, 8)
            //        .Build();
            //
            //    set.CreateThermometerBuilder(4, 4)
            //        .AddSequence(5, 4)
            //        .AddSequence(6, 4)
            //        .AddSequence(7, 4)
            //        .Build();
            //
            //    set.CreateThermometerBuilder(6, 2)
            //        .AddSequence(5, 2)
            //        .Build();
            //
            //    set.CreateThermometerBuilder(7, 1)
            //        .AddSequence(7, 2)
            //        .Build();
            //
            //    set.CreateThermometerBuilder(7, 0)
            //        .AddSequence(6, 0)
            //        .AddSequence(5, 0)
            //        .AddSequence(5, 1)
            //        .Build();
            //
            //    set.CreateThermometerBuilder(7, 8)
            //        .AddSequence(6, 8)
            //        .AddSequence(5, 8)
            //        .Build();
            //
            //    set.CreateThermometerBuilder(7, 8)
            //        .AddSequence(8, 8)
            //        .AddSequence(8, 7)
            //        .AddSequence(8, 6)
            //        .AddSequence(8, 5)
            //        .AddSequence(8, 4)
            //        .Build();
            //});

            /*
             * Console.Write(rule.Thermometers);
             * Console.ReadLine();
             *
             * Console.WriteLine();
             * Console.WriteLine("------------------------------");
             * Console.WriteLine();
             */

            BoardSolver solver  = new BoardSolver();
            var         results = solver.SolveAll(board, rule, null);
            var         count   = 0;

            foreach (var result in results)
            {
                count++;
                DisplayBoard(result);

                Console.ReadLine();
            }

            Console.Write("End of solutions");

            Console.ReadLine();
        }