示例#1
0
        public void TrySelectAndDeselectPossibility_WithMultipleRequired_Works()
        {
            var puzzle        = new Puzzle(4);
            var matrix        = ExactCoverGraph.Create(puzzle);
            var possibilities = new FakePossibility[] {
                new FakePossibility(),
                new FakePossibility(),
            };
            var        firstSelected     = possibilities[0];
            var        secondSelected    = possibilities[1];
            var        concreteObjective = Objective.CreateFullyConnected(matrix, possibilities, 2);
            IObjective objective         = concreteObjective;

            Assert.True(objective.TrySelectPossibility(firstSelected.AttachedObjectives.First()));
            Assert.NotEqual(NodeState.SELECTED, concreteObjective.State);
            Assert.Equal(1, concreteObjective.CountUnknown);
            Assert.Single(objective.GetUnknownDirectPossibilities(), secondSelected);
            Assert.Contains(concreteObjective, matrix.GetUnsatisfiedRequiredObjectivesWithConcretePossibilities());

            Assert.True(objective.TrySelectPossibility(secondSelected.AttachedObjectives.First()));
            Assert.Equal(NodeState.SELECTED, concreteObjective.State);
            Assert.Equal(0, concreteObjective.CountUnknown);
            Assert.True(!matrix.GetUnsatisfiedRequiredObjectivesWithConcretePossibilities().Contains(concreteObjective) ||
                        matrix.GetUnsatisfiedRequiredObjectivesWithConcretePossibilities().Count() == 1);

            objective.DeselectPossibility(secondSelected.AttachedObjectives.First());
            Assert.NotEqual(NodeState.SELECTED, concreteObjective.State);
            Assert.Equal(1, concreteObjective.CountUnknown);
            Assert.Single(objective.GetUnknownDirectPossibilities(), secondSelected);
            Assert.Contains(concreteObjective, matrix.GetUnsatisfiedRequiredObjectivesWithConcretePossibilities());

            objective.DeselectPossibility(firstSelected.AttachedObjectives.First());
            Assert.Equal(2, concreteObjective.CountUnknown);
        }
示例#2
0
        public void TrySelectAndDeselectPossibility_WithOneRequired_Works()
        {
            var puzzle        = new Puzzle(4);
            var matrix        = ExactCoverGraph.Create(puzzle);
            var possibilities = new FakePossibility[] {
                new FakePossibility(),
                new FakePossibility(),
            };
            var selectedPossibility = possibilities[0];
            var droppedPossibility  = possibilities[1];
            var objective           = Objective.CreateFullyConnected(matrix, possibilities, 1);

            Assert.NotEqual(NodeState.SELECTED, objective.State);
            ((IObjective)objective).TrySelectPossibility(selectedPossibility.AttachedObjectives.First());
            Assert.Equal(NodeState.SELECTED, objective.State);
            Assert.DoesNotContain(objective, matrix.GetUnsatisfiedRequiredObjectives());
            Assert.Empty(((IObjective)objective).GetUnknownDirectPossibilities());
            Assert.Empty(selectedPossibility.DroppedFromObjectives);
            Assert.Single(droppedPossibility.DroppedFromObjectives);

            ((IObjective)objective).DeselectPossibility(selectedPossibility.AttachedObjectives.First());
            Assert.NotEqual(NodeState.SELECTED, objective.State);
            Assert.Contains(objective, matrix.GetUnsatisfiedRequiredObjectivesWithConcretePossibilities());
            Assert.Empty(selectedPossibility.DroppedFromObjectives);
            Assert.Empty(droppedPossibility.DroppedFromObjectives);
            Assert.Contains(selectedPossibility, ((IObjective)objective).GetUnknownDirectPossibilities());
            Assert.Contains(droppedPossibility, ((IObjective)objective).GetUnknownDirectPossibilities());
        }
