Esempio n. 1
0
            private static bool BruteForceRecursion(Board work, ConstraintData data, int Index)
            {
                if (Index == 81)
                    return true;

                if (work[Index] > 0)
                    return BruteForceRecursion(work, data, Index + 1);

                var loc = new Location(Index);

                for (int i = 1; i < 10; i++)
                {
                    if (!data.DigitInRow[i, loc.Row] && !data.DigitInColumn[i, loc.Column] && !data.DigitInZone[i, loc.Zone])
                    {
                        work[loc] = i;
                        data.DigitInRow[i, loc.Row] = data.DigitInColumn[i, loc.Column] = data.DigitInZone[i, loc.Zone] = true;
                        if (BruteForceRecursion(work, data, Index + 1))
                            return true;
                        data.DigitInRow[i, loc.Row] = data.DigitInColumn[i, loc.Column] = data.DigitInZone[i, loc.Zone] = false;
                    }
                }

                work[Index] = 0;
                return false;
            }
Esempio n. 2
0
            /// <summary>
            /// Tries each filled location, in order. If the result has more than one solution, it is filled back in
            /// </summary>
            /// <returns></returns>
            public Board AllSingles()
            {
                var result = new Board(_parent);

                var Filled = _parent.Find.FilledLocations();

                foreach (var loc in Filled)
                {
                    int test = result[loc];
                    result[loc] = 0;

                    var possible = result.Find.Candidates(loc);

                    if (possible.Count > 1)
                    {
                        int count = 0;
                        foreach (var item in possible)
                        {
                            result[loc] = item;
                            if (result.Fill.Sequential() != null)
                                count++;
                        }

                        if (count > 1)
                            result[loc] = test;
                        else
                            result[loc] = 0;
                    }
                }

                return result;
            }
Esempio n. 3
0
        public void CreatePuzzle()
        {
            for (int iter = 0; iter < Iterations; iter++)
            {
                var Work = Factory.Solution(rnd);
                for (int i = 0; i < 3; i++)
                {
                    var step = new Board(Work);

                    for (int j = 0; j < 3; j++)
                    {
                        Location loc = rnd.Next(81);
                        step[loc] = 0;
                        step[loc.FlipHorizontal()] = 0;
                        step[loc.FlipVertical()] = 0;
                        step[loc.FlipVertical().FlipHorizontal()] = 0;
                    }

                    if (step.ExistsUniqueSolution())
                        Work = step;
                }

                givens[0].Add(Work.Find.FilledLocations().Count());
            }

            WriteStatistics("Givens in generated puzzles: ", givens[0]);
        }
Esempio n. 4
0
            private static bool RandomRecursion(Board work, ConstraintData data, List<int> Digits, int Index)
            {
                if (Index == 81)
                    return true;

                var loc = new Location(Index);

                if (work[loc] > 0)
                    return RandomRecursion(work, data, Digits, Index + 1);

                foreach (int test in Digits)
                {
                    if (!data.DigitInRow[test, loc.Row] && !data.DigitInColumn[test, loc.Column] && !data.DigitInZone[test, loc.Zone])
                    {
                        work[loc] = test;
                        data.DigitInRow[test, loc.Row] = data.DigitInColumn[test, loc.Column] = data.DigitInZone[test, loc.Zone] = true;
                        if (RandomRecursion(work, data, Digits, Index + 1))
                            return true;
                        data.DigitInRow[test, loc.Row] = data.DigitInColumn[test, loc.Column] = data.DigitInZone[test, loc.Zone] = false;
                    }
                }

                work[loc] = 0;
                return false;
            }
        public void TestFill()
        {
            var b = new SudokuSharp.Board(Data);

            foreach (var idx in Location.All)
            {
                Assert.AreEqual(b[idx], Data[idx]);
            }
        }
