public void NoSolutionFoundToUnsolvableBoard()
        {
            int[,] board = GetUnsolvableBoard();
            Solver solver = new Solver();
            bool solved = solver.Solve(board);

            Assert.IsFalse(solved);
        }
Пример #2
0
        public void SolutionIsValid()
        {
            int[,] board = GetBoard();

            Solver solver = new Solver();
            solver.Solve(board);

            TestHelper.TestSolutionValid(solver.GetFirstSolution());
        }
Пример #3
0
        public void CanSolveSampleBoard()
        {
            int[,] board = GetBoard();

            Solver solver = new Solver();
            bool solved = solver.Solve(board);

            Assert.IsTrue(solved);
        }
Пример #4
0
        public void CanSolveEmptyBoard()
        {
            Solver solver = new Solver();
            int[,] board = new int[9, 9];

            bool solved = solver.Solve(board);

            // there are solutions to an empty board
            Assert.IsTrue(solved);
        }
Пример #5
0
        public void EmptyBoardSolutionIsValid()
        {
            int[,] board = new int[9, 9];
            Solver solver = new Solver();

            solver.Solve(board);
            int[,] firstSolution = solver.GetFirstSolution();

            TestHelper.TestSolutionValid(firstSolution);
        }
Пример #6
0
        public void CanSolveSimpleBoard()
        {
            Solver solver = new Solver();
            int[,] board = GetSimpleBoardToSolve();

            bool solved = solver.Solve(board);

            // there is a solution to this board
            Assert.IsTrue(solved);
            Assert.GreaterOrEqual(solver.SolutionCount, 1);
        }
Пример #7
0
        public void CanSolveBoard()
        {
            Solver solver = new Solver();
            int[,] board = GetBoard();

            bool solved = solver.Solve(board);

            // there is a solution to this board
            Assert.IsTrue(solved);
            Assert.AreEqual(1, solver.SolutionCount);
        }
Пример #8
0
        public void SolutionIsCorrect()
        {
            Solver solver = new Solver();
            int[,] board = GetBoard();

            solver.Solve(board);

            int[,] solution = solver.GetFirstSolution();

            TestHelper.TestSolutionValid(solution);
            TestHelper.BoardsAreSameInFilledCells(solution, GetBoardSolution());
        }
Пример #9
0
        public void TimeSolution()
        {
            Solver solver = new Solver();
            int[,] board = GetBoard();

            Stopwatch timer = new Stopwatch();
            timer.Start();
            solver.Solve(board);
            timer.Stop();

            TimeSpan timeToSolve = timer.Elapsed;

            Assert.Fail("Solving took " + timeToSolve);
        }