示例#3
0
        public void TryDropAndReturnPossibility_Succeeds()
        {
            var puzzle        = new Puzzle(4);
            var matrix        = ExactCoverGraph.Create(puzzle);
            var possibilities = new FakePossibility[] {
                new FakePossibility(),
                new FakePossibility(),
                new FakePossibility(),
            };
            var        toDrop            = possibilities[0];
            var        concreteObjective = Objective.CreateFullyConnected(matrix, possibilities, 2);
            IObjective objective         = concreteObjective;

            Assert.True(objective.TryDropPossibility(toDrop.AttachedObjectives.First()));
            Assert.Equal(2, concreteObjective.CountUnknown);
            Assert.Equal(2, objective.GetUnknownDirectPossibilities().Count());
            Assert.Contains(possibilities[1], objective.GetUnknownDirectPossibilities());
            Assert.Contains(possibilities[2], objective.GetUnknownDirectPossibilities());
            Assert.Empty(toDrop.DroppedFromObjectives);

            objective.ReturnPossibility(toDrop.AttachedObjectives.First());
            Assert.Equal(3, concreteObjective.CountUnknown);
            Assert.Equal(3, objective.GetUnknownDirectPossibilities().Count());
            Assert.Contains(toDrop, objective.GetUnknownDirectPossibilities());
            Assert.Contains(possibilities[1], objective.GetUnknownDirectPossibilities());
            Assert.Contains(possibilities[2], objective.GetUnknownDirectPossibilities());
        }
示例#4
0
        public void Create_ConfiguresSquareObjectives()
        {
            var puzzle = new Puzzle(4);
            var graph  = ExactCoverGraph.Create(puzzle);

            var objectives = graph.GetUnsatisfiedRequiredObjectives();

            Assert.Equal(puzzle.Size * puzzle.Size, objectives.Count());

            var seenCoordinates    = new HashSet <Coordinate>();
            var possibilityIndices = new HashSet <int>()
            {
                0, 1, 2, 3
            };

            Assert.All(objectives,
                       concreteObjective =>
            {
                IObjective objective = concreteObjective;
                var possibilities    = objective.GetUnknownDirectPossibilities().Cast <Possibility>().ToArray();
                // Assert that each square links every possibility at that coordinate.
                Assert.Equal(puzzle.Size, possibilities.Length);
                Assert.Equal(possibilityIndices, new HashSet <int>(possibilities.Select(p => p.Index)));
                var firstCoord = possibilities.First().Coordinate;
                Assert.All(possibilities,
                           p =>
                {
                    Assert.Equal(firstCoord, p.Coordinate);
                    Assert.Equal(NodeState.UNKNOWN, p.State);
                });
                // Assert an objective is made for each square.
                Assert.DoesNotContain(firstCoord, seenCoordinates);
                seenCoordinates.Add(firstCoord);
            });
        }
示例#5
0
        public void CreateFullyConnected_ConnectsCorrectly(int numPossibilities, int numRequired, bool asConcrete)
        {
            int size          = 4;
            var puzzle        = new Puzzle(size);
            var matrix        = ExactCoverGraph.Create(puzzle);
            var possibilities = Possibilities.CreatePossibilities(new Coordinate(), numPossibilities);

            Objective objective;

            if (asConcrete)
            {
                objective = Objective.CreateFullyConnected(matrix,
                                                           new ReadOnlySpan <Possibility>(possibilities),
                                                           numRequired);
            }
            else
            {
                objective = Objective.CreateFullyConnected(matrix,
                                                           new ReadOnlySpan <IPossibility>(possibilities),
                                                           numRequired);
            }

            Assert.True(objective.AllUnknownPossibilitiesAreConcrete);
            Assert.True(((IObjective)objective).IsRequired);
            Assert.Equal(numPossibilities == numRequired, objective.AllUnknownPossibilitiesAreRequired);
            Assert.NotEqual(NodeState.SELECTED, objective.State);
            Assert.Equal(possibilities.Length, objective.CountUnknown);
            Assert.Equal(numRequired, objective.TotalCountToSatisfy);
            Assert.All(possibilities,
                       p => Assert.Contains(p, ((IObjective)objective).GetUnknownDirectPossibilities()));
            Assert.All(((IObjective)objective).GetUnknownDirectPossibilities(),
                       p => Assert.Contains(p, possibilities));
            Assert.Contains(objective, matrix.GetUnsatisfiedRequiredObjectivesWithConcretePossibilities());
        }