Esempio n. 6
0
 public ConstraintData(Board Src)
 {
     foreach (var loc in Location.All)
     {
         DigitInRow[Src[loc], loc.Row] =
             DigitInColumn[Src[loc], loc.Column] =
             DigitInZone[Src[loc], loc.Zone] = true;
     }
 }
Esempio n. 7
0
        /// <summary>
        /// Provides a completely filled, randomly generated, Sudoku <see cref="Board"/>
        /// </summary>
        /// <param name="Stream">An existing <see cref="Random"/> number generator</param>
        /// <returns><see cref="Board"/></returns>
        public static Board Solution(Random Stream)
        {
            Board work = null;

            do
            {
                work = new Board().Fill.Randomized(Stream);
            } while (work == null);

            return work;
        }
Esempio n. 8
0
            /// <summary>
            /// Attempts to fill the calling <see cref="Board"/> instance with numbers.
            /// The original instance remains unchanged
            /// </summary>
            /// <returns>Either a new instance of <see cref="Board"/> or, if unsuccessful, null</returns>
            public Board Sequential()
            {
                var work = new Board(_parent);

                ConstraintData data = new ConstraintData(work);

                if (BruteForceRecursion(work, data, 0))
                    return work;

                return null;
            }
Esempio n. 9
0
        /// <summary>
        /// Calls Cut.Quad, .Pair, and .Single the specified number of times on the provided <see cref="Board"/>
        /// </summary>
        /// <param name="Source">The <see cref="Board"/> to be modified</param>
        /// <param name="Stream">An existing <see cref="Random"/> number generator</param>
        /// <param name="QuadsToCut">The number of times to call Cut.Quad</param>
        /// <param name="PairsToCut">The number of times to call Cut.Pair</param>
        /// <param name="SinglesToCut">The number of times to call Cut.Single</param>
        /// <returns></returns>
        public static Board Puzzle(Board Source, Random Stream, int QuadsToCut, int PairsToCut, int SinglesToCut)
        {
            var work = new Board(Source);

            for (int i = 0; i < QuadsToCut; i++)
                work = work.Cut.Quad(Stream);
            for (int i = 0; i < PairsToCut; i++)
                work = work.Cut.Pair(Stream);
            for (int i = 0; i < SinglesToCut; i++)
                work = work.Cut.Single(Stream);

            return work;
        }
Esempio n. 10
0
            /// <summary>
            /// Attempts to fill the calling <see cref="Board"/> instance with numbers.
            /// The original instance remains unchanged
            /// </summary>
            /// <param name="Stream">If you already have a <see cref="Random"/> stream, you may provide it here</param>
            /// <returns>Either a new instance of <see cref="Board"/> or, if unsuccessful, null</returns>
            public Board Randomized(Random Stream)
            {
                var result = new Board(_parent);
                ConstraintData data = new ConstraintData(result);

                var digits = new List<int>();
                for (int i = 1; i < 10; i++)
                    digits.Insert(Stream.Next(digits.Count), i);

                if (RandomRecursion(result, data, digits, 0))
                    return result;

                return null;
            }
