Esempio n. 1
0
 public void VerifyThatEmptyPuzzleIsSolved()
 {
     var solved = this.boardBruteForceSolver.Solve(new SudokuBoard());
     this.boardReaderInstance.Input = EmptyPuzzleSolution;
     var boardWithSolution = new SudokuBoard();
     this.boardReaderInstance.FillBoard(boardWithSolution);
     Assert.AreEqual(solved, boardWithSolution);
 }
Esempio n. 2
0
 public SudokuBoard Clone()
 {
     var board = new SudokuBoard();
     foreach (var cell in AllCells)
     {
         board.Cells[cell.RowIndex, cell.ColumnIndex] = new SudokuCell(board, cell.RowIndex,
             cell.ColumnIndex)
         {
             Number = cell.Number,
             CalculatedValue = cell.CalculatedValue,
             GuessValue = cell.GuessValue,
             CalculatedAfterGuess = cell.CalculatedAfterGuess
         };
     }
     return board;
 }
Esempio n. 3
0
 public Vm()
 {
     Board = new SudokuBoard();
     this.PropertyChanged += (sender, args) =>
     {
         if (args.PropertyName =="Board")
         {
             if(_notNewBoard)
                 return;
             _solver = new Solver(Board);
         }
     };
     _solver = new Solver(Board);
     SaveCommand = new RelayCommand(o => Save());
     SaveAsCommand = new RelayCommand(o=> SaveAs());
     OpenCommand = new RelayCommand(o => Open());
     NewCommand = new RelayCommand(o => New());
     NextCommand = new RelayCommand(o=>Next(),o=>!_solver.IsDone);
 }
Esempio n. 4
0
        private void SolveByBruteForce(SudokuBoard board)
        {
            var listOfAttempts = new List <Attempt>();

            foreach (var sudokuRow in board.Rows)
            {
                foreach (var sudokuRowCell in sudokuRow.Cells.Where(c => !c.IsFilled))
                {
                    var column       = board.Columns.FirstOrDefault(c => c.ColumnNumber == sudokuRowCell.ColumnNumber);
                    var squareNumber = SudokuBoard.CalculateSquareNumber(sudokuRowCell.RowNumber, sudokuRowCell.ColumnNumber);
                    var square       = board.Squares.FirstOrDefault(s => s.SquareNumber == squareNumber);
                    var unusedNumber = 0;
                    for (int i = 1; i <= board.NumbersPerUnit; i++)
                    {
                        if (!sudokuRow.HasNumberBeenUsed(i) && !column.HasNumberBeenUsed(i) && !square.HasNumberBeenUsed(i) && !DoesAttemptExist(sudokuRowCell, i, listOfAttempts))
                        {
                            unusedNumber = i;
                        }
                    }
                    if (unusedNumber == 0)
                    {
                        continue;
                    }
                    //Try setting the number of the cell to the first unused number
                    listOfAttempts.Add(new Attempt(sudokuRowCell, unusedNumber));
                    var attemptBoard = board.Clone();
                    var attemptCell  = attemptBoard.GetCell(sudokuRowCell.ColumnNumber, sudokuRowCell.RowNumber);
                    attemptCell.Number = unusedNumber;
                    SolveBoard(attemptBoard);
                    if (attemptBoard.IsSolved)
                    {
                        sudokuRowCell.Number = unusedNumber;
                        SolveBoard(board);
                        return;
                    }
                }
            }
        }
Esempio n. 5
0
        static void Main(string[] args)
        {
            int?[,] initialBoard = new int?[, ] {
                { null, null, null, 2, null, null, null, null, 1 },
                { null, null, 3, 8, null, null, null, 9, null },
                { 7, null, 4, null, 9, 5, 8, null, null },

                { 2, 8, null, null, null, null, null, null, 5 },
                { null, null, null, null, null, null, null, null, null },
                { 6, null, null, null, null, null, null, 7, 3 },

                { null, null, 2, 7, 5, null, 6, null, 9 },
                { null, 7, null, null, null, 6, 4, null, null },
                { 5, null, null, null, null, 9, null, null, null }
            };

            SudokuBoard board = new SudokuBoard(initialBoard);

            bool solved = SudokuSolver.Solve(board);

            Console.WriteLine(board.ToString());
            Console.WriteLine($"{(solved ? "SOLVED" : "UNSOLVABLE")}");
        }
Esempio n. 6
0
 public SudokuCell(SudokuBoard board, int row, int col)
 {
     this.board       = board;
     this.RowIndex    = row;
     this.ColumnIndex = col;
 }
Esempio n. 7
0
 public SudokuSolve(SudokuBoard Board, CheckSudoku Check)
 {
     board = Board;
     check = Check;
 }
Esempio n. 8
0
 public Solver(SudokuBoard board)
 {
     this.board          = board;
     totalMissingNumbers = CountMissingNumbers();
     missingNumbers      = totalMissingNumbers;
 }