Пример #10
0
        public string generateString(int holeNumber)
        // generate n boards...
        {
            int NUM_MAX = gridSize * 3 - 6; // number of random generated numbers

            status = 0;
            List <int> selected = new List <int>();
            Random     r        = new Random();
            bool       solved   = false;

            //lasvegas algorithms.
            do // while bm has a solution
            {
                sv = null;
                do // while newBoard got valid puzzle
                {
                    int numberSelect = NUM_MAX;
                    selected.Clear();
                    newBoard = initBoard.Copy();
                    while (numberSelect > 0)
                    {
                        int inputPosition = r.Next(1, gridSize * gridSize);
                        if (!selected.Contains(inputPosition))
                        {
                            selected.Add(inputPosition);
                            newBoard.setBoard(inputPosition / gridSize, inputPosition % gridSize, r.Next(1, gridSize));
                            numberSelect--;
                        }
                    }
                }while (!newBoard.isValid());
                sv = new Solver(newBoard);
                sv.PresentBoard += PresentBoard;
                bool DONE = false;
                var  t0   = new System.Threading.Thread(() => {
                    threeseconds();
                    if (DONE == false)
                    {
                        sv.killSolver();
                        DONE = true;
                    }
                });
                var t1 = new System.Threading.Thread(() =>
                {
                    solved = sv.solve(2, true);
                    Console.WriteLine("solved in three seconds...");
                    DONE = true;
                });
                t0.Start();
                t1.Start();
                while (!DONE)
                {
                    System.Threading.Thread.Sleep(200);
                }
                t0.Abort();
                t1.Abort();
            }while (!solved);

            Console.WriteLine("digging hole initiated");
            status = 1; // DO NOT PRESENT WHILE THIS REGION

            Board Digged = sv.solution.Copy();

            bool[,] DONOTDIG = new bool[gridSize, gridSize];
            //holeNumber = r.Next(54, 73); // 9x9 Normal difficulty (temporal), we should implement difficulty later
            sv = null;
            int[] shuffledArr = new int[gridSize * gridSize];

            for (int i = 0; i < gridSize * gridSize; i++)
            {
                DONOTDIG[i / gridSize, i % gridSize] = false;
                shuffledArr[i] = i;
            }

            // shuffling size array...
            int n = shuffledArr.Length;

            while (n > 1)
            {
                int k    = r.Next(n--);
                int temp = shuffledArr[n];
                shuffledArr[n] = shuffledArr[k];
                shuffledArr[k] = temp;
            }

            //lets dig holes!
            int cnt = gridSize * gridSize - 1;

            while (holeNumber > 0)
            {
                if (cnt == 0)
                {
                    break;
                }
                int digRow       = shuffledArr[cnt] / gridSize;
                int digCol       = shuffledArr[cnt--] % gridSize;
                int diggedNumber = Digged.getBoard(digRow, digCol);

                if (DONOTDIG[digRow, digCol])
                {
                    continue;
                }

                bool nope = false;
                holeNumber--;
                for (int i = 1; i <= gridSize; i++)
                {
                    if (i == diggedNumber)
                    {
                        continue;
                    }
                    Digged.setBoard(digRow, digCol, i);
                    sv = new Solver(Digged);
                    if (sv.solve(2, true))
                    {
                        DONOTDIG[digRow, digCol] = true;
                        Digged.setBoard(digRow, digCol, diggedNumber);
                        nope = true;
                        holeNumber++;
                        break;
                    }
                }
                if (!nope)
                {
                    DONOTDIG[digRow, digCol] = true;
                    //Console.WriteLine("digging #{0}: {1}, {2}", holeNumber, digRow, digCol);
                    Digged.setBoard(digRow, digCol, 0);
                    newBoard = Digged.Copy();
                }
            }
            SolBoard = Digged.Copy();
            Console.WriteLine("generating complete");
            Console.WriteLine(Digged.ToString());
            PresentBoard(this, new PresentBoardArgs(Digged.ToString()));
            return(Digged.ToString());
        }
Пример #11
0
        public static void Hint(Board board)
        {
            var solver = new Solver(board);

            solver.Hint();
        }
