コード例 #1
0
        public int Solve(byte[] puzzle, byte[] solution, out int difficulty)
        {
            difficulty = 0;
            var context = new PuzzleSolverContext(puzzle.ToArray(), solution);

            var possibilities = InitializePossibilities(puzzle);

            if (!PuzzleIsValid(puzzle, possibilities))
            {
                return(0);
            }

            RecursiveSolve(context, possibilities, 0);

            // Calculate a difficulty score
            var empty = 0;

            foreach (var value in puzzle)
            {
                if (!CellIsSet(value))
                {
                    empty++;
                }
            }

            var multiplier = 1;

            while (multiplier <= puzzle.Length)
            {
                multiplier *= 10;
            }

            difficulty = context.BranchDifficulty * multiplier + empty;

            return(context.Count);
        }
コード例 #2
0
        public void RecursiveSolve(PuzzleSolverContext context, BitArray[] possibilities, int difficulty)
        {
            var cellIndex = FindCellWithFewestPossibilities(context.Problem, possibilities);

            if (cellIndex < 0)
            {
                if (context.Count == 0)
                {
                    context.BranchDifficulty = difficulty;
                    if (context.Solution != null)
                    {
                        Array.Copy(context.Problem, context.Solution, context.Solution.Length);
                    }
                }

                context.Count++;
                return;
            }

            var mask = new BitArray(possibilities[cellIndex]);
            int branchingFactor;

            // If we can't determine a cell value, see if set-oriented
            // backtracking provides a smaller branching factor.
            if (CountSetBits(mask) > 1)
            {
                var offsets = new int[Size];

                var setSize = PossibilityAnalysis(context.Problem, possibilities, ref offsets, out var value);
                if (setSize >= 0 && setSize < CountSetBits(mask))
                {
                    branchingFactor = setSize - 1;
                    difficulty     += branchingFactor * branchingFactor;

                    for (var i = 0; i < setSize; i++)
                    {
                        var offset = offsets[i];

                        var newPossibilities = possibilities
                                               .Select(x => new BitArray(x))
                                               .ToArray();

                        EliminatePossibilities(newPossibilities, offset % Size, offset / Size, value);

                        context.Problem[offset] = Convert.ToByte(value);
                        RecursiveSolve(context, newPossibilities, difficulty);
                        context.Problem[offset] = 0;

                        if (context.Count >= 2)
                        {
                            return;
                        }
                    }

                    return;
                }
            }

            // Otherwise, fall back to cell-oriented backtracking.
            branchingFactor = CountSetBits(mask) - 1;
            difficulty     += branchingFactor * branchingFactor;

            for (var i = 0; i < Size; i++)
            {
                if (mask[i])
                {
                    var newPossibilities = possibilities
                                           .Select(x => new BitArray(x))
                                           .ToArray();

                    EliminatePossibilities(newPossibilities, cellIndex % Size, cellIndex / Size, i + 1);
                    context.Problem[cellIndex] = Convert.ToByte(i + 1);
                    RecursiveSolve(context, newPossibilities, difficulty);

                    if (context.Count >= 2)
                    {
                        return;
                    }
                }
            }

            context.Problem[cellIndex] = 0;
        }