Esempio n. 11
0
        public void FindEmptyLocations()
        {
            for (int iter = 0; iter < Iterations; iter++)
            {
                var src = Factory.Solution(rnd);

                for (int i = 0; i < NumBatches; i++)
                {
                    var work = new Board(src);
                    for (int cut = 0; cut < 60; cut++)
                        work[rnd.Next(81)] = 0;

                    for (int j = 0; j < BatchSize; j++)
                    {
                        var result = work.Find.EmptyLocations();
                    }
                }
            }
        }
        private static int CountRecursion(Board work, int idx)
        {
            if (idx == 81) // using int instead of Location because Location CAN'T have a value of 81
                return 1;

            if (work[idx] > 0)
                return CountRecursion(work, idx + 1);

            var possible = work.Find.Candidates(idx);
            if (possible.Count == 0)
                return 0;

            int count = 0;
            foreach (var item in possible)
            {
                work[idx] = item;
                count += CountRecursion(work, idx + 1);
            }
            work[idx] = 0;

            return count;
        }
        /// <summary>
        /// Verifies the existance of a unique solution
        /// </summary>
        /// <value>
        /// <c>true</c> if [a unique solution exists]; otherwise, <c>false</c>.
        /// </value>
        public bool ExistsUniqueSolution()
        {
            if (IsSolved) return true;
            if (!IsValid) return false;

            for (int i = 0; i < 81; i++)
            {
                if (GetCell(i) == 0)
                { // Only test against empty cells
                    var Candidates = Find.Candidates(i);

                    if (Candidates.Count > 1)
                    { // Only test where there's more than one option
                        bool foundSolution = false;
                        var working = new Board(this);

                        foreach (int test in Candidates)
                        {
                            working[i] = test;

                            if (working.Fill.Sequential() != null)
                            {
                                // We just found a solution. If we have already found a solution, then multiple exist and we may quit.
                                if (foundSolution)
                                    return false;

                                foundSolution = true;
                            }
                        }
                    }
                }
            }
            return true;
        }
        /// <summary>
        /// Attempts to count all possible solutions
        /// </summary>
        /// <returns></returns>
        public int CountSolutions()
        {
            Board work = new Board(this);

            // fill everything that has definite answers
            var mustFill = work.Find.AllSingles().Union(work.Find.LockedCandidates());
            while (mustFill.Count() > 0)
            {
                foreach (var item in mustFill)
                    work[item.Key] = item.Value;

                mustFill = work.Find.LockedCandidates();
            }

            if (IsSolved)
                return 1;

            return CountRecursion(work, 0);
        }
Esempio n. 15
0
 /// <summary>
 /// Hack to allow a namespace inside a class.
 /// </summary>
 public _CutClass(Board Parent)
 {
     _parent = Parent;
 }
Esempio n. 16
0
            /// <summary>
            /// Attempts to cut a single location
            /// </summary>
            /// <param name="Stream">An existing <see cref="Random"/> number generator</param>
            /// <returns>If the result has a unique solution, then the new <see cref="Board"/>. Otherwise, the original</returns>
            public Board Single(Random Stream)
            {
                var result = new Board(_parent);

                var Filled = _parent.Find.FilledLocations().ToList();

                if (Filled.Count > 0)
                {
                    result[Filled[Stream.Next(Filled.Count)]] = 0;

                    if (result.ExistsUniqueSolution())
                        return result;
                }
                return _parent;
            }
Esempio n. 17
0
            /// <summary>
            /// Attempts to cut 4 locations from the current board, mirrored about both horizontal and vertical axes.
            /// </summary>
            /// <param name="Stream">An existing <see cref="Random"/> number generator</param>
            /// <returns>If the result has a unique solution, then the new <see cref="Board"/>. Otherwise, the original</returns>
            public Board Quad(Random Stream)
            {
                var result = new Board(_parent);

                var Filled = _parent.Find.FilledLocations().ToList();

                if (Filled.Count > 0)
                {
                    Location loc = new Location(Filled[Stream.Next(Filled.Count)]);

                    result[loc] = 0;
                    result[loc.FlipHorizontal()] = 0;
                    result[loc.FlipVertical()] = 0;
                    result[loc.FlipHorizontal().FlipVertical()] = 0;

                    if (result.ExistsUniqueSolution())
                        return result;
                }
                return _parent;
            }
Esempio n. 18
0
 /// <summary>
 /// Copies an instance of the <see cref="Board"/> class.
 /// </summary>
 /// <param name="src">The source.</param>
 public Board(Board src)
 {
     Array.Copy(src.data, this.data, 81);
 }
Esempio n. 19
0
 /// <summary>
 /// Hack to allow a namespace inside a class.
 /// </summary>
 public _FillClass(Board Parent)
 {
     _parent = Parent;
 }