Пример #12
0
        private void RemoveRandomIntegers(int[,] sudokuArray)
        {
            var r = new Random();

            var boolArray = new bool[5] {
                false, false, false, false, false
            };

            var excludedCoordinatesList = new List <int[]>();

            switch (difficulty)
            {
            case Difficulty.Easy:
                break;

            case Difficulty.Normal:
                boolArray[0] = true;
                break;

            case Difficulty.Hard:
                boolArray[0] = true;
                boolArray[1] = true;
                break;

            case Difficulty.VeryHard:
                boolArray[0] = true;
                boolArray[1] = true;
                boolArray[2] = true;
                boolArray[3] = true;
                break;

            case Difficulty.ExtremelyHard:
                boolArray[0] = true;
                boolArray[1] = true;
                boolArray[2] = true;
                boolArray[3] = true;
                boolArray[4] = true;
                break;
            }
            for (int j = 0; j < 5; j++)
            {
                var rowsList = RandomizeList(integersList);

                for (int i = 0; i < rowsList.Count; i++)
                {
                    var coordinate = new int[2] {
                        r.Next(0, fieldsPerRowAmount), rowsList[i] - 1
                    };
                    int n = sudokuArray[coordinate[0], coordinate[1]];
                    if (n != 0 && !Solver.CheckIfCoordinateListContainsCoordinate(excludedCoordinatesList, coordinate))
                    {
                        sudokuArray[coordinate[0], coordinate[1]] = 0;
                        if (CheckIfDifficultyMet(difficulty, sudokuArray) == -1)
                        {
                            sudokuArray[coordinate[0], coordinate[1]] = n;
                            excludedCoordinatesList.Add(coordinate);
                        }
                        else
                        {
                            var p = Solver.RateSudokuGrid(this, Solver.CopySudoku(sudokuArray), boolArray[0], boolArray[1], boolArray[2], boolArray[3], boolArray[4]);

                            if (p == 0 || p > difficultyRange[1])
                            {
                                sudokuArray[coordinate[0], coordinate[1]] = n;
                                excludedCoordinatesList.Add(coordinate);
                            }
                        }
                    }
                }

                var columnList = RandomizeList(rowsList);

                for (int i = 0; i < columnList.Count; i++)
                {
                    var coordinate = new int[2] {
                        columnList[i] - 1, r.Next(0, fieldsPerRowAmount)
                    };
                    int n = sudokuArray[coordinate[0], coordinate[1]];
                    if (n != 0 && !Solver.CheckIfCoordinateListContainsCoordinate(excludedCoordinatesList, coordinate))
                    {
                        sudokuArray[coordinate[0], coordinate[1]] = 0;
                        if (CheckIfDifficultyMet(difficulty, sudokuArray) == -1)
                        {
                            sudokuArray[coordinate[0], coordinate[1]] = n;
                            excludedCoordinatesList.Add(coordinate);
                        }
                        else
                        {
                            var p = Solver.RateSudokuGrid(this, Solver.CopySudoku(sudokuArray), boolArray[0], boolArray[1], boolArray[2], boolArray[3], boolArray[4]);

                            if (p == 0 || p > difficultyRange[1])
                            {
                                sudokuArray[coordinate[0], coordinate[1]] = n;
                                excludedCoordinatesList.Add(coordinate);
                            }
                        }
                    }
                }
            }

            var rowList = RandomizeList(integersList);

            for (int x = 0; x < fieldsPerRowAmount; x++)
            {
                int row        = rowList[x] - 1;
                var columnList = RandomizeList(rowList);
                for (int y = 0; y < fieldsPerRowAmount; y++)
                {
                    int col        = columnList[x] - 1;
                    var coordinate = new int[2] {
                        col, row
                    };
                    int n = sudokuArray[col, row];
                    if (n != 0 && !Solver.CheckIfCoordinateListContainsCoordinate(excludedCoordinatesList, coordinate))
                    {
                        sudokuArray[col, row] = 0;
                        if (CheckIfDifficultyMet(difficulty, sudokuArray) == -1)
                        {
                            sudokuArray[coordinate[0], coordinate[1]] = n;
                            excludedCoordinatesList.Add(coordinate);
                        }
                        else
                        {
                            var p = Solver.RateSudokuGrid(this, Solver.CopySudoku(sudokuArray), boolArray[0], boolArray[1], boolArray[2], boolArray[3], boolArray[4]);

                            if (p == 0 || p > difficultyRange[1])
                            {
                                sudokuArray[coordinate[0], coordinate[1]] = n;
                                excludedCoordinatesList.Add(coordinate);
                            }
                            else
                            {
                                Console.WriteLine(p);
                            }
                        }
                    }
                }
            }
        }