Esempio n. 9
0
        static void Main(string[] args)
        {
            Cell[,] c = new Cell[9, 9];
            for (int x = 0; x < 9; ++x)
            {
                for (int y = 0; y < 9; ++y)
                {
                    c[x, y] = new Cell();
                }
            }

            //test the block resoning solver

            /*c[0, 3].solved = 1;
            *  c[1, 1].solved = 1;
            *  c[3, 4].solved = 1;
            *  c[4, 0].solved = 1;
            *  c[5, 8].solved = 1;
            *  c[6, 6].solved = 1;
            *  c[7, 5].solved = 1;
            *  c[8, 2].solved = 1;*/

            //test case 1

            /*c[0, 0].solved = 5;
             * c[0, 1].solved = 3;
             * c[0, 4].solved = 7;
             *
             * c[1, 0].solved = 6;
             * c[1, 3].solved = 1;
             * c[1, 4].solved = 9;
             * c[1, 5].solved = 5;
             *
             * c[2, 1].solved = 9;
             * c[2, 2].solved = 8;
             * c[2, 7].solved = 6;
             *
             * c[3, 0].solved = 8;
             * c[3, 4].solved = 6;
             * c[3, 8].solved = 3;
             *
             * c[4, 0].solved = 4;
             * c[4, 3].solved = 8;
             * c[4, 5].solved = 3;
             * c[4, 8].solved = 1;
             *
             * c[5, 0].solved = 7;
             * c[5, 4].solved = 2;
             * c[5, 8].solved = 6;
             *
             * c[6, 1].solved = 6;
             * c[6, 6].solved = 2;
             * c[6, 7].solved = 8;
             *
             * c[7, 3].solved = 4;
             * c[7, 4].solved = 1;
             * c[7, 5].solved = 9;
             * c[7, 8].solved = 5;
             *
             * c[8, 4].solved = 8;
             * c[8, 7].solved = 7;
             * c[8, 8].solved = 9;//*/

            //test case 3 not logically solvable

            /*c[1, 5].solved = 3;
             * c[1, 7].solved = 8;
             * c[1, 8].solved = 5;
             *
             * c[2, 2].solved = 1;
             * c[2, 4].solved = 2;
             *
             * c[3, 3].solved = 5;
             * c[3, 5].solved = 7;
             *
             * c[4, 2].solved = 4;
             * c[4, 6].solved = 1;
             *
             * c[5, 1].solved = 9;
             *
             * c[6, 0].solved = 5;
             * c[6, 7].solved = 7;
             * c[6, 8].solved = 3;
             *
             * c[7, 2].solved = 2;
             * c[7, 4].solved = 1;
             *
             * c[8, 4].solved = 4;
             * c[8, 8].solved = 9;//*/

            //test case 4 isollate bug when trying to recusivly solve

            /*c[0, 7].solved = 2;
             * c[0, 8].solved = 1;
             *
             * c[1, 0].solved = 2;
             * c[1, 1].solved = 4;
             * c[1, 2].solved = 6;
             * c[1, 3].solved = 1;
             * c[1, 4].solved = 7;
             * c[1, 5].solved = 3;
             * c[1, 6].solved = 9;
             * c[1, 7].solved = 8;
             * c[1, 8].solved = 5;
             *
             * c[2, 2].solved = 1;
             * c[2, 4].solved = 2;
             *
             * c[3, 0].solved = 1;
             * c[3, 2].solved = 8;
             * c[3, 3].solved = 5;
             * c[3, 5].solved = 7;
             * c[3, 6].solved = 6;
             *
             * c[4, 2].solved = 4;
             * c[4, 6].solved = 1;
             *
             * c[5, 1].solved = 9;
             * c[5, 3].solved = 4;
             * c[5, 5].solved = 1;
             *
             * c[6, 0].solved = 5;
             * c[6, 1].solved = 1;
             * c[6, 2].solved = 9;
             * c[6, 6].solved = 4;
             * c[6, 7].solved = 7;
             * c[6, 8].solved = 3;
             *
             * c[7, 0].solved = 4;
             * c[7, 2].solved = 2;
             * c[7, 4].solved = 1;
             *
             * c[8, 4].solved = 4;
             * c[8, 6].solved = 2;
             * c[8, 7].solved = 1;
             * c[8, 8].solved = 9;//*/

            string[] lines = System.IO.File.ReadAllLines(@"C:\Users\Brandon\Documents\sudokuBoard.txt");

            for (int x = 0; x < lines.Count(); ++x)
            {
                for (int y = 0; y < lines[x].Length; ++y)
                {
                    c[x, y].solved = lines[x][y] - '0';
                }
            }

            SudokuBoard b = new SudokuBoard(c);

            b.printBoard();
            b.solve();
            //b.printBoard();
        }