示例#6
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);
        }
示例#7
0
        public void TryConstrain_ConstrainsCorrectly()
        {
            var puzzle = new Puzzle(new int?[][] {
                new int?[] { null, null, 9, null, null, null, null, null, null },
                new int?[] { null, null, null, null, null, null, null, null, null },
                new int?[] { null, 3, 5, null, null, null, null, null, null },
                new int?[] { null, null, null, null, null, null, null, null, null },
                new int?[] { null, null, null, null, null, null, null, null, null },
                new int?[] { null, null, null, null, null, null, null, null, null },
                new int?[] { null, null, null, null, null, null, null, null, null },
                new int?[] { null, null, null, null, null, null, null, null, null },
                new int?[] { null, null, null, null, null, null, null, null, null },
            });
            var boxesToConstrain = new Box[] {
                new Box(new Coordinate(0, 0), 3),
            };
            var constraint = new MagicSquaresConstraint(
                _CreateStandardPossibleValues(9),
                boxesToConstrain, includeDiagonals: false);
            var graph = ExactCoverGraph.Create(puzzle);

            Assert.True(constraint.TryConstrain(puzzle, graph));

            _AssertPossibleValuesAtSquare(new(0, 0), new int[] { 1, 2, 4, 5 }, graph);
            _AssertPossibleValuesAtSquare(new(0, 1), new int[] { 4, 5 }, graph);
            _AssertPossibleValuesAtSquare(new(1, 0), new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, graph);
            _AssertPossibleValuesAtSquare(new(1, 1), new int[] { 4, 5, 7, 8 }, graph);
            _AssertPossibleValuesAtSquare(new(1, 2), new int[] { 1 }, graph);
            _AssertPossibleValuesAtSquare(new(2, 0), new int[] { 7 }, graph);
            _AssertPossibleValuesAtSquare(new(3, 0), new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, graph);
        }
示例#8
0
        public void TryConstrain_WithUniqueValuesInDiagonals_Succeeds()
        {
            var puzzle = new Puzzle(new int?[][] {
                new int?[] { 1, null, null, null },
                new int?[] { null, null, 2, null },
                new int?[] { null, 3, 3, null },
                new int?[] { 4, null, null, null },
            });
            var graph      = ExactCoverGraph.Create(puzzle);
            var constraint = new DiagonalUniquenessConstraint();

            Assert.True(constraint.TryConstrain(puzzle, graph));

            ExactCoverGraphs.AssertPossibleValuesAtSquare(new(0, 1), new int[] { 1, 2, 3, 4 }, graph);
            ExactCoverGraphs.AssertPossibleValuesAtSquare(new(0, 2), new int[] { 1, 2, 3, 4 }, graph);
            ExactCoverGraphs.AssertPossibleValuesAtSquare(new(1, 0), new int[] { 1, 2, 3, 4 }, graph);
            ExactCoverGraphs.AssertPossibleValuesAtSquare(new(1, 3), new int[] { 1, 2, 3, 4 }, graph);
            ExactCoverGraphs.AssertPossibleValuesAtSquare(new(2, 0), new int[] { 1, 2, 3, 4 }, graph);
            ExactCoverGraphs.AssertPossibleValuesAtSquare(new(2, 3), new int[] { 1, 2, 3, 4 }, graph);
            ExactCoverGraphs.AssertPossibleValuesAtSquare(new(3, 1), new int[] { 1, 2, 3, 4 }, graph);
            ExactCoverGraphs.AssertPossibleValuesAtSquare(new(3, 2), new int[] { 1, 2, 3, 4 }, graph);
            ExactCoverGraphs.AssertPossibleValuesAtSquare(new(1, 1), new int[] { 2, 4 }, graph);
            ExactCoverGraphs.AssertPossibleValuesAtSquare(new(3, 3), new int[] { 2, 4 }, graph);
            ExactCoverGraphs.AssertPossibleValuesAtSquare(new(0, 3), new int[] { 1 }, graph);
            ExactCoverGraphs.AssertNoPossibleValuesAtSquare(new(0, 0), graph);
            ExactCoverGraphs.AssertNoPossibleValuesAtSquare(new(2, 2), graph);
            ExactCoverGraphs.AssertNoPossibleValuesAtSquare(new(1, 2), graph);
            ExactCoverGraphs.AssertNoPossibleValuesAtSquare(new(2, 1), graph);
            ExactCoverGraphs.AssertNoPossibleValuesAtSquare(new(3, 0), graph);
        }
