Exemple #1
0
        private static void SolveSudokuProblem()
        {
            var initialState =
                new SudokuState(
                    new int[9, 9]
            {
                { 0, 0, 5, 0, 3, 0, 0, 6, 2 },
                { 0, 3, 0, 8, 9, 0, 0, 0, 1 },
                { 0, 2, 9, 4, 0, 0, 0, 0, 0 },
                { 0, 0, 0, 2, 6, 0, 0, 0, 0 },
                { 8, 9, 3, 0, 0, 0, 0, 0, 0 },
                { 6, 0, 0, 0, 0, 0, 8, 5, 0 },
                { 3, 6, 8, 9, 0, 0, 0, 0, 0 },
                { 0, 0, 4, 0, 0, 0, 0, 9, 6 },
                { 0, 0, 0, 0, 4, 3, 0, 0, 0 }
            });

            var actionFunction  = new SudokuActionFunction();
            var resultFunction  = new SudokuResultFunction();
            var goalTest        = new SudokuGoalTest();
            var stepCost        = new SudokuStepCost();
            var searchAlgorithm = new GraphSearch <SudokuState, SudokuAction>();

            SolveProblem(actionFunction, resultFunction, goalTest, stepCost, initialState, searchAlgorithm);
        }
Exemple #2
0
        private void Solve(SudokuPuzzle puzzle, string input, string expected)
        {
            var state  = SudokuState.Parse(input);
            var solver = new SudokuSolver(puzzle);

            var sw     = Stopwatch.StartNew();
            var actual = solver.Solve(state);

            sw.Stop();

            Console.WriteLine("Elapsed: {0:#,##0.#####} ms", sw.Elapsed.TotalMilliseconds);

            Console.WriteLine(actual);

            Assert.IsTrue(actual.IsSolved, "The puzzle is not solved.");
            Assert.AreEqual(SudokuState.Parse(expected), actual);
        }
