Exemple #1
0
        private bool _TrySolve(SquareTracker <TPuzzle> tracker)
        {
            var puzzle = tracker.Puzzle;

            if (puzzle.NumEmptySquares == 0)
            {
                return(true);
            }
            Coordinate c = tracker.GetBestCoordinateToGuess();
            Span <int> possibleValues = stackalloc int[puzzle.Size];
            int        numPossible    = tracker.PopulatePossibleValues(in c, possibleValues);

            for (int i = 0; i < numPossible; ++i)
            {
                int possibleValue = possibleValues[i];
                if (tracker.TrySet(in c, possibleValue))
                {
                    if (_TrySolve(tracker))
                    {
                        return(true);
                    }
                    tracker.UnsetLast();
                }
            }
            return(false);
        }
 /// <summary>
 /// Constructs a solver for the given square tracker.
 /// </summary>
 /// <param name="tracker">A square tracker referencing the puzzle to solve.</param>
 public PuzzleSolver(
     IPuzzle puzzle,
     PossibleValues possibleValues,
     ISudokuRuleKeeper ruleKeeper,
     ISudokuHeuristic?heuristic = null)
 {
     _tracker = new SquareTracker(puzzle, possibleValues, ruleKeeper, heuristic);
 }
Exemple #3
0
 /// <inheritdoc/>
 public bool TrySolve(TPuzzle puzzle, bool randomizeGuesses = false)
 {
     if (!SquareTracker <TPuzzle> .TryInit(puzzle, _ruleKeeper, _heuristic, out SquareTracker <TPuzzle>?tracker))
     {
         return(false);
     }
     return(randomizeGuesses ? _TrySolveRandomly(tracker !, new Random()) : _TrySolve(tracker !));
 }
 /// <summary>
 /// Creates a deep copy of this ISquareTracker in its current state.
 /// </summary>
 public SquareTracker(SquareTracker existing)
 {
     _puzzle         = existing._puzzle.DeepCopy();
     _possibleValues = new PossibleValues(existing._possibleValues);
     _ruleKeeper     = existing._ruleKeeper.CopyWithNewReferences(_puzzle, _possibleValues);
     _heuristic      = existing._heuristic?.CopyWithNewReferences(
         _puzzle, _possibleValues, _ruleKeeper.GetRules());
     _setCoords = new Stack <Coordinate>(existing._setCoords);
     _coordsThatUsedHeuristics = new Stack <Coordinate>(existing._coordsThatUsedHeuristics);
 }
Exemple #5
0
 /// <summary>
 /// Creates a deep copy of this tracker in its current state.
 /// </summary>
 internal SquareTracker(SquareTracker <TPuzzle> existing)
 {
     _puzzle    = existing._puzzle.DeepCopy();
     _setCoords = new Stack <Coordinate>(existing._setCoords);
     if (existing._coordsThatUsedHeuristics is not null)
     {
         _coordsThatUsedHeuristics = new Stack <Coordinate>(existing._coordsThatUsedHeuristics !);
     }
     _ruleKeeper = existing._ruleKeeper.CopyWithNewReferences(_puzzle);
     _heuristic  = existing._heuristic?.CopyWithNewReferences(
         _puzzle, _ruleKeeper.GetRules());
 }
Exemple #6
0
 private SolveStats _ComputeStatsForAllSolutions(
     TPuzzle puzzle, bool validateUniquenessOnly, CancellationToken?cancellationToken)
 {
     cancellationToken?.ThrowIfCancellationRequested();
     // Copy the puzzle so that the given puzzle is not modified.
     if (!SquareTracker <TPuzzle> .TryInit(puzzle.DeepCopy(), _ruleKeeper, _heuristic, out SquareTracker <TPuzzle>?tracker))
     {
         // No solutions.
         return(new SolveStats());
     }
     return(_TryAllSolutions(tracker !, validateUniquenessOnly, cancellationToken));
 }
Exemple #7
0
        private bool _TrySolveRandomly(SquareTracker <TPuzzle> tracker, Random random)
        {
            if (tracker.Puzzle.NumEmptySquares == 0)
            {
                return(true);
            }
            Coordinate c = tracker.GetBestCoordinateToGuess();
            Span <int> possibleValues = stackalloc int[tracker.Puzzle.Size];
            int        numPossible    = tracker.PopulatePossibleValues(in c, possibleValues);

            while (numPossible > 0)
            {
                int possibleValue = Spans.PopRandom(random, possibleValues[0..numPossible--]);
Exemple #8
0
 /// <summary>
 /// Tries to construct and initialize a tracker for the given puzzle, rules, and heuristics.
 /// </summary>
 /// <param name="puzzle">The puzzle to solve.</param>
 /// <param name="ruleKeeper">The rule-keeper to satisfy.</param>
 /// <param name="heuristic">An optional heuristic to user.</param>
 /// <param name="tracker">
 /// An <c>out</c> param where the tracker will be created. Set to null if initialization
 /// fails (i.e. this method returns false).
 /// </param>
 /// <returns>
 /// False if initialization fails, for example if the puzzle violates a rule, else true.
 /// </returns>
 internal static bool TryInit(
     TPuzzle puzzle,
     IRuleKeeper ruleKeeper,
     IHeuristic?heuristic,
     out SquareTracker <TPuzzle>?tracker)
 {
     if (!ruleKeeper.TryInit(puzzle) ||
         (!heuristic?.TryInitFor(puzzle) ?? false))
     {
         tracker = null;
         return(false);
     }
     tracker = new SquareTracker <TPuzzle>(puzzle, ruleKeeper, heuristic);
     return(true);
 }
        private static SolveStats _TryAllSolutionsWithGuess(
            SquareTracker tracker,
            Coordinate c,
            List <int> valuesToGuess)
        {
            var solveStats = new SolveStats();

            for (int i = 0; i < valuesToGuess.Count - 1; i++)
            {
                var trackerCopy = new SquareTracker(tracker);
                if (trackerCopy.TrySet(in c, valuesToGuess[i]))
                {
                    SolveStats guessStats = _TryAllSolutions(trackerCopy);
                    solveStats.NumSolutionsFound += guessStats.NumSolutionsFound;
                    solveStats.NumSquaresGuessed += guessStats.NumSquaresGuessed;
                    solveStats.NumTotalGuesses   += guessStats.NumTotalGuesses;
                }
            }
            if (tracker.TrySet(in c, valuesToGuess[^ 1]))
        private static SolveStats _TryAllSolutions(SquareTracker tracker)
        {
            if (tracker.Puzzle.NumEmptySquares == 0)
            {
                return(new SolveStats()
                {
                    NumSolutionsFound = 1,
                });
            }
            Coordinate c = tracker.GetBestCoordinateToGuess();
            List <int>?possibleValues = tracker.GetPossibleValues(in c);

            if (possibleValues.Count == 1)
            {
                if (tracker.TrySet(in c, possibleValues[0]))
                {
                    return(_TryAllSolutions(tracker));
                }
                return(new SolveStats());
            }
            return(_TryAllSolutionsWithGuess(tracker, c, possibleValues));
        }
 /// <summary>
 /// Constructs a solver for a standard Sudoku puzzle that uses a standard heuristic and
 /// standard rule keeper. Provided for convenience.
 /// </summary>
 public PuzzleSolver(Puzzle puzzle)
 {
     _tracker = new SquareTracker(puzzle);
 }