示例#9
0
 public void CascadingDropUpDownUpWithDropAtMidpoint()
 {
     var puzzle          = new Puzzle(4);
     var matrix          = ExactCoverGraph.Create(puzzle);
     var possibilities   = Possibilities.CreatePossibilities(new Coordinate(), 3);
     var required        = Objective.CreateFullyConnected(matrix, new ReadOnlySpan <Possibility>(possibilities), 1);
     var fakePossibility = new FakePossibility();
     var optional        = OptionalObjective.CreateWithPossibilities(
         possibilities[1..3], 2);
示例#10
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);
        }
示例#11
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));
        }
示例#13
0
        public void GetPossibilitiesOnRow_ReturnsExpectedSquares()
        {
            var puzzle = new Puzzle(4);
            var graph  = ExactCoverGraph.Create(puzzle);

            int rowIndex = 1;
            var row      = graph.GetPossibilitiesOnRow(rowIndex);

            Assert.Equal(4, row.Length);
            Assert.Equal(new Coordinate(rowIndex, 0), row[0] ![0] !.Coordinate);
示例#14
0
        public void TryConstrain_IncludingDiagonals_ConstrainsCorrectly()
        {
            var puzzle = new Puzzle(new int?[][] {
                new int?[] { null, null, null, null, null, null, null, null, null },
                new int?[] { null, null, null, null, null, null, null, null, null },
                new int?[] { null, null, null, null, null, null, null, null, null },
                new int?[] { null, null, null, null, null, 6, null, null, null },
                new int?[] { null, null, null, null, null, null, null, null, null },
                new int?[] { null, null, null, null, 3, 8, null, null, null },
                new int?[] { null, null, null, null, null, null, null, null, null },
                new int?[] { null, null, null, null, null, null, null, null, null },
                new int?[] { null, null, null, null, null, null, null, null, null },
            });
            var boxesToConstrain = new Box[] {
                new Box(new Coordinate(3, 3), 3),
            };
            var constraint = new MagicSquaresConstraint(
                _CreateStandardPossibleValues(9),
                boxesToConstrain, includeDiagonals: true);
            var graph = ExactCoverGraph.Create(puzzle);

            Assert.True(constraint.TryConstrain(puzzle, graph));

            // rows: 18, 27, 45
            // rows: all
            // rows: 4

            // cols: all
            // cols: 84 75
            // cols: 1

            // 124578    | 4578 | x
            // 123456789 | 4578 | 1
            // 4         | x    | x

            // diagonals \: 16 25 34 -> Has to be 25 when combining top left and middle possibles.
            // diagonals /: 18 27 45 -> Has to be 45 when combining bottom left and middle possibles.

            // 25        | 4578 | x
            // 123456789 | 5    | 1
            // 4         | x    | x

            // Note this doesn't filter further because failed optional objectives can't drop
            // possiblities.

            _AssertPossibleValuesAtSquare(new(3, 3), new int[] { 2, 5 }, graph);
            _AssertPossibleValuesAtSquare(new(3, 4), new int[] { 4, 5, 7, 8 }, graph);
            _AssertPossibleValuesAtSquare(new(4, 3), new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, graph);
            _AssertPossibleValuesAtSquare(new(4, 4), new int[] { 5 }, graph);
            _AssertPossibleValuesAtSquare(new(4, 5), new int[] { 1 }, graph);
            _AssertPossibleValuesAtSquare(new(5, 3), new int[] { 4 }, graph);
            _AssertPossibleValuesAtSquare(new(6, 3), new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, graph);
        }
示例#15
0
        public void TryConstrain_WithNonUniqueValuesInDiagonals_Fails()
        {
            var puzzle = new Puzzle(new int?[][] {
                new int?[] { 1, null, null, null },
                new int?[] { null, null, null, null },
                new int?[] { null, 3, 1, null },
                new int?[] { null, null, null, null },
            });
            var graph      = ExactCoverGraph.Create(puzzle);
            var constraint = new DiagonalUniquenessConstraint();

            Assert.False(constraint.TryConstrain(puzzle, graph));
        }
示例#16
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 void Constrain_ReturnsExpectedConstraints()
        {
            int size = 4;

            int[] possibleValues   = new int[] { 1, 3, 5, 7 };
            var   puzzle           = new Puzzle(size);
            var   matrix           = ExactCoverGraph.Create(puzzle);
            var   squareObjectives = new HashSet <Objective>(matrix.GetUnsatisfiedRequiredObjectivesWithConcretePossibilities());

            Assert.True(new ColumnUniquenessConstraint().TryConstrain(puzzle, matrix));

            Assert.Equal(
                size * possibleValues.Length + squareObjectives.Count,
                matrix.GetUnsatisfiedRequiredObjectivesWithConcretePossibilities().Count());
            Dictionary <int, HashSet <int> > columnsToValues = new();

            for (int i = 0; i < size; ++i)
            {
                columnsToValues[i] = new HashSet <int>();
            }
            var expectedRows = new int[] { 0, 1, 2, 3 };

            Assert.All(matrix.GetUnsatisfiedRequiredObjectivesWithConcretePossibilities(),
                       concreteObjective =>
            {
                if (squareObjectives.Contains(concreteObjective))
                {
                    return;
                }
                IObjective objective = concreteObjective;
                var possibilities    = objective.GetUnknownDirectPossibilities().Cast <Possibility>().ToArray();
                int column           = possibilities[0].Coordinate.Column;
                int value            = possibilities[0].Index;
                Assert.DoesNotContain(value, columnsToValues[column]);
                columnsToValues[column].Add(value);
                var expectedCoordinates = expectedRows.Select(row => new Coordinate(row, column)).ToArray();
                Assert.Equal(expectedCoordinates.Length, possibilities.Length);
                Assert.All(possibilities, p =>
                {
                    Assert.Contains(p.Coordinate, expectedCoordinates);
                    Assert.Equal(value, p.Index);
                });
                Assert.All(expectedCoordinates, c => Assert.NotNull(possibilities.SingleOrDefault(p => p.Coordinate == c)));
            });
            Assert.All(
                columnsToValues.Values,
                values => Assert.Equal(new HashSet <int> {
                0, 1, 2, 3
            }, values));
        }
示例#18
0
        public void Constrain_GroupsConstraintsAsExpected()
        {
            int size    = 4;
            int boxSize = 2;

            int[] possibleValues   = new int[] { 1, 3, 5, 7 };
            var   puzzle           = new Puzzle(size);
            var   matrix           = ExactCoverGraph.Create(puzzle);
            var   squareObjectives = new HashSet <Objective>(matrix.GetUnsatisfiedRequiredObjectivesWithConcretePossibilities());

            Assert.True(new BoxUniquenessConstraint().TryConstrain(puzzle, matrix));

            Assert.Equal(
                size * possibleValues.Length + squareObjectives.Count,
                matrix.GetUnsatisfiedRequiredObjectivesWithConcretePossibilities().Count());
            Dictionary <int, HashSet <int> > boxIndicesToValues = new();

            for (int i = 0; i < size; ++i)
            {
                boxIndicesToValues[i] = new HashSet <int>();
            }
            Assert.All(matrix.GetUnsatisfiedRequiredObjectivesWithConcretePossibilities(),
                       concreteObjective =>
            {
                if (squareObjectives.Contains(concreteObjective))
                {
                    return;
                }
                IObjective objective = concreteObjective;
                var possibilities    = objective.GetUnknownDirectPossibilities().Cast <Possibility>().ToArray();
                int boxIndex         = Boxes.CalculateBoxIndex(possibilities[0].Coordinate, boxSize);
                int value            = possibilities[0].Index;
                Assert.DoesNotContain(value, boxIndicesToValues[boxIndex]);
                boxIndicesToValues[boxIndex].Add(value);
                var boxCoordinates = Boxes.YieldUnsetCoordsForBox(boxIndex, boxSize, puzzle).ToArray();
                Assert.Equal(boxCoordinates.Length, possibilities.Length);
                Assert.All(possibilities, p =>
                {
                    Assert.Contains(p.Coordinate, boxCoordinates);
                    Assert.Equal(value, p.Index);
                });
                Assert.All(boxCoordinates, c => Assert.NotNull(possibilities.SingleOrDefault(p => p.Coordinate == c)));
            });
            Assert.All(
                boxIndicesToValues.Values,
                values => Assert.Equal(new HashSet <int> {
                0, 1, 2, 3
            }, values));
        }
示例#19
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);
 }