Exemple #3
0
        public void Parse_3x3_ReturnSudokuState3x3()
        {
            var puzzle = SudokuState.Parse(@"
				53.|.7.|...
				6..|195|...
				.98|...|.6.
				---+---+---
				8..|.6.|..3
				4..|8.3|..1
				7..|.2.|..6
				---+---|---
				.6.|...|28.
				...|419|..5
				...|.8.|.79"                );

            Assert.AreEqual(3, puzzle.Size);
        }
Exemple #4
0
        /// <summary>Reduces hidden singles.</summary>
        /// <remarks>
        /// Very frequently, there is only one candidate for a given row, column or
        /// sub square, but it is hidden among other candidates.
        /// </remarks>
        private ReduceResult ReduceHiddenSingles(ReduceResult result, SudokuState state)
        {
            if (SkipMethod(SudokuSolverMethods.HiddenSingles, result)) { return result; }

            foreach (var region in Puzzle.Regions)
            {
                foreach (var singleValue in Puzzle.SingleValues)
                {
                    var cnt = 0;
                    var found = -1;
                    foreach (var index in region)
                    {
                        var val = state[index];
                        if ((val & singleValue) != SudokuPuzzle.Invalid)
                        {
                            unchecked { cnt++; }
                            if (state.IsKnown(index))
                            {
                                found = -1;
                                break;
                            }
                            else if (cnt == 1)
                            {
                                found = index;
                            }
                        }
                    }
                    if (cnt == 1 && found != -1)
                    {
                        result |= state.AndMask(found, singleValue);
                    }
                    else if (cnt == 0)
                    {
                        return ReduceResult.Inconsistend;
                    }
                }
            }
            return result;
        }
Exemple #5
0
        /// <summary>Solves a Sudoku puzzle given the Sudoku state.</summary>
        public SudokuState Solve(SudokuState sudokuState)
        {
            // As states are not immutable, create a copy.
            var state = sudokuState.Copy();

            var result = ReduceResult.Reduced;

            while (result == ReduceResult.Reduced)
            {
                result = ReduceResult.None;
                result |= ReduceSingles(result, state);
                result |= ReduceHiddenSingles(result, state);
                result |= ReduceLockedCandidates(result, state);
                result |= ReduceNakedPairs(result, state);
                result |= ReduceNakedTriples(result, state);
                result |= ReduceNakedQuads(result, state);
            }
            if (result.HasFlag(ReduceResult.Inconsistend))
            {
                throw new InvalidPuzzleException();
            }
            return state;
        }
Exemple #6
0
        /// <summary>Reduces singles.</summary>
        /// <remarks>
        /// Any cells which have only one candidate can safely be assigned that value.
        /// 
        /// It is very important whenever a value is assigned to a cell, that this
        /// value is also excluded as a candidate from all other blank cells sharing
        /// the same row, column and sub square.
        /// </remarks>
        private ReduceResult ReduceSingles(ReduceResult result, SudokuState state)
        {
            if (SkipMethod(SudokuSolverMethods.Singles, result)) { return result; }

            result = ReduceResult.Reduced;
            while (result == ReduceResult.Reduced)
            {
                result = ReduceResult.None;

                for (var index1 = 0; index1 <= Puzzle.MaximumIndex; index1++)
                {
                    if (state.IsKnown(index1))
                    {
                        foreach (var group in Puzzle.Lookup[index1])
                        {
                            foreach (var index0 in group)
                            {
                                if (index0 != index1)
                                {
                                    result |= state.Exclude(index0, index1);
                                }
                            }
                        }
                    }
                }
            }
            return result;
        }
Exemple #7
0
        /// <summary>Reduces naked triples.</summary>
        private ReduceResult ReduceNakedTriples(ReduceResult result, SudokuState state)
        {
            if (SkipMethod(SudokuSolverMethods.NakedTriples, result)) { return result; }

            foreach (var singleValue in Puzzle.SingleValues)
            {
                foreach (var region in Puzzle.Regions)
                {
                    var index0 = -1;
                    var index1 = -1;
                    var index2 = -1;

                    var match = singleValue;

                    foreach (var index in region)
                    {
                        var value = state[index];
                        if (!state.IsKnown(index) && (value & match) != SudokuPuzzle.Invalid)
                        {
                            match |= value;

                            /**/ if (index0 == -1) { index0 = index; }
                            else if (index1 == -1) { index1 = index; }
                            else if (index2 == -1) { index2 = index; }
                            else { index2 = -1; break; }
                        }
                    }
                    // We found 3 cells.
                    if (index2 != -1 && SudokuCell.Count(match) == 3)
                    {
                        foreach (var index in region)
                        {
                            if (index != index0 && index != index1 && index != index2)
                            {
                                result |= state.AndMask(index, ~match);
                            }
                        }
                    }
                }
            }
            return result;
        }
Exemple #8
0
        /// <summary>Reduces options that should be in the intersection.</summary>
        private ReduceResult ReduceLockedCandidates(ReduceResult result, SudokuState state)
        {
            if (SkipMethod(SudokuSolverMethods.LockedCandidates, result)) { return result; }

            foreach (var region in Puzzle.Regions)
            {
                foreach (var other in region.Intersected)
                {
                    ulong combined = 0;
                    foreach (var index in region)
                    {
                        if (!other.Contains(index))
                        {
                            combined |= state[index];
                        }
                    }
                    // There are options that should be in the intersection.
                    if (combined != Puzzle.Unknown)
                    {
                        foreach (var index in other)
                        {
                            if (!region.Contains(index))
                            {
                                var val = state[index];
                                var nw = val & combined;
                                result |= state.AndMask(index, nw);
                            }
                        }
                    }
                }
            }
            return result;
        }
Exemple #9
0
 public SudokuSolver(SudokuState sudokuState, SudokuBlock sudokuBlock)
 {
     _sudokuState = sudokuState;
     _sudokuBlock = sudokuBlock;
 }