Пример #1
0
        /// <inheritdoc/>
        public TPuzzle Solve(TPuzzle puzzle, bool randomizeGuesses = false)
        {
            if (!_AreValuesUnique(puzzle.AllPossibleValuesSpan))
            {
                throw new ArgumentException(
                          $"{nameof(puzzle.AllPossibleValuesSpan)} must all be unique. Received values: {puzzle.AllPossibleValuesSpan.ToString()}.");
            }
            var puzzleCopy = puzzle.DeepCopy();
            var graph      = ExactCoverGraph.Create(puzzleCopy);

            foreach (IConstraint?constraint in _constraints)
            {
                if (!constraint.TryConstrain(puzzleCopy, graph))
                {
                    throw new ArgumentException("Puzzle violates this solver's constraints.");
                }
                ;
            }
            if (!(randomizeGuesses ?
                  _TrySolveRandomly(new Guesser <TPuzzle>(puzzleCopy, graph), new Random()) :
                  _TrySolve(new Guesser <TPuzzle>(puzzleCopy, graph))))
            {
                throw new ArgumentException("Failed to solve the given puzzle.");
            }
            return(puzzleCopy);
        }
Пример #2
0
 internal Guesser(TPuzzle puzzle, ExactCoverGraph graph)
 {
     _puzzle       = puzzle;
     _graph        = graph;
     _setSquares   = new Stack <Guess>(puzzle.NumEmptySquares);
     MaxGuessCount = _graph.AllPossibleValues.Length;
 }
Пример #3
0
 private Guesser(Guesser <TPuzzle> other)
 {
     _puzzle = other._puzzle.DeepCopy();
     // Copy graph, focusing only on 'Unknown' possible square values and (therefore) unsatisfied constraints.
     _graph        = other._graph.CopyUnknowns();
     _setSquares   = new Stack <Guess>(_puzzle.NumEmptySquares);
     MaxGuessCount = other.MaxGuessCount;
 }
Пример #4
0
 private Objective(ExactCoverGraph graph, int countToSatisfy)
 {
     _graph          = graph;
     _countToSatisfy = countToSatisfy;
     _allPossibilitiesAreConcrete     = true;
     _atLeastOnePossibilityIsConcrete = false;
     _state = NodeState.UNKNOWN;
     _nextObjectiveInGraph     = this;
     _previousObjectiveInGraph = this;
 }
Пример #5
0
        private ExactCoverGraph(ExactCoverGraph other)
        {
            int length = other._possibilities.Length;

            _possibilities = new Possibility[length][][];
            for (int rowIndex = 0; rowIndex < length; ++rowIndex)
            {
                _possibilities[rowIndex] = new Possibility[length][];
            }
            _allPossibleValues = other.AllPossibleValues.ToArray();
            ValuesToIndices    = other.ValuesToIndices;
        }
Пример #6
0
        /// <summary>
        /// Creates an exact-cover graph for solving the given puzzle.
        ///
        /// This adds <see cref="Possibility"/> objects for all the unset coordinates in a puzzle on
        /// creation, as well as <see cref="Objective"/> objects that group all the possible values
        /// for each location. These effectively implements the constraint: "Each square in the
        /// puzzle must have one and only one value."
        /// </summary>
        /// <param name="puzzle">The puzzle to solve.</param>
        public static ExactCoverGraph Create(IReadOnlyPuzzle puzzle)
        {
            var graph     = new ExactCoverGraph(puzzle);
            int size      = puzzle.Size;
            int numValues = graph._allPossibleValues.Length;

            for (int rowIndex = 0; rowIndex < size; rowIndex++)
            {
                var possibilitiesRow = graph._possibilities[rowIndex];
                for (int columnIndex = 0; columnIndex < size; columnIndex++)
                {
                    var coord = new Coordinate(rowIndex, columnIndex);
                    if (!puzzle[in coord].HasValue)
Пример #7
0
 /// <inheritdoc />
 void IObjective.DeselectPossibility(Link toDeselect)
 {
     Debug.Assert(!_toPossibility !.GetLinksOnObjective().Contains(toDeselect) ||
                  _toPossibility.GetLinksOnObjective().Count() == 1,
                  "Tried to deselect a link that's not connected to this objective.");
     _ReinsertPossibility(toDeselect);
     if (_selectedCount == _countToSatisfy)
     {
         _state = NodeState.UNKNOWN;
         ExactCoverGraph.ReattachObjective(this);
         Links.RevertOthersOnObjective(
             toDeselect,
             toReattach => toReattach.Possibility.ReturnFromObjective(toReattach));
     }
     --_selectedCount;
 }
Пример #8
0
        private SolveStats _ComputeStats(TPuzzle puzzle, bool validateUniquenessOnly, CancellationToken?token)
        {
            if (!_AreValuesUnique(puzzle.AllPossibleValuesSpan))
            {
                return(new SolveStats());
            }
            var puzzleCopy = puzzle.DeepCopy();
            var graph      = ExactCoverGraph.Create(puzzleCopy);

            foreach (IConstraint?constraint in _constraints)
            {
                if (!constraint.TryConstrain(puzzleCopy, graph))
                {
                    return(new SolveStats());
                }
            }
            return(_TryAllSolutions(new Guesser <TPuzzle>(puzzleCopy, graph), validateUniquenessOnly, token));
        }
Пример #9
0
        public static Objective CreateFullyConnected(
            ExactCoverGraph graph,
            ReadOnlySpan <IPossibility> possibilities,
            int countToSatisfy)
        {
            if (countToSatisfy < 1 || countToSatisfy > possibilities.Length)
            {
                throw new ArgumentException($"{nameof(countToSatisfy)} must be in the inclusive range [1, {nameof(possibilities)}.Length].");
            }
            var objective = new Objective(graph, countToSatisfy);

            foreach (var possibility in possibilities)
            {
                Link.CreateConnectedLink(possibility, objective);
            }
            graph.AttachObjective(objective);
            return(objective);
        }
Пример #10
0
        /// <inheritdoc/>
        public bool TrySolve(TPuzzle puzzle, bool randomizeGuesses = false)
        {
            if (!_AreValuesUnique(puzzle.AllPossibleValuesSpan))
            {
                return(false);
            }
            var graph = ExactCoverGraph.Create(puzzle);

            foreach (IConstraint?constraint in _constraints)
            {
                if (!constraint.TryConstrain(puzzle, graph))
                {
                    return(false);
                }
            }
            return(randomizeGuesses ?
                   _TrySolveRandomly(new Guesser <TPuzzle>(puzzle, graph), new Random()) :
                   _TrySolve(new Guesser <TPuzzle>(puzzle, graph)));
        }