Esempio n. 10
0
        public bool solve()//solve the current board
        {
            bool solved             = false;
            bool changesMadeToBoard = false;

            Section[] sectionSolverArray = new Section[3];//contain the three types of section solvers
            sectionSolverArray[0] = new Row(board);
            sectionSolverArray[1] = new Column(board);
            sectionSolverArray[2] = new Block(board);

            List <int>[] sectionsUnsolved = new List <int> [3];//list that will hold the rows, columns, and blocks to check
            //intitilize all the lists
            sectionsUnsolved[0] = new List <int>();
            sectionsUnsolved[1] = new List <int>();
            sectionsUnsolved[2] = new List <int>();

            for (int i = 0; i < 9; ++i)//add the number 0-8 to the list
            {
                sectionsUnsolved[0].Add(i);
                sectionsUnsolved[1].Add(i);
                sectionsUnsolved[2].Add(i);
            }

            while (!solved)//continue till solved
            {
                //if experiencing errors try reseting interscting numbers for all cells(code commened out underneath)

                /*
                 * for (int x = 0; x < 9; ++x)//go though the x of the block
                 * {
                 *  for (int y = 0; y < 9; ++y)//go throught the y of the block
                 *  {
                 *      board[x, y].intersectingNumbers = new bool[9];
                 *      for (int t = 0; t < 9; ++t)//go throught the y of the block
                 *      {
                 *          board[x, y].intersectingNumbers[t] = false;
                 *      }
                 *  }
                 * }*/

                //check all the boards row, columns, and blocks and updating the intersecting numbers of all cells
                for (int i = 0; i < 3; ++i)
                {
                    for (int j = 0; j < sectionsUnsolved[i].Count(); ++j)
                    {
                        if (sectionSolverArray[i].updateIntersection(sectionsUnsolved[i][j])) //if the current row, column or block is solved
                        {
                            sectionsUnsolved[i].RemoveAt(j);                                  //remove it from the list
                            j--;                                                              //account for it by moving one position back
                        }
                    }
                }

                solved             = true;
                changesMadeToBoard = false;
                //solve throught elemination
                for (int x = 0; x < 9; ++x)
                {
                    for (int y = 0; y < 9; ++y)
                    {
                        if (board[x, y].trySolvingByElimination()) //if position is solved during this round of testing(aka something was changed)
                        {
                            changesMadeToBoard = true;             //board was changed
                        }
                        if (board[x, y].solved == 0)               //if a position is unsolved
                        {
                            solved = false;                        //board is not solved
                        }
                    }
                }

                //if experiencing errors try reset all intersecting numbers for each cell

                //check all the boards row, columns, and blocks and updating the intersecting numbers of all cells
                for (int i = 0; i < 3; ++i)
                {
                    for (int j = 0; j < sectionsUnsolved[i].Count(); ++j)
                    {
                        if (sectionSolverArray[i].updateIntersection(sectionsUnsolved[i][j])) //if the current row, column or block is solved
                        {
                            sectionsUnsolved[i].RemoveAt(j);                                  //remove it from the list
                            j--;                                                              //account for it by moving one position back
                        }
                    }
                }

                //solve by reasoning
                //check to see if each block has only one position availible for a number
                int counter = 0;
                int xPos = 0, yPos = 0;
                for (int block = 0; block < 9; ++block)                                                                                                                             //go throught all the blocks
                {
                    for (int i = 0; i < 9; ++i)                                                                                                                                     //i represents the possible number to be checked
                    {
                        for (int x = 0; x < 3; ++x)                                                                                                                                 //go though the x of the block
                        {
                            for (int y = 0; y < 3; ++y)                                                                                                                             //go throught the y of the block
                            {
                                if (board[(block / 3) * 3 + x, (block % 3) * 3 + y].intersectingNumbers[i] == false && board[(block / 3) * 3 + x, (block % 3) * 3 + y].solved == 0) // && numbersSolved[i] == false) //the number i was already in this block
                                {
                                    counter++;                                                                                                                                      //count all the false
                                    //record the position
                                    xPos = x;
                                    yPos = y;
                                }
                            }
                        }
                        if (counter == 1)//if there was only one false
                        {
                            //a test print statment

                            /*Console.Write("solved throught reasoning y" + ((block%3) * 3 + yPos) + ", x" + ((block / 3) * 3 + xPos) + " " + (i + 1) + "\n");
                             * for (int x = 0; x < 3; ++x)
                             * {
                             *  for (int y = 0; y < 3; ++y)
                             *  {
                             *      if (board[blockX * 3 + x, blockY * 3 + y].solved == 0)
                             *          Console.Write(Convert.ToInt32(board[blockX * 3 + x, blockY * 3 + y].solvedNumbers[i]) + " ");
                             *  }
                             * }
                             * Console.Write('\n');//*/
                            changesMadeToBoard = true;
                            board[(block / 3) * 3 + xPos, (block % 3) * 3 + yPos].solved = i + 1;
                            solved = false;
                        }
                        counter = 0;
                    }
                }

                if (!changesMadeToBoard && !solved)//changes made to board=false and solved=false (if the board is not changed and not solved)
                {
                    //Console.Write("board not changed\n/////////////////\n");
                    //printBoard();
                    int guess = findBestGuess();
                    if (guess < 0)
                    {
                        Console.WriteLine(guess);
                        return(false);
                    }
                    //Console.Write("guess position: " + guess + "\n");

                    List <int> pN = board[(guess / 9), (guess % 9)].getNonIntersectingNumbers();//get the list of all non intersecting numbers of the best guess
                    for (int i = 0; i < pN.Count(); ++i)
                    {
                        Cell[,] b = new Cell[9, 9];
                        for (int x = 0; x < 9; ++x)     //go though the x of the block
                        {
                            for (int y = 0; y < 9; ++y) //go throught the y of the block
                            {
                                b[x, y] = new Cell(board[x, y]);
                            }
                        }
                        //Console.Write("making guess of " + (pN[i] + 1) + " i:" + i + " x,y: " + ((guess / 9)) + ", " + ((guess % 9)) + "\n" + "\n");
                        b[(guess / 9), (guess % 9)].solved = pN[i] + 1;
                        SudokuBoard s = new SudokuBoard(b);
                        if (s.solve())    //try to solve for this board if it cant then it will return to here(true or false) continueing onto the next permutation
                        {
                            return(true); //will continue to return true untill it reaches the original permutation it started to make guesses at
                        }
                        //reset intersecting numbers
                    }
                    //Console.WriteLine("revert back to a board guess");
                    return(false);
                }
                //reset intersecting numbers
            }
            //Console.Write("checking board if solved\n");
            bool checkBoardSolved = checkIfSolved();

            if (checkBoardSolved)
            {
                printBoard();
            }
            //return if true if correctly solved false if not correctly solved
            return(checkBoardSolved);
        }