Пример #13
0
        private void CreateIncompleteSudokuGrid()
        {
            int[,] sudokuArray    = Solver.CopySudoku(SudokuCompleteArray);;
            protectedPatternsList = DetermineProtectedPatterns();

            if (boxPerRowAmount == 3)
            {
                switch (difficulty)
                {
                case Difficulty.Easy:
                    difficultyRange[0] = 450;
                    difficultyRange[1] = 530;
                    break;

                case Difficulty.Normal:
                    if (diagonalRows)
                    {
                        difficultyRange[0] = 560;
                        difficultyRange[1] = 660;
                    }
                    else
                    {
                        difficultyRange[0] = 530;
                        difficultyRange[1] = 575;
                    }
                    break;

                case Difficulty.Hard:
                    if (diagonalRows)
                    {
                        difficultyRange[0] = 660;
                        difficultyRange[1] = 775;
                    }
                    else
                    {
                        difficultyRange[0] = 575;
                        difficultyRange[1] = 630;
                    }
                    break;

                case Difficulty.VeryHard:
                    if (diagonalRows)
                    {
                        difficultyRange[0] = 775;
                        difficultyRange[1] = 950;
                    }
                    else
                    {
                        difficultyRange[0] = 630;
                        difficultyRange[1] = 700;
                    }
                    break;

                case Difficulty.ExtremelyHard:
                    if (diagonalRows)
                    {
                        difficultyRange[0] = 950;
                        difficultyRange[1] = 1500;
                    }
                    else
                    {
                        difficultyRange[0] = 700;
                        difficultyRange[1] = 1500;
                    }
                    break;
                }
            }

            while (true)
            {
                RemoveRandomIntegers(sudokuArray);

                if (CheckIfDifficultyMet(difficulty, sudokuArray) == 1)
                {
                    var p = Solver.RateSudokuGrid(this, Solver.CopySudoku(sudokuArray));
                    if (p >= difficultyRange[0] && p <= difficultyRange[1])
                    {
                        rating = p;
                        break;
                    }
                }

                sudokuArray = Solver.CopySudoku(SudokuCompleteArray);
            }

            SudokuIncompleteArray = Solver.CopySudoku(sudokuArray);
        }
Пример #14
0
        private short CheckIfDifficultyMet(Difficulty difficulty, int[,] sudokuArray)
        {
            //-1: too hard,
            //0: too easy,
            //1: met,

            var tooEasy = false;

            int[] numbersPerBox;
            int[] instancesOfNumbers;
            int[] numbersPerRow;
            int[] overallNumbers;

            switch (difficulty)
            {
            case Difficulty.Easy:
                numbersPerBox = new int[2] {
                    2, 9
                };
                instancesOfNumbers = new int[2] {
                    1, 9
                };
                numbersPerRow = new int[2] {
                    1, 9
                };
                overallNumbers = new int[2] {
                    30, 40
                };
                break;

            case Difficulty.Normal:
                numbersPerBox = new int[2] {
                    1, 8
                };
                instancesOfNumbers = new int[2] {
                    1, 7
                };
                numbersPerRow = new int[2] {
                    1, 7
                };
                overallNumbers = new int[2] {
                    25, 30
                };
                break;

            case Difficulty.Hard:
                numbersPerBox = new int[2] {
                    1, 5
                };
                instancesOfNumbers = new int[2] {
                    0, 7
                };
                numbersPerRow = new int[2] {
                    0, 5
                };
                overallNumbers = new int[2] {
                    20, 25
                };
                break;

            case Difficulty.VeryHard:
                numbersPerBox = new int[2] {
                    0, 7
                };
                instancesOfNumbers = new int[2] {
                    0, 7
                };
                numbersPerRow = new int[2] {
                    0, 7
                };
                overallNumbers = new int[2] {
                    17, 25
                };
                break;

            case Difficulty.ExtremelyHard:
                numbersPerBox = new int[2] {
                    0, 9
                };
                instancesOfNumbers = new int[2] {
                    0, 9
                };
                numbersPerRow = new int[2] {
                    0, 9
                };
                overallNumbers = new int[2] {
                    15, 25
                };
                break;

            default:
                numbersPerBox = new int[2] {
                    2, 9
                };
                instancesOfNumbers = new int[2] {
                    1, 9
                };
                numbersPerRow = new int[2] {
                    1, 9
                };
                overallNumbers = new int[2] {
                    30, 35
                };
                break;
            }
            if (!diagonalRows)
            {
                overallNumbers[1] += 3;
            }

            int n;

            if (!CheckIfProtectedPatternsAreSafe(sudokuArray))
            {
                return(-1);
            }

            foreach (var i in CreateListOfAllIntegers())
            {
                n = Solver.CountInstancesOfInteger(i, sudokuArray);
                if (n > instancesOfNumbers[1])
                {
                    tooEasy = true;
                }
                if (n < instancesOfNumbers[0])
                {
                    return(-1);
                }

                n = Solver.CountIntegersOfRow(i - 1, sudokuArray);
                if (n > numbersPerRow[1])
                {
                    tooEasy = true;
                }
                if (n < numbersPerRow[0])
                {
                    return(-1);
                }

                n = Solver.CountIntegersOfColumn(i - 1, sudokuArray);
                if (n > numbersPerRow[1])
                {
                    tooEasy = true;
                }
                if (n < numbersPerRow[0])
                {
                    return(-1);
                }

                n = Solver.CountIntegersOfBox(SudokuBoxArrayList[i - 1], sudokuArray);
                if (n > numbersPerBox[1])
                {
                    tooEasy = true;
                }
                if (n < numbersPerBox[0])
                {
                    return(-1);
                }
            }

            n = Solver.CountIntegersOfGrid(sudokuArray);
            if (n > overallNumbers[1])
            {
                tooEasy = true;
            }
            if (n < overallNumbers[0])
            {
                return(-1);
            }

            if (tooEasy)
            {
                return(0);
            }

            return(1);
        }