示例#20
0
 /// <inheritdoc/>
 public bool TryConstrain(IReadOnlyPuzzle puzzle, ExactCoverGraph graph)
 {
     if (!Boxes.TryIntSquareRoot(puzzle.Size, out int boxSize))
     {
         return(false);
     }
     for (int box = 0; box < puzzle.Size; box++)
     {
         if (!_TryAppendRequirementsInBox(box, boxSize, puzzle, graph))
         {
             return(false);
         }
     }
     return(true);
 }
示例#21
0
        public void GetAllPossibilitiesAt_ForUnsetCoordinate_ReturnsExpectedPossibilities()
        {
            var             puzzle = new Puzzle(4);
            ExactCoverGraph graph  = ExactCoverGraph.Create(puzzle);

            var possibilities = graph.GetAllPossibilitiesAt(new Coordinate());

            Assert.NotNull(possibilities);
            Assert.Equal(puzzle.Size, possibilities !.Length);
            for (int i = 0; i < puzzle.Size; ++i)
            {
                Assert.NotNull(possibilities[i]);
                Assert.Equal(i, possibilities[i] !.Index);
            }
        }
示例#22
0
        public void CreateFullyConnected_WithOptionalObjectives_ConnectsCorrectly()
        {
            var puzzle             = new Puzzle(4);
            var matrix             = ExactCoverGraph.Create(puzzle);
            var optionalObjectives = new OptionalObjective[] {
                OptionalObjective.CreateWithPossibilities(Possibilities.CreatePossibilities(new Coordinate(), 2), 1),
                OptionalObjective.CreateWithPossibilities(Possibilities.CreatePossibilities(new Coordinate(), 2), 1),
            };
            var        concreteObjective = Objective.CreateFullyConnected(matrix, optionalObjectives, 1);
            IObjective objective         = concreteObjective;

            Assert.Equal(
                new HashSet <IPossibility>(optionalObjectives),
                new HashSet <IPossibility>(objective.GetUnknownDirectPossibilities()));
        }