Esempio n. 11
0
 private static void Main()
 {
     var sudokuBoard = new SudokuBoard();
     var sudokuSolver = SetUpSudokuSolver(sudokuBoard);
     TryToSolvePuzzle(sudokuSolver, sudokuBoard);
 }
Esempio n. 12
0
        static void Main(string[] args)
        {
            bool quit = false;
            List <SudokuBoard> sudokuTestBoards = new List <SudokuBoard>();

            #region Test boards
            // Normal #14
            SudokuBoard boardOne = new SudokuBoard(9, 9, new int[, ]
            {
                { 3, 0, 0, 0, 6, 0, 8, 0, 1 },
                { 0, 0, 0, 0, 0, 4, 0, 0, 0 },
                { 0, 0, 1, 8, 0, 0, 0, 0, 5 },
                { 0, 0, 2, 0, 5, 6, 0, 7, 0 },
                { 8, 0, 0, 1, 0, 9, 0, 0, 4 },
                { 0, 7, 0, 2, 4, 0, 5, 0, 0 },
                { 2, 0, 0, 0, 0, 1, 3, 0, 0 },
                { 0, 0, 0, 7, 0, 0, 0, 0, 0 },
                { 1, 0, 8, 0, 3, 0, 0, 0, 9 }
            }, "TestBoard_1");
            sudokuTestBoards.Add(boardOne);

            // Easy #2
            SudokuBoard boardTwo = new SudokuBoard(9, 9, new int[, ]
            {
                { 3, 0, 1, 8, 4, 5, 6, 0, 9 },
                { 0, 0, 0, 0, 6, 0, 0, 0, 0 },
                { 5, 0, 0, 3, 0, 9, 0, 0, 2 },
                { 1, 0, 9, 0, 0, 0, 3, 0, 5 },
                { 6, 3, 0, 0, 0, 0, 0, 9, 1 },
                { 8, 0, 7, 0, 0, 0, 2, 0, 4 },
                { 2, 0, 0, 5, 0, 4, 0, 0, 3 },
                { 0, 0, 0, 0, 1, 0, 0, 0, 0 },
                { 4, 0, 3, 2, 9, 7, 8, 0, 6 }
            }, "TestBoard_2");
            sudokuTestBoards.Add(boardTwo);

            // Easy #3
            SudokuBoard boardThree = new SudokuBoard(9, 9, new int[, ]
            {
                { 0, 4, 8, 0, 0, 0, 9, 2, 0 },
                { 0, 0, 3, 8, 1, 5, 4, 0, 0 },
                { 5, 0, 0, 0, 0, 0, 0, 0, 1 },
                { 0, 0, 1, 5, 0, 6, 8, 0, 0 },
                { 0, 7, 0, 2, 0, 9, 0, 1, 0 },
                { 0, 0, 2, 1, 0, 8, 5, 0, 0 },
                { 7, 0, 0, 0, 0, 0, 0, 0, 3 },
                { 0, 0, 9, 7, 5, 1, 2, 0, 0 },
                { 0, 1, 4, 0, 0, 0, 7, 5, 0 }
            }, "TestBoard_3");
            sudokuTestBoards.Add(boardThree);

            // Normal #10
            SudokuBoard boardFour = new SudokuBoard(9, 9, new int[, ]
            {
                { 0, 0, 0, 0, 0, 2, 0, 1, 0 },
                { 3, 0, 8, 0, 9, 1, 0, 0, 0 },
                { 0, 0, 0, 6, 3, 0, 0, 5, 0 },
                { 4, 2, 0, 0, 0, 0, 5, 0, 0 },
                { 0, 3, 9, 0, 0, 0, 1, 6, 0 },
                { 0, 0, 1, 0, 0, 0, 0, 7, 2 },
                { 0, 9, 0, 0, 4, 3, 0, 0, 0 },
                { 0, 0, 0, 5, 2, 0, 7, 0, 9 },
                { 0, 6, 0, 9, 0, 0, 0, 0, 0 }
            }, "TestBoard_4");
            sudokuTestBoards.Add(boardFour);

            // Hard #2
            SudokuBoard boardFive = new SudokuBoard(9, 9, new int[, ]
            {
                { 0, 4, 0, 0, 1, 0, 2, 0, 6 },
                { 0, 3, 0, 5, 9, 0, 8, 0, 1 },
                { 0, 0, 0, 4, 0, 0, 0, 0, 0 },
                { 6, 1, 8, 0, 0, 0, 0, 0, 0 },
                { 0, 0, 0, 0, 2, 0, 0, 0, 0 },
                { 0, 0, 0, 0, 0, 0, 1, 6, 3 },
                { 0, 0, 0, 0, 0, 5, 0, 0, 0 },
                { 1, 0, 6, 0, 7, 9, 0, 8, 0 },
                { 7, 0, 4, 0, 6, 0, 0, 3, 0 }
            }, "TestBoard_5");
            sudokuTestBoards.Add(boardFive);

            // 1. Hackerakademi
            SudokuBoard boardSix = new SudokuBoard(9, 9, new int[, ]
            {
                { 2, 0, 3, 0, 0, 0, 7, 0, 4 },
                { 0, 9, 1, 2, 7, 4, 5, 0, 3 },
                { 0, 6, 7, 3, 5, 9, 2, 0, 1 },
                { 7, 0, 0, 6, 0, 3, 0, 4, 5 },
                { 5, 3, 4, 0, 1, 7, 6, 2, 8 },
                { 0, 8, 0, 0, 2, 0, 9, 0, 7 },
                { 9, 1, 0, 5, 3, 6, 4, 7, 2 },
                { 3, 4, 5, 0, 9, 0, 0, 0, 6 },
                { 0, 0, 2, 0, 0, 1, 0, 0, 9 }
            }, "TestBoard_6");
            sudokuTestBoards.Add(boardSix);

            #endregion

            Stopwatch stopwatch = new Stopwatch();

            // Select option
            string lastMessage = "";
            while (!quit)
            {
                PrintBoardOptions(sudokuTestBoards, lastMessage);
                int op = GetOption();

                if (op == -2)
                {
                    lastMessage = "Input MUST be a number!";
                }
                if (op == -1)
                {
                    quit = true;
                }
                else if (op == 0)
                {
                    // Load new board from user
                    lastMessage = String.Empty;
                    UpdateLastMessage("Loading new board from user");
                    ClearWorkSpace();
                    Console.SetCursorPosition(0, 25);

                    SudokuBoard b = GetBoard(9, 9);
                    if (b != null)
                    {
                        sudokuTestBoards.Add(b);
                        lastMessage = "New board loaded";
                    }
                    else
                    {
                        lastMessage = "Error loading new board";
                    }
                }
                else if (op > 0 && op <= sudokuTestBoards.Count)
                {
                    // Solve board from list
                    SudokuBoard b = sudokuTestBoards[op - 1];
                    lastMessage = $"Solving board '{ b.Label }'";
                    ClearWorkSpace();

                    // Print board
                    Console.SetCursorPosition(0, 25);
                    Solve(b, stopwatch, b.Label);
                }
                else
                {
                    lastMessage = "Invalid option";
                }

                UpdateLastMessage(lastMessage);
            }
        }
