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()); }
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); }
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); }
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()); }
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); }); }
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()); }
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); }
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);
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);
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); }
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)); }
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)); }
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)); }
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())); }
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); } }
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); }
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); }
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()); }
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)); }
public void CreateFullyConnected_NeedsMoreThanPossible_Throws(bool asConcrete) { int size = 4; var puzzle = new Puzzle(size); var matrix = ExactCoverGraph.Create(puzzle); var possibilities = Possibilities.CreatePossibilities(new Coordinate(), 1); Assert.Single(possibilities); Assert.Throws <ArgumentException>( () => { if (asConcrete) { Objective.CreateFullyConnected(matrix, new ReadOnlySpan <Possibility>(possibilities), possibilities.Length + 1); } else { Objective.CreateFullyConnected(matrix, new ReadOnlySpan <IPossibility>(possibilities), possibilities.Length + 1); } }); }
public void TryConstrain_NotPossible_Fails() { var puzzle = new Puzzle(new int?[][] { new int?[] { null, null, 6, null, null, null, null, null, null }, new int?[] { 1, null, null, null, null, null, null, null, null }, new int?[] { null, 3, 8, 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.False(constraint.TryConstrain(puzzle, graph)); }
public void TrySelectPossibility_WithUndetachablePossibility_Fails() { var puzzle = new Puzzle(4); var matrix = ExactCoverGraph.Create(puzzle); var possibilities = new FakePossibility[] { new FakePossibility(), new FakePossibility(), new FakePossibility(), }; var toSelect = possibilities[0]; var undetachable = possibilities[2]; undetachable.CanBeDetached = false; var concreteObjective = Objective.CreateFullyConnected(matrix, possibilities, 1); IObjective objective = concreteObjective; Assert.False(objective.TrySelectPossibility(toSelect.AttachedObjectives.First())); Assert.Empty(possibilities[1].DroppedFromObjectives); Assert.Empty(undetachable.DroppedFromObjectives); Assert.Contains(objective, matrix.GetUnsatisfiedRequiredObjectivesWithConcretePossibilities()); Assert.Contains(toSelect, objective.GetUnknownDirectPossibilities()); Assert.Contains(possibilities[1], objective.GetUnknownDirectPossibilities()); Assert.Contains(undetachable, objective.GetUnknownDirectPossibilities()); }
public void TrySelectPossibility_CausesCascadingDrop_SelectsAndDeselectsCorrectly() { var puzzle = new Puzzle(4); var matrix = ExactCoverGraph.Create(puzzle); var fakePossibilities = new FakePossibility[] { new FakePossibility(), new FakePossibility(), }; var optional = OptionalObjective.CreateWithPossibilities(fakePossibilities, 1); var fakesOnParentToSelect = new FakePossibility[] { new FakePossibility(), new FakePossibility(), }; var parentToSelect = OptionalObjective.CreateWithPossibilities( fakesOnParentToSelect.Cast <IPossibility>().Prepend(optional).ToArray(), 2); var fakeOnParentToDrop = new FakePossibility(); var parentToDrop = OptionalObjective.CreateWithPossibilities( new IPossibility[] { fakeOnParentToDrop, optional, }, 2); var required = Objective.CreateFullyConnected( matrix, new IPossibility[] { parentToSelect, parentToDrop }, 1); IObjective objective = optional; ; // Select one fake on parentToSelect so that selecting this optional will satisfy the // objective. Assert.True(((IObjective)parentToSelect).TrySelectPossibility(fakesOnParentToSelect[0].AttachedObjectives.First())); Assert.True(objective.TrySelectPossibility(fakePossibilities[0].AttachedObjectives.First())); Assert.Equal(NodeState.SELECTED, optional.State); Assert.Equal(NodeState.SELECTED, parentToSelect.State); Assert.Empty(fakesOnParentToSelect[1].DroppedFromObjectives); Assert.Equal(NodeState.SELECTED, required.State); Assert.Equal(NodeState.DROPPED, parentToDrop.State); Assert.Empty(fakeOnParentToDrop.DroppedFromObjectives); objective.DeselectPossibility(fakePossibilities[0].AttachedObjectives.First()); Assert.Equal(NodeState.UNKNOWN, optional.State); Assert.Equal(NodeState.UNKNOWN, parentToSelect.State); Assert.Empty(fakesOnParentToSelect[1].DroppedFromObjectives); Assert.Equal(NodeState.UNKNOWN, required.State); Assert.Equal(NodeState.UNKNOWN, parentToDrop.State); Assert.Empty(fakeOnParentToDrop.DroppedFromObjectives); // Select a possibility on parentToDrop first. This should result in no change overall. Assert.True(((IObjective)parentToDrop).TrySelectPossibility(fakeOnParentToDrop.AttachedObjectives.First())); // Selecting the objective would satisfy both optional parents, which violates the // required objective. Assert.False(objective.TrySelectPossibility(fakePossibilities[0].AttachedObjectives.First())); // Deselect a possibility from parentToSelect so that we can now select parentToDrop. ((IObjective)parentToSelect).DeselectPossibility(fakesOnParentToSelect[0].AttachedObjectives.First()); Assert.True(objective.TrySelectPossibility(fakePossibilities[0].AttachedObjectives.First())); Assert.Equal(NodeState.SELECTED, optional.State); Assert.Equal(NodeState.DROPPED, parentToSelect.State); Assert.Empty(fakesOnParentToSelect[1].DroppedFromObjectives); Assert.Equal(NodeState.SELECTED, required.State); Assert.Equal(NodeState.SELECTED, parentToDrop.State); Assert.Empty(fakeOnParentToDrop.DroppedFromObjectives); }