Пример #15
0
 public int[,] GetCopyOfCompleteSudokuArray()
 {
     return(Solver.CopySudoku(SudokuCompleteArray));
 }
Пример #16
0
        /// <summary>Generates a random Sudoku puzzle.</summary>
        /// <returns>The generated results.</returns>
        private static SolverResults GenerateOne(GeneratorOptions options)
        {
            // Generate a full solution randomly, using the solver to solve a completely empty grid.
            // For this, we'll use the elimination techniques that yield fast solving.
            PuzzleState   solvedState   = new PuzzleState();
            SolverOptions solverOptions = new SolverOptions();

            solverOptions.MaximumSolutionsToFind = 1;
            solverOptions.EliminationTechniques  = new List <EliminationTechnique> {
                new NakedSingleTechnique()
            };
            solverOptions.AllowBruteForce = true;
            SolverResults newSolution = Solver.Solve(solvedState, solverOptions);

            // Create options to use for removing filled cells from the complete solution.
            // MaximumSolutionsToFind is set to 2 so that we look for more than 1, but there's no
            // need in continuing once we know there's more than 1, so 2 is a find value to use.
            solverOptions.MaximumSolutionsToFind = 2;
            solverOptions.AllowBruteForce        =
                !options.MaximumNumberOfDecisionPoints.HasValue || options.MaximumNumberOfDecisionPoints > 0;
            solverOptions.EliminationTechniques = solverOptions.AllowBruteForce ?
                                                  new List <EliminationTechnique> {
                new NakedSingleTechnique()
            } : options.Techniques;                                                              // For perf: if brute force is allowed, techniques don't matter!

            // Now that we have a full solution, we want to randomly remove values from cells
            // until we get to a point where there is not a unique solution for the puzzle.  The
            // last puzzle state that did have a unique solution can then be used.
            PuzzleState newPuzzle = newSolution.Puzzle;

            // Get a random ordering of the cells in which to test their removal
            Point [] filledCells = GetRandomCellOrdering(newPuzzle);

            // Do we want to ensure symmetry?
            int filledCellCount = options.EnsureSymmetry && (filledCells.Length % 2 != 0) ? filledCells.Length - 1 : filledCells.Length;

            // If ensuring symmetry...
            if (options.EnsureSymmetry)
            {
                // Find the middle cell and put it at the end of the ordering
                for (int i = 0; i < filledCells.Length - 1; i++)
                {
                    Point p = filledCells[i];
                    if (p.X == newPuzzle.GridSize - p.X - 1 &&
                        p.Y == newPuzzle.GridSize - p.Y - 1)
                    {
                        Point temp = filledCells[i];
                        filledCells[i] = filledCells[filledCells.Length - 1];
                        filledCells[filledCells.Length - 1] = temp;
                    }
                }

                // Modify the random ordering so that paired symmetric cells are next to each other
                // i.e. filledCells[i] and filledCells[i+1] are symmetric pairs
                for (int i = 0; i < filledCells.Length - 1; i += 2)
                {
                    Point p  = filledCells[i];
                    Point sp = new Point(newPuzzle.GridSize - p.X - 1, newPuzzle.GridSize - p.Y - 1);
                    for (int j = i + 1; j < filledCells.Length; j++)
                    {
                        if (filledCells[j].Equals(sp))
                        {
                            Point temp = filledCells[i + 1];
                            filledCells[i + 1] = filledCells[j];
                            filledCells[j]     = temp;
                            break;
                        }
                    }
                }

                // In the order of the array, try to remove each pair from the puzzle and see if it's
                // still solvable and in a valid way.  If it is, greedily leave those cells out of the puzzle.
                // Otherwise, skip them.
                byte [] oldValues = new byte[2];
                for (int filledCellNum = 0;
                     filledCellNum < filledCellCount && newPuzzle.NumberOfFilledCells > options.MinimumFilledCells;
                     filledCellNum += 2)
                {
                    // Store the old value so we can put it back if necessary,
                    // then wipe it out of the cell
                    oldValues[0] = newPuzzle[filledCells[filledCellNum]].Value;
                    oldValues[1] = newPuzzle[filledCells[filledCellNum + 1]].Value;
                    newPuzzle[filledCells[filledCellNum]]     = null;
                    newPuzzle[filledCells[filledCellNum + 1]] = null;

                    // Check to see whether removing it left us in a good position (i.e. a
                    // single-solution puzzle that doesn't violate any of the generation options)
                    SolverResults newResults = Solver.Solve(newPuzzle, solverOptions);
                    if (!IsValidRemoval(newPuzzle, newResults, options))
                    {
                        newPuzzle[filledCells[filledCellNum]]     = oldValues[0];
                        newPuzzle[filledCells[filledCellNum + 1]] = oldValues[1];
                    }
                }

                // If there are an odd number of cells in the puzzle (which there will be
                // as everything we're doing is 9x9, 81 cells), try to remove the odd
                // cell that doesn't have a pairing.  This will be the middle cell.
                if (filledCells.Length % 2 != 0)
                {
                    // Store the old value so we can put it back if necessary,
                    // then wipe it out of the cell
                    int  filledCellNum = filledCells.Length - 1;
                    byte oldValue      = newPuzzle[filledCells[filledCellNum]].Value;
                    newPuzzle[filledCells[filledCellNum]] = null;

                    // Check to see whether removing it left us in a good position (i.e. a
                    // single-solution puzzle that doesn't violate any of the generation options)
                    SolverResults newResults = Solver.Solve(newPuzzle, solverOptions);
                    if (!IsValidRemoval(newPuzzle, newResults, options))
                    {
                        newPuzzle[filledCells[filledCellNum]] = oldValue;
                    }
                }
            }
            // otherwise, it's much easier.
            else
            {
                // Look at each cell in the random ordering.  Try to remove it.
                // If it works to remove it, do so greedily.  Otherwise, skip it.
                for (int filledCellNum = 0;
                     filledCellNum < filledCellCount && newPuzzle.NumberOfFilledCells > options.MinimumFilledCells;
                     filledCellNum++)
                {
                    // Store the old value so we can put it back if necessary,
                    // then wipe it out of the cell
                    byte oldValue = newPuzzle[filledCells[filledCellNum]].Value;
                    newPuzzle[filledCells[filledCellNum]] = null;

                    // Check to see whether removing it left us in a good position (i.e. a
                    // single-solution puzzle that doesn't violate any of the generation options)
                    SolverResults newResults = Solver.Solve(newPuzzle, solverOptions);
                    if (!IsValidRemoval(newPuzzle, newResults, options))
                    {
                        newPuzzle[filledCells[filledCellNum]] = oldValue;
                    }
                }
            }

            // Make sure to now use the techniques specified by the user to score this thing
            solverOptions.EliminationTechniques = options.Techniques;
            SolverResults finalResult = Solver.Solve(newPuzzle, solverOptions);

            // Return the best puzzle we could come up with
            newPuzzle.Difficulty = options.Difficulty;
            return(new SolverResults(PuzzleStatus.Solved, newPuzzle, finalResult.NumberOfDecisionPoints, finalResult.UseOfTechniques));
        }
Пример #17
0
        public static void Solve(Board board)
        {
            var solver = new Solver(board);

            solver.Solve();
        }