Esempio n. 13
0
 public Solver(SudokuBoard board)
 {
     Board = board;
 }
Esempio n. 14
0
 public SudokuSolverTest()
 {
     this.boardInstance = new SudokuBoard();
     this.boardReaderInstance = new StringBoardReaderStrategy(TestCaseInitial);
     this.boardBruteForceSolver = new BruteForceSudokuSolver();
 }
Esempio n. 15
0
 public Solver(Solver antecedent, SudokuBoard board)
 {
     this.antecedent = antecedent;
     this.Board      = board;
 }
Esempio n. 16
0
 public static bool Solve(SudokuBoard board)
 {
     return(Solve(board, 0, 0));
 }
Esempio n. 17
0
 public Solver(SudokuBoard board)
 {
     this.Board = board;
 }
 private static bool IsNotValidNumber(SudokuBoard board, Position position, Position nextPosition, int number)
 {
     return(NextCellCanHoldOnlyCurrentNumber(board, nextPosition, number) &&
            !IsFinalPosition(position) &&
            IsOnTheSameRow(position, nextPosition));
 }
Esempio n. 19
0
        public IEnumerable <SudokuBoard> Solve()
        {
            SudokuProgress Simplify()
            {
                bool valid = _rules.All(rule => rule.CheckValid());

                if (!valid)
                {
                    return(SudokuProgress.FAILED);
                }

                return(_rules.Aggregate(SudokuProgress.NO_PROGRESS,
                                        (progress, rule) => SudokuTile.CombineSolvedState(progress, rule.Solve())));
            }

            // reset solution
            foreach (SudokuTile tile in _tiles)
            {
                tile.ResetPossibles();
            }

            SudokuProgress simplify = SudokuProgress.PROGRESS;

            while (simplify == SudokuProgress.PROGRESS)
            {
                simplify = Simplify();
            }

            if (simplify == SudokuProgress.FAILED)
            {
                yield break;
            }

            // Find one of the values with the least number of alternatives, but that still has at least 2 alternatives
            IEnumerable <SudokuTile> query = from rule in _rules
                                             from tile in rule
                                             where tile.PossibleCount > 1
                                             orderby tile.PossibleCount ascending
                                             select tile;

            SudokuTile chosen = query.FirstOrDefault();

            if (chosen == null)
            {
                // The board has been completed, we're done!
                yield return(this);

                yield break;
            }

            foreach (int value in Enumerable.Range(1, _maxValue))
            {
                // Iterate through all the valid possibles on the chosen square and pick a number for it
                if (!chosen.IsValuePossible(value))
                {
                    continue;
                }
                SudokuBoard copy = new SudokuBoard(this);
                copy[chosen.X, chosen.Y].Fix(value, "Trial and error");
                foreach (SudokuBoard innerSolution in copy.Solve())
                {
                    yield return(innerSolution);
                }
            }
            yield break;
        }