示例#23
0
        internal static void AssertNoPossibleValuesAtSquare(Coordinate coord, ExactCoverGraph graph)
        {
            var square = graph.GetAllPossibilitiesAt(coord);

            if (square is not null)
            {
                for (int valueIndex = 0; valueIndex < square.Length; ++valueIndex)
                {
                    var possibleValue = square[valueIndex];
                    if (possibleValue is not null)
                    {
                        Assert.Equal(NodeState.DROPPED, possibleValue.State);
                    }
                }
            }
        }
示例#24
0
        /// <inheritdoc/>
        public bool TryConstrain(IReadOnlyPuzzle puzzle, ExactCoverGraph graph)
        {
            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);
                }
                if (!ConstraintUtil.TryImplementUniquenessConstraintForSquares(puzzle, columnCoordinates, graph))
                {
                    return(false);
                }
            }
            return(true);
        }
示例#25
0
        public void AllUnknownPossibilitiesAreConcrete_UpdatesWhenPossibilitiesChange()
        {
            var puzzle          = new Puzzle(4);
            var matrix          = ExactCoverGraph.Create(puzzle);
            var fakePossibility = new FakePossibility(isConcrete: false);
            var possibilities   = new IPossibility[] {
                new Possibility(new Coordinate(), 0),
                fakePossibility,
            };

            var objective = Objective.CreateFullyConnected(matrix, possibilities, 1);

            Assert.Single(fakePossibility.AttachedObjectives);
            Assert.False(objective.AllUnknownPossibilitiesAreConcrete);

            Assert.True(((IObjective)objective).TryDropPossibility(fakePossibility.AttachedObjectives.First()));
            Assert.True(objective.AllUnknownPossibilitiesAreConcrete);
        }
