Beispiel #1
0
 private DiagonalUniquenessRule(DiagonalUniquenessRule existing, IReadOnlyPuzzle puzzle)
 {
     _puzzle            = puzzle;
     _unsetBackwardDiag = existing._unsetBackwardDiag;
     _unsetForwardDiag  = existing._unsetForwardDiag;
     _allUnset          = existing._allUnset;
 }
        /// <inheritdoc/>
        public void Constrain(IReadOnlyPuzzle puzzle, ExactCoverMatrix matrix)
        {
            Span <bool> isConstraintSatisfiedAtIndex =
                stackalloc bool[matrix.AllPossibleValues.Length];

            for (int row = 0; row < puzzle.Size; row++)
            {
                ReadOnlySpan <Square?> rowSquares = matrix.GetSquaresOnRow(row);
                isConstraintSatisfiedAtIndex.Clear();
                for (int col = 0; col < puzzle.Size; col++)
                {
                    int?puzzleValue = puzzle[row, col];
                    if (puzzleValue.HasValue)
                    {
                        isConstraintSatisfiedAtIndex[matrix.ValuesToIndices[puzzleValue.Value]] = true;
                    }
                }
                for (int valueIndex = 0; valueIndex < isConstraintSatisfiedAtIndex.Length; valueIndex++)
                {
                    if (isConstraintSatisfiedAtIndex[valueIndex])
                    {
                        ConstraintUtil.DropPossibleSquaresForValueIndex(rowSquares, valueIndex, matrix);
                        continue;
                    }
                    ConstraintUtil.AddConstraintHeadersForValueIndex(rowSquares, valueIndex, matrix);
                }
            }
        }
 internal static void AssertMagicSquaresSatisfied(
     IReadOnlyPuzzle puzzle, Box[] boxesToCheck, int expectedSum, bool verifyDiagonals)
 {
     foreach (Box box in boxesToCheck)
     {
         int boxSize    = box.Size;
         var rowSums    = new int[boxSize];
         var colSums    = new int[boxSize];
         var startCoord = box.TopLeft;
         var endCoord   = new Coordinate(startCoord.Row + boxSize, startCoord.Column + boxSize);
         for (int row = startCoord.Row; row < endCoord.Row; ++row)
         {
             for (int col = startCoord.Column; col < endCoord.Column; ++col)
             {
                 var value = puzzle[row, col].Value;
                 rowSums[row - startCoord.Row]    += value;
                 colSums[col - startCoord.Column] += value;
             }
         }
         Assert.All(rowSums, sum => Assert.Equal(expectedSum, sum));
         Assert.All(colSums, sum => Assert.Equal(expectedSum, sum));
         if (verifyDiagonals)
         {
             int diagSum = 0;
             for (Coordinate coord = startCoord; coord != endCoord; coord = new Coordinate(coord.Row + 1, coord.Column + 1))
             {
                 var value = puzzle[in coord].Value;
Beispiel #4
0
        /// <summary>
        /// Enforces uniqueness of the values at the given coordinates.
        /// </summary>
        /// <remarks>
        /// This drops any <see cref="PossibleValue"/>s that are no longer possible, and
        /// adds <see cref="ConstraintHeader"/>s and links to enforce this constraint for the ones
        /// that are still possible.
        /// </remarks>
        /// <param name="puzzle">The puzzle being solved.</param>
        /// <param name="squareCoordinates">
        /// The coordinates that must contain unique values.
        /// </param>
        /// <param name="matrix">The exact cover matrix for the current puzzle.</param>
        /// <exception cref="ArgumentException">
        /// Thrown if the puzzle violates uniquness for the given coordinates.
        /// </exception>
        public static void ImplementUniquenessConstraintForSquares(
            IReadOnlyPuzzle puzzle,
            ReadOnlySpan <Coordinate> squareCoordinates,
            ExactCoverMatrix matrix)
        {
            Span <bool> isConstraintSatisfiedAtIndex =
                stackalloc bool[matrix.AllPossibleValues.Length];

            CheckForSetValues(puzzle, matrix, squareCoordinates, isConstraintSatisfiedAtIndex);
            var squares = new Square?[squareCoordinates.Length];

            for (int i = 0; i < squares.Length; i++)
            {
                squares[i] = matrix.GetSquare(in squareCoordinates[i]);
            }
            for (int valueIndex = 0; valueIndex < isConstraintSatisfiedAtIndex.Length; valueIndex++)
            {
                if (isConstraintSatisfiedAtIndex[valueIndex])
                {
                    DropPossibleSquaresForValueIndex(squares, valueIndex, matrix);
                    continue;
                }
                AddConstraintHeadersForValueIndex(squares, valueIndex, matrix);
            }
        }
Beispiel #5
0
        /// <inheritdoc/>
        public virtual bool TryInit(IReadOnlyPuzzle puzzle, BitVector uniquePossibleValues)
        {
            int numDimensions = GetNumDimensions(puzzle);

            if (numDimensions != _dimensions?.Length)
            {
                _dimensions = new BitVector[numDimensions];
            }
            _dimensions.AsSpan().Fill(uniquePossibleValues);
            int size = puzzle.Size;

            for (int row = 0; row < size; ++row)
            {
                for (int col = 0; col < size; ++col)
                {
                    int dimension = GetDimension(new(row, col));
                    int?val       = puzzle[row, col];
                    if (!val.HasValue)
                    {
                        continue;
                    }
                    if (!_IsPossible(dimension, val.Value))
                    {
                        // Puzzle has duplicate value on this dimension.
                        return(false);
                    }
                    _RemovePossible(dimension, val.Value);
                }
            }
            return(true);
        }
Beispiel #6
0
 /// <inheritdoc/>
 public void Constrain(IReadOnlyPuzzle puzzle, ExactCoverMatrix matrix)
 {
     for (int box = 0; box < puzzle.Size; box++)
     {
         _AppendConstraintHeadersInBox(box, (IReadOnlyBoxPuzzle)puzzle, matrix);
     }
 }
Beispiel #7
0
        public static bool TryImplementUniquenessConstraintForSquares(
            IReadOnlyPuzzle puzzle,
            ReadOnlySpan <Coordinate> squareCoordinates,
            ExactCoverGraph graph)
        {
            Span <bool> isConstraintSatisfiedAtIndex =
                stackalloc bool[graph.AllPossibleValues.Length];

            if (!TryCheckForSetValues(puzzle, graph, squareCoordinates, isConstraintSatisfiedAtIndex))
            {
                return(false);
            }
            Possibility?[]?[] squares = new Possibility[squareCoordinates.Length][];
            for (int i = 0; i < squares.Length; i++)
            {
                squares[i] = graph.GetAllPossibilitiesAt(in squareCoordinates[i]);
            }
            for (int possibilityIndex = 0; possibilityIndex < isConstraintSatisfiedAtIndex.Length; possibilityIndex++)
            {
                if (isConstraintSatisfiedAtIndex[possibilityIndex])
                {
                    if (!TryDropPossibilitiesAtIndex(squares, possibilityIndex))
                    {
                        return(false);
                    }
                    continue;
                }
                if (!TryAddObjectiveForPossibilityIndex(squares, possibilityIndex, graph, requiredCount: 1, objective: out _))
                {
                    return(false);
                }
            }
            return(true);
        }
Beispiel #8
0
 public DiagonalUniquenessRule(IReadOnlyPuzzle puzzle, BitVector allUniqueValues)
 {
     Debug.Assert(puzzle.Size == allUniqueValues.Count,
                  $"Can't enforce box uniqueness for mismatched puzzle size {puzzle.Size} and number of unique values {allUniqueValues.Count}");
     _puzzle   = puzzle;
     _allUnset = _unsetForwardDiag = _unsetBackwardDiag = allUniqueValues;
     // Iterate through the backward diagonal (like a backslash '\')
     for (int row = 0, col = 0; row < puzzle.Size; row++, col++)
     {
         int?val = puzzle[row, col];
         if (val.HasValue)
         {
             if (!_unsetBackwardDiag.IsBitSet(val.Value))
             {
                 throw new ArgumentException(
                           $"Puzzle does not satisfy diagonal uniqueness rule at ({row}, {col}).");
             }
             _unsetBackwardDiag.UnsetBit(val.Value);
         }
     }
     // Iterate through the forward diagonal (like a forward slash '/')
     for (int row = 0, col = puzzle.Size - 1; row < puzzle.Size; row++, col--)
     {
         int?val = puzzle[row, col];
         if (val.HasValue)
         {
             if (!_unsetForwardDiag.IsBitSet(val.Value))
             {
                 throw new ArgumentException(
                           $"Puzzle does not satisfy diagonal uniqueness rule at ({row}, {col}).");
             }
             _unsetForwardDiag.UnsetBit(val.Value);
         }
     }
 }
 public UniqueInRowHeuristic(IReadOnlyPuzzle puzzle, PossibleValues possibleValues, IMissingRowValuesTracker rule)
 {
     _puzzle                 = puzzle;
     _possibleValues         = possibleValues;
     _rowTracker             = rule;
     _possiblesToCheckInRow  = new BitVector[puzzle.Size];
     _previousPossiblesStack = new Stack <IReadOnlyDictionary <Coordinate, BitVector> >();
 }
Beispiel #10
0
 public BoxPossibleValues CopyWithNewReference(IReadOnlyPuzzle puzzle)
 {
     if (_puzzle.Size != puzzle.Size)
     {
         throw new ArgumentException("Puzzle sizes should match.");
     }
     return(new BoxPossibleValues(this, puzzle));
 }
 /// <inheritdoc/>
 public ISudokuRule CopyWithNewReference(IReadOnlyPuzzle puzzle)
 {
     if (puzzle is IReadOnlyBoxPuzzle boxPuzzle)
     {
         return(new BoxUniquenessRule(this, boxPuzzle));
     }
     throw new ArgumentException($"An {nameof(IReadOnlyBoxPuzzle)} is required to copy {nameof(BoxUniquenessRule)}.");
 }
 public UniqueInColumnHeuristic(IReadOnlyPuzzle puzzle, PossibleValues possibleValues, IMissingColumnValuesTracker rule)
 {
     _puzzle                   = puzzle;
     _possibleValues           = possibleValues;
     _columnTracker            = rule;
     _possiblesToCheckInColumn = new BitVector[puzzle.Size];
     _previousPossiblesStack   = new Stack <IReadOnlyDictionary <Coordinate, BitVector> >(puzzle.NumEmptySquares);
 }
 /// <summary>
 /// Creates a deep copy of this heuristic. Requires <c>rules</c> to contain an
 /// <see cref="IMissingRowValuesTracker"/>.
 /// </summary>
 public ISudokuHeuristic CopyWithNewReferences(
     IReadOnlyPuzzle puzzle,
     PossibleValues possibleValues,
     IReadOnlyList <ISudokuRule> rules)
 {
     return(new UniqueInRowHeuristic(
                this, puzzle, possibleValues,
                (IMissingRowValuesTracker)rules.First(r => r is IMissingRowValuesTracker)));
 }
Beispiel #14
0
 public PossibleValues(IReadOnlyPuzzle puzzle, BitVector allPossible)
 {
     _possibleValues = new BitVector[puzzle.Size, puzzle.Size];
     AllPossible     = allPossible;
     foreach (Coordinate c in puzzle.GetUnsetCoords())
     {
         _possibleValues[c.Row, c.Column] = AllPossible;
     }
 }
 /// <inheritdoc/>
 public override bool TryInit(IReadOnlyPuzzle puzzle, BitVector uniquePossibleValues)
 {
     if (!base.TryInit(puzzle, uniquePossibleValues))
     {
         return(false);
     }
     _puzzle = puzzle;
     return(true);
 }
Beispiel #16
0
 /// <inheritdoc/>
 public ISudokuRuleKeeper CopyWithNewReferences(
     IReadOnlyPuzzle puzzle, PossibleValues possibleValues)
 {
     if (puzzle is IReadOnlyBoxPuzzle boxPuzzle)
     {
         return(new StandardRuleKeeper(this, boxPuzzle, possibleValues));
     }
     throw new ArgumentException($"An {nameof(IReadOnlyBoxPuzzle)} is required to copy {nameof(StandardRuleKeeper)}.");
 }
Beispiel #17
0
        private bool _TryConstrainBox(Box box, IReadOnlyPuzzle puzzle, ExactCoverGraph graph)
        {
            Coordinate               startCoord  = box.TopLeft;
            Span <Coordinate>        toConstrain = stackalloc Coordinate[_squareSize];
            List <OptionalObjective> setsToOr    = new();

            for (int rowIdx = 0; rowIdx < _squareSize; ++rowIdx)
            {
                for (int i = 0; i < _squareSize; ++i)
                {
                    toConstrain[i] = new Coordinate(startCoord.Row + rowIdx, startCoord.Column + i);
                }
                if (!_TryConstrainToPossibleSets(toConstrain, puzzle, graph, setsToOr))
                {
                    return(false);
                }
                _ConstrainAndClearOverlappingSets(graph, setsToOr);
            }
            for (int colIdx = 0; colIdx < _squareSize; ++colIdx)
            {
                for (int i = 0; i < _squareSize; ++i)
                {
                    toConstrain[i] = new Coordinate(startCoord.Row + i, startCoord.Column + colIdx);
                }
                if (!_TryConstrainToPossibleSets(toConstrain, puzzle, graph, setsToOr))
                {
                    return(false);
                }
                _ConstrainAndClearOverlappingSets(graph, setsToOr);
            }
            if (!_includeDiagonals)
            {
                return(true);
            }
            int lastColumn = startCoord.Column + _squareSize - 1;

            for (int offset = 0; offset < _squareSize; ++offset)
            {
                toConstrain[offset] = new Coordinate(startCoord.Row + offset, lastColumn - offset);
            }
            if (!_TryConstrainToPossibleSets(toConstrain, puzzle, graph, setsToOr))
            {
                return(false);
            }
            _ConstrainAndClearOverlappingSets(graph, setsToOr);
            for (int offset = 0; offset < _squareSize; ++offset)
            {
                toConstrain[offset] = new Coordinate(startCoord.Row + offset, startCoord.Column + offset);
            }
            if (!_TryConstrainToPossibleSets(toConstrain, puzzle, graph, setsToOr))
            {
                return(false);
            }
            _ConstrainAndClearOverlappingSets(graph, setsToOr);
            return(true);
        }
Beispiel #18
0
        private static void _ConstrainBackwardDiagonal(IReadOnlyPuzzle puzzle, ExactCoverMatrix matrix)
        {
            Span <Coordinate> Coordinates = stackalloc Coordinate[puzzle.Size];

            for (int row = 0, col = 0; row < puzzle.Size; row++, col++)
            {
                Coordinates[row] = new Coordinate(row, col);
            }
            ConstraintUtil.ImplementUniquenessConstraintForSquares(puzzle, Coordinates, matrix);
        }
Beispiel #19
0
 public static bool TryCheckForSetValues(
     IReadOnlyPuzzle puzzle,
     ExactCoverGraph graph,
     ReadOnlySpan <Coordinate> squareCoordinates,
     Span <bool> isValueIndexPresentInSquares)
 {
     isValueIndexPresentInSquares.Clear();
     foreach (Coordinate coordinate in squareCoordinates)
     {
         int?square = puzzle[in coordinate];
        private static bool _TryConstrainBackwardDiagonal(IReadOnlyPuzzle puzzle, ExactCoverGraph graph)
        {
            Span <Coordinate> Coordinates = stackalloc Coordinate[puzzle.Size];

            for (int row = 0, col = 0; row < puzzle.Size; row++, col++)
            {
                Coordinates[row] = new Coordinate(row, col);
            }
            return(ConstraintUtil.TryImplementUniquenessConstraintForSquares(puzzle, Coordinates, graph));
        }
 /// <inheritdoc/>
 public override bool TryInit(IReadOnlyPuzzle puzzle, BitVector uniquePossibleValues)
 {
     _boxSize = Boxes.IntSquareRoot(puzzle.Size);
     _puzzle  = puzzle;
     if (!base.TryInit(puzzle, uniquePossibleValues))
     {
         _puzzle = null;
         return(false);
     }
     return(true);
 }
Beispiel #22
0
        public PossibleValues(IReadOnlyPuzzle puzzle)
        {
            _possibleValues = new BitVector[puzzle.Size, puzzle.Size];
            var allPossible = BitVector.CreateWithSize(puzzle.Size + 1);

            allPossible.UnsetBit(0);
            AllPossible = allPossible;
            foreach (Coordinate c in puzzle.GetUnsetCoords())
            {
                _possibleValues[c.Row, c.Column] = AllPossible;
            }
        }
Beispiel #23
0
        internal static void AssertMagicSquaresSatisfied(
            IReadOnlyPuzzle puzzle, int expectedSum, bool verifyDiagonals)
        {
            int boxSize = Boxes.IntSquareRoot(puzzle.Size);
            var boxes   = new Box[puzzle.Size];

            for (int boxIdx = 0; boxIdx < boxes.Length; ++boxIdx)
            {
                boxes[boxIdx] = new Box(Boxes.GetStartingBoxCoordinate(boxIdx, boxSize), boxSize);
            }
            AssertMagicSquaresSatisfied(puzzle, boxes, expectedSum, verifyDiagonals);
        }
        /// <inheritdoc/>
        public void Constrain(IReadOnlyPuzzle puzzle, ExactCoverMatrix matrix)
        {
            Span <Coordinate> columnCoordinates = stackalloc Coordinate[puzzle.Size];

            for (int column = 0; column < puzzle.Size; column++)
            {
                for (int row = 0; row < puzzle.Size; row++)
                {
                    columnCoordinates[row] = new Coordinate(row, column);
                }
                ConstraintUtil.ImplementUniquenessConstraintForSquares(puzzle, columnCoordinates, matrix);
            }
        }
 private UniqueInRowHeuristic(
     UniqueInRowHeuristic existing,
     IReadOnlyPuzzle puzzle,
     PossibleValues possibleValues,
     IMissingRowValuesTracker rule)
 {
     _puzzle                 = puzzle;
     _possibleValues         = possibleValues;
     _rowTracker             = rule;
     _possiblesToCheckInRow  = (BitVector[])existing._possiblesToCheckInRow.Clone();
     _previousPossiblesStack = new Stack <IReadOnlyDictionary <Coordinate, BitVector> >(
         existing._previousPossiblesStack);
 }
Beispiel #26
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)
Beispiel #27
0
        private bool _TryConstrainToPossibleSets(
            ReadOnlySpan <Coordinate> toConstrain,
            IReadOnlyPuzzle puzzle,
            ExactCoverGraph graph,
            List <OptionalObjective> setsToOr)
        {
            Possibility?[]?[] unsetSquares = new Possibility[toConstrain.Length][];
            BitVector         alreadySet   = new BitVector();
            int numUnset = 0;

            for (int i = 0; i < toConstrain.Length; ++i)
            {
                var square = puzzle[in toConstrain[i]];
 public DynamicRuleKeeper(IReadOnlyPuzzle puzzle, PossibleValues possibleValues, IReadOnlyList <ISudokuRule> rules)
 {
     _puzzle         = puzzle;
     _possibleValues = possibleValues;
     _coordTracker   = new CoordinateTracker(puzzle.Size);
     _rules          = rules;
     foreach (Coordinate c in _puzzle.GetUnsetCoords())
     {
         foreach (ISudokuRule?r in _rules)
         {
             _possibleValues.Intersect(in c, r.GetPossibleValues(in c));
         }
         if (_possibleValues[in c].IsEmpty())
 private StandardHeuristic(
     StandardHeuristic existing,
     IReadOnlyPuzzle puzzle,
     PossibleValues possibleValues,
     IReadOnlyList <ISudokuRule> rules)
 {
     _rowHeuristic = (UniqueInRowHeuristic)existing._rowHeuristic.CopyWithNewReferences(
         puzzle, possibleValues, rules);
     _columnHeuristic = (UniqueInColumnHeuristic)existing._columnHeuristic
                        .CopyWithNewReferences(puzzle, possibleValues, rules);
     _boxHeuristic = (UniqueInBoxHeuristic)existing._boxHeuristic.CopyWithNewReferences(
         puzzle, possibleValues, rules);
     _numHeuristicsRan = new Stack <int>(existing._numHeuristicsRan);
 }
Beispiel #30
0
 /// <inheritdoc />
 public bool TryConstrain(IReadOnlyPuzzle puzzle, ExactCoverGraph graph)
 {
     if (!_IsCompatible(puzzle))
     {
         return(false);
     }
     foreach (Box box in _magicSquares)
     {
         if (!_TryConstrainBox(box, puzzle, graph))
         {
             return(false);
         }
     }
     return(true);
 }