Esempio n. 20
0
        public Bitmap SolveSudokuPhoto(Bitmap sudokuPhoto)
        {
            Bitmap transformedImage = ImageTransformation.TranformImage(sudokuPhoto);
            //transformedImage.Save(@"D:\k\trash\transformedImage.jpg");

            Bitmap thresholdedImage = ImageTransformation.PerformThresholding(transformedImage);
            //thresholdedImage.Save(@"D:\k\trash\thresholdedImage.jpg");


            //todo del
            //ImageTransformation.Test(transformedImage).Save(@"D:\k\trash\abc.jpg");


            //TODO: Threshold will probably be needed for noisy images
            //var thresholdFilter = new Threshold(100);
            //thresholdFilter.ApplyInPlace(image);
            var invertFilter  = new Invert();
            var invertedImage = invertFilter.Apply(thresholdedImage);

            //invertedImage.Save(@"D:\k\trash\invertedInput.jpg");


            var blobCounter = new BlobCounter
            {
                BackgroundThreshold = Color.FromArgb(255, 70, 70, 70)
            };

            blobCounter.ProcessImage(invertedImage);

            var invertedImageBlobs        = blobCounter.GetObjectsInformation();
            var boardBlobCandidates       = invertedImageBlobs;
            var biggestBoardBlobCandidate = boardBlobCandidates.OrderByDescending(b => b.Area).First();
            var boardBlob = biggestBoardBlobCandidate;

            var expectedCellBlobHeight = boardBlob.Rectangle.Height /
                                         SudokuBoard.NumberOfBoardCellsInSingleDirection;

            var expectedCellBlobWidth = boardBlob.Rectangle.Width /
                                        SudokuBoard.NumberOfBoardCellsInSingleDirection;

            var blobCellSizeTolerance = 0.25;

            blobCounter.ProcessImage(thresholdedImage);

            //todo
            thresholdedImage = transformedImage;

            var cellBlobCandidates = blobCounter.GetObjectsInformation();

            var cellBlobs = cellBlobCandidates.Where(
                b =>
                boardBlob.Rectangle.Contains(b.Rectangle) &&
                IsMatch(b.Rectangle.Width, expectedCellBlobWidth, blobCellSizeTolerance) &&
                IsMatch(b.Rectangle.Height, expectedCellBlobHeight, blobCellSizeTolerance)).ToArray();

            if (cellBlobs.Length != SudokuBoard.NumberOfBoardCells)
            {
                throw new InvalidOperationException();
            }

            var expectedCellsData =
                Enumerable.Range(0, SudokuBoard.NumberOfBoardCellsInSingleDirection)
                .SelectMany(
                    cvi =>
                    Enumerable.Range(0, SudokuBoard.NumberOfBoardCellsInSingleDirection)
                    .Select(chi => new
            {
                CellHorizontalIndex = chi,
                CellVerticalIndex   = cvi,
                ExpectedCellCenter  =
                    new Point((int)(boardBlob.Rectangle.X + (cvi + 0.5) * expectedCellBlobWidth),
                              boardBlob.Rectangle.Y + (int)((chi + 0.5) * expectedCellBlobHeight)),
            })).ToArray();

            var sudokuBoard = new SudokuBoard();
            var digitImages = new List <Bitmap>();
            var parsedDigitIndexToCellBlobMap = new Dictionary <int, Blob>();
            var lastParsedDigitIndex          = 0;

            foreach (var cellBlob in cellBlobs)
            {
                // TODO: There may be more than one blob candidate
                var digitBlob = invertedImageBlobs.SingleOrDefault(b => cellBlob.Rectangle.Contains(b.Rectangle));

                if (digitBlob == null)
                {
                    continue;
                }

                var digitImage = thresholdedImage.Clone(digitBlob.Rectangle, thresholdedImage.PixelFormat);
                digitImages.Add(digitImage);
                parsedDigitIndexToCellBlobMap[lastParsedDigitIndex++] = cellBlob;
            }

            IReadOnlyCollection <int> parsedDigits;

            using (var digitParser = new DigitParser())
            {
                parsedDigits = digitParser.ParseDigits(digitImages);
            }

            foreach (var digitImage in digitImages)
            {
                digitImage.Dispose();
            }

            for (var parsedDigitIndex = 0; parsedDigitIndex < parsedDigits.Count; parsedDigitIndex++)
            {
                var digitCellBlob = parsedDigitIndexToCellBlobMap[parsedDigitIndex];

                var expectedCellData =
                    expectedCellsData.Single(d => digitCellBlob.Rectangle.Contains(d.ExpectedCellCenter));

                var parsedDigit = parsedDigits.ElementAt(parsedDigitIndex);

                if (!SudokuBoard.ValidNumbers.Contains(parsedDigit))
                {
                    throw new InvalidOperationException();
                }

                sudokuBoard[expectedCellData.CellHorizontalIndex, expectedCellData.CellVerticalIndex] =
                    parsedDigit;
            }

            var solvedBoard = sudokuBoard.Solve();

            if (solvedBoard == null)
            {
                return(null);
            }

            Debug.Assert(solvedBoard.IsComplete() && solvedBoard.IsValid());

            var cellsToPrint = Enumerable.Range(0, SudokuBoard.NumberOfBoardCellsInSingleDirection)
                               .SelectMany(
                vi =>
                Enumerable.Range(0, SudokuBoard.NumberOfBoardCellsInSingleDirection)
                .Select(hi => new
            {
                HorizontalIndex = hi,
                VerticalIndex   = vi
            })).Where(c => sudokuBoard[c.HorizontalIndex, c.VerticalIndex] == null).Select(
                i =>
            {
                var expectedCellData =
                    expectedCellsData.Single(
                        d =>
                        d.CellHorizontalIndex == i.HorizontalIndex &&
                        d.CellVerticalIndex == i.VerticalIndex);

                var cellBlob =
                    cellBlobs.Single(
                        b => b.Rectangle.Contains(expectedCellData.ExpectedCellCenter));

                var cellCenter = new Point(cellBlob.Rectangle.X + cellBlob.Rectangle.Width / 2,
                                           cellBlob.Rectangle.Y + cellBlob.Rectangle.Height / 2);
                return(new Cell(i.HorizontalIndex, i.VerticalIndex, cellBlob.Rectangle));
            }).ToList();

            var solutionPhoto = PrintSolutionToSourceImage(thresholdedImage, cellsToPrint, solvedBoard);

            return(solutionPhoto);
        }