示例#26
0
        public void TrySelectAndDeselect_WhenSharedByOpposingObjectives_Fails()
        {
            var puzzle = new Puzzle(4);
            var matrix = ExactCoverGraph.Create(puzzle);
            var concretePossibility = new Possibility(new(), 1);
            var possibilities       = new IPossibility[] { concretePossibility };
            var parentA             = OptionalObjective.CreateWithPossibilities(possibilities, 1);
            var parentB             = OptionalObjective.CreateWithPossibilities(possibilities.Append(new FakePossibility()).ToArray(), 1);
            var required            = Objective.CreateFullyConnected(
                matrix,
                new IPossibility[] { parentA, parentB },
                1);

            Assert.False(concretePossibility.TrySelect());
            Assert.Equal(NodeState.UNKNOWN, parentA.State);
            Assert.Equal(NodeState.UNKNOWN, parentB.State);
            Assert.NotEqual(NodeState.SELECTED, required.State);
        }
示例#27
0
        private static bool _TryAppendRequirementsInBox(
            int box, int boxSize, IReadOnlyPuzzle puzzle, ExactCoverGraph graph)
        {
            Coordinate startCoord = Boxes.GetStartingBoxCoordinate(box, boxSize);
            var        endCoord   = new Coordinate(
                startCoord.Row + boxSize, startCoord.Column + boxSize);
            Span <Coordinate> boxCoordinates = stackalloc Coordinate[puzzle.Size];
            int i = 0;

            for (int row = startCoord.Row; row < endCoord.Row; row++)
            {
                for (int col = startCoord.Column; col < endCoord.Column; col++)
                {
                    boxCoordinates[i++] = new Coordinate(row, col);
                }
            }
            return(ConstraintUtil.TryImplementUniquenessConstraintForSquares(puzzle, boxCoordinates, graph));
        }
示例#28
0
        public void TryDropPossibility_WhenRequired_Fails()
        {
            var puzzle        = new Puzzle(4);
            var matrix        = ExactCoverGraph.Create(puzzle);
            var possibilities = new FakePossibility[] {
                new FakePossibility(),
                new FakePossibility(),
                new FakePossibility(),
            };
            var        toDrop            = possibilities[0];
            var        concreteObjective = Objective.CreateFullyConnected(matrix, possibilities, 3);
            IObjective objective         = concreteObjective;

            Assert.False(objective.TryDropPossibility(toDrop.AttachedObjectives.First()));
            Assert.Equal(3, concreteObjective.CountUnknown);
            Assert.Equal(3, objective.GetUnknownDirectPossibilities().Count());
            Assert.Contains(toDrop, objective.GetUnknownDirectPossibilities());
            Assert.Contains(possibilities[1], objective.GetUnknownDirectPossibilities());
            Assert.Contains(possibilities[2], objective.GetUnknownDirectPossibilities());
        }
示例#29
0
        /// <inheritdoc/>
        public bool TryConstrain(IReadOnlyPuzzle puzzle, ExactCoverGraph graph)
        {
            Span <bool> isConstraintSatisfiedAtIndex =
                stackalloc bool[graph.AllPossibleValues.Length];

            for (int row = 0; row < puzzle.Size; row++)
            {
                ReadOnlySpan <Possibility?[]?> rowSquares = graph.GetPossibilitiesOnRow(row);
                isConstraintSatisfiedAtIndex.Clear();
                for (int col = 0; col < puzzle.Size; col++)
                {
                    int?puzzleValue = puzzle[row, col];
                    if (puzzleValue.HasValue)
                    {
                        int valueIndex = graph.ValuesToIndices[puzzleValue.Value];
                        if (isConstraintSatisfiedAtIndex[valueIndex])
                        {
                            return(false);
                        }
                        isConstraintSatisfiedAtIndex[valueIndex] = true;
                    }
                }
                for (int possibilityIndex = 0; possibilityIndex < isConstraintSatisfiedAtIndex.Length; possibilityIndex++)
                {
                    if (isConstraintSatisfiedAtIndex[possibilityIndex])
                    {
                        if (!ConstraintUtil.TryDropPossibilitiesAtIndex(rowSquares, possibilityIndex))
                        {
                            return(false);
                        }
                        continue;
                    }
                    if (!ConstraintUtil.TryAddObjectiveForPossibilityIndex(
                            rowSquares, possibilityIndex, graph, requiredCount: 1, objective: out _))
                    {
                        return(false);
                    }
                }
            }
            return(true);
        }
示例#30
0
        public void CascadingDropUpDownUp()
        {
            var puzzle          = new Puzzle(4);
            var matrix          = ExactCoverGraph.Create(puzzle);
            var possibilities   = Possibilities.CreatePossibilities(new Coordinate(), 2);
            var required        = Objective.CreateFullyConnected(matrix, new ReadOnlySpan <Possibility>(possibilities), 1);
            var fakePossibility = new FakePossibility();
            var optional        = OptionalObjective.CreateWithPossibilities(
                possibilities.Cast <IPossibility>().ToArray(), 2);
            var fakeLinkToOptional = Link.CreateConnectedLink(fakePossibility, optional);
            var separateRequired   = Objective.CreateFullyConnected(matrix, new IPossibility[] { optional }, 1);


            // Additionally try one where optional ends up dropped before the cascade somehow... maybe add one to possibilities and to optional's countToSatisfy.

            Assert.True(possibilities[0].TrySelect());
            Assert.Equal(NodeState.SELECTED, possibilities[0].State);
            Assert.Equal(NodeState.DROPPED, possibilities[1].State);
            Assert.Equal(NodeState.UNKNOWN, optional.State);
            Assert.Empty(fakePossibility.DroppedFromObjectives);
            Assert.Equal(NodeState.SELECTED, required.State);
            Assert.NotEqual(NodeState.SELECTED, separateRequired.State);

            Assert.True(((IObjective)optional).TrySelectPossibility(fakeLinkToOptional));
            Assert.Equal(NodeState.SELECTED, possibilities[0].State);
            Assert.Equal(NodeState.DROPPED, possibilities[1].State);
            Assert.Equal(NodeState.SELECTED, optional.State);
            Assert.Equal(NodeState.SELECTED, required.State);
            Assert.Equal(NodeState.SELECTED, separateRequired.State);

            ((IObjective)optional).DeselectPossibility(fakeLinkToOptional);
            Assert.Equal(NodeState.SELECTED, possibilities[0].State);
            Assert.Equal(NodeState.DROPPED, possibilities[1].State);
            Assert.Equal(NodeState.UNKNOWN, optional.State);
            Assert.Empty(fakePossibility.DroppedFromObjectives);
            Assert.Equal(NodeState.SELECTED, required.State);
            Assert.NotEqual(NodeState.SELECTED, separateRequired.State);

            Assert.False(((IObjective)optional).TryDropPossibility(fakeLinkToOptional));
        }