Esempio n. 21
0
 private void New()
 {
     _fileName = null;
     Board= new SudokuBoard();
 }
Esempio n. 22
0
        private Bitmap PrintSolutionToSourceImage(Bitmap sourceImage,
                                                  IReadOnlyCollection <Cell> cellsToPrint, SudokuBoard solvedBoard)
        {
            var solutionImage = sourceImage.Clone(new Rectangle(0, 0, sourceImage.Width, sourceImage.Height),
                                                  PixelFormat.Format24bppRgb);

            using (var solutionImageGraphics = Graphics.FromImage(solutionImage))
            {
                solutionImageGraphics.SmoothingMode     = SmoothingMode.AntiAlias;
                solutionImageGraphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
                solutionImageGraphics.PixelOffsetMode   = PixelOffsetMode.HighQuality;

                foreach (var cell in cellsToPrint)
                {
                    var borderRatio           = 0.1;
                    var horizontalBorderWidth = (int)(cell.Rectangle.Width * borderRatio);
                    var verticalBorderWidth   = (int)(cell.Rectangle.Height * borderRatio);

                    var rectangle = new Rectangle(
                        cell.Rectangle.X + horizontalBorderWidth,
                        cell.Rectangle.Y + verticalBorderWidth,
                        cell.Rectangle.Width - 2 * horizontalBorderWidth,
                        cell.Rectangle.Height - 2 * verticalBorderWidth);

                    var cellValue = solvedBoard[cell.HorizontalIndex, cell.VerticalIndex];

                    solutionImageGraphics.DrawString(cellValue.ToString(),
                                                     new Font("Tahoma", rectangle.Height, GraphicsUnit.Pixel),
                                                     Brushes.DarkRed,
                                                     rectangle);
                }
            }

            return(solutionImage);
        }
 public SudokuBoard SolveSudoku(SudokuBoard board)
 {
     return((IsSolvable(board, StartPosition))
         ? board
         : throw new Exception("This sudoku board cannot be solved"));
 }
Esempio n. 24
0
        public static SudokuBoard SolveInternal(SudokuBoard sudokuBoard)
        {
            if (!sudokuBoard.IsValid())
            {
                return(null);
            }

            var cells = Enumerable.Range(0, NumberOfBoardCellsInSingleDirection)
                        .SelectMany(
                vni =>
                Enumerable.Range(0, NumberOfBoardCellsInSingleDirection)
                .Select(hni => new Cell(hni, vni, sudokuBoard._numbers))).ToList();

            Debug.Assert(cells.Count == NumberOfBoardCellsInSingleDirection * NumberOfBoardCellsInSingleDirection);

            var rows = Enumerable.Range(0, NumberOfBoardCellsInSingleDirection).Select(rowIndex =>
            {
                var rowCells = cells.Where(c => c.VerticalIndex == rowIndex).ToList();
                return(new SolutionRegion(rowCells));
            }).ToList();

            // TODO: rows and cols are mismatched, imporve just for readability
            var columns = Enumerable.Range(0, NumberOfBoardCellsInSingleDirection).Select(columnIndex =>
            {
                var columnCells = cells.Where(c => c.HorizontalIndex == columnIndex).ToList();
                return(new SolutionRegion(columnCells));
            }).ToList();

            var quadrants = Enumerable.Range(0, NumberOfQuadrantsInOneDirection).SelectMany(quadrantHorizontalIndex =>
                                                                                            Enumerable.Range(0, NumberOfQuadrantsInOneDirection)
                                                                                            .Select(
                                                                                                quadrantVerticalIndex =>
                                                                                                new
            {
                QuadrantHorizontalIndex = quadrantHorizontalIndex,
                QuadrantVerticalIndex   = quadrantVerticalIndex
            })).Select(i =>
            {
                var quardantCells =
                    cells.Where(
                        c =>
                        c.HorizontalIndex >=
                        i.QuadrantHorizontalIndex * NumberOfQuadrantCellsInOneDirection &&
                        c.HorizontalIndex <
                        (i.QuadrantHorizontalIndex + 1) * NumberOfQuadrantCellsInOneDirection &&
                        c.VerticalIndex >=
                        i.QuadrantVerticalIndex * NumberOfQuadrantCellsInOneDirection &&
                        c.VerticalIndex <
                        (i.QuadrantVerticalIndex + 1) * NumberOfQuadrantCellsInOneDirection
                        ).ToList();

                return(new SolutionRegion(quardantCells));
            }).ToList();

            Debug.Assert(new[] { rows, columns, quadrants }.All(s => s.Count == NumberOfBoardCellsInSingleDirection));

            var solutionRegions = rows.Concat(columns).Concat(quadrants).ToList();

            var cellsToSolutionRegionsMap = cells.ToDictionary(c => c,
                                                               c => (IReadOnlyCollection <SolutionRegion>)solutionRegions.Where(r => r.Cells.Contains(c)).ToList());

            Debug.Assert(cellsToSolutionRegionsMap.Values.All(s => s.Count == 3));

            var cellsToProcess = cells.Where(c => !c.Number.HasValue).ToList();
            var processedCellsBacktrackingInfos = new Stack <CellBacktractingInfo>();

            while (true)
            {
                var currentCellToProcess =
                    cellsToProcess.OrderBy(c => GetCellPossibleValues(c, cellsToSolutionRegionsMap[c]).Count)
                    .FirstOrDefault();

                if (currentCellToProcess == null)
                {
                    return(sudokuBoard);
                }

                Debug.Assert(!currentCellToProcess.Number.HasValue);

                var currentCellToProcessPossibleValues = GetCellPossibleValues(currentCellToProcess,
                                                                               cellsToSolutionRegionsMap[currentCellToProcess]);

                var currentCellToProcessBacktrackingInfo = new CellBacktractingInfo(currentCellToProcess,
                                                                                    currentCellToProcessPossibleValues);

                do
                {
                    var currentCellToProcessPossibleNumber =
                        currentCellToProcessBacktrackingInfo.GetNextPossibleNumber();

                    if (!currentCellToProcessPossibleNumber.HasValue)
                    {
                        currentCellToProcessBacktrackingInfo.Cell.Number = null;

                        if (!processedCellsBacktrackingInfos.Any())
                        {
                            return(null);
                        }

                        currentCellToProcessBacktrackingInfo = processedCellsBacktrackingInfos.Pop();
                        cellsToProcess.Add(currentCellToProcessBacktrackingInfo.Cell);
                        continue;
                    }

                    currentCellToProcessBacktrackingInfo.Cell.Number = currentCellToProcessPossibleNumber;
                    processedCellsBacktrackingInfos.Push(currentCellToProcessBacktrackingInfo);
                    cellsToProcess.Remove(currentCellToProcessBacktrackingInfo.Cell);
                    break;
                } while (true);
            }
        }
 private static bool NextCellCanHoldOnlyCurrentNumber(SudokuBoard board, Position nextAvailablePosition, int num)
 {
     return(board.GetAllAvailableNumbersForCell(nextAvailablePosition).Count == 1 &&
            board.GetAllAvailableNumbersForCell(nextAvailablePosition)[0] == num);
 }
Esempio n. 26
0
 public Solver(Solver antecedent, SudokuBoard board)
 {
     _antecedent = antecedent;
     Board = board;
 }
Esempio n. 27
0
 public SudokuCell(SudokuBoard board, int row, int col)
 {
     _board = board;
     RowIndex = row;
     ColumnIndex = col;
 }