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 TrySelectAndDeselectPossibility_Succeeds() { var fakePossibilities = new FakePossibility[] { new FakePossibility(), new FakePossibility(), }; var childOptional = OptionalObjective.CreateWithPossibilities( Possibilities.CreatePossibilities(new(), 2), 1); var optional = OptionalObjective.CreateWithPossibilities(fakePossibilities, 2); var linkToChildOptional = Link.CreateConnectedLink(childOptional, optional); var parent = new FakeObjective(isRequired: true); var linkToParent = Link.CreateConnectedLink(optional, parent); IPossibility possibility = optional; IObjective objective = optional; Assert.True(objective.TrySelectPossibility(fakePossibilities[0].AttachedObjectives.First())); Assert.Equal(NodeState.UNKNOWN, optional.State); Assert.Equal(NodeState.UNKNOWN, childOptional.State); Assert.All(((IObjective)childOptional).GetUnknownDirectPossibilities().Cast <Possibility>(), p => Assert.Equal(NodeState.UNKNOWN, p.State)); Assert.Empty(fakePossibilities[0].DroppedFromObjectives); Assert.Empty(fakePossibilities[1].DroppedFromObjectives); Assert.Empty(parent.SelectedPossibilities); Assert.True(objective.TrySelectPossibility(fakePossibilities[1].AttachedObjectives.First())); Assert.Equal(NodeState.SELECTED, optional.State); Assert.Equal(NodeState.UNKNOWN, childOptional.State); Assert.All(((IObjective)childOptional).GetUnknownDirectPossibilities().Cast <Possibility>(), p => Assert.Equal(NodeState.UNKNOWN, p.State)); Assert.Single(parent.SelectedPossibilities, linkToParent); Assert.Empty(fakePossibilities[0].DroppedFromObjectives); Assert.Empty(fakePossibilities[1].DroppedFromObjectives); objective.DeselectPossibility(fakePossibilities[1].AttachedObjectives.First()); Assert.Equal(NodeState.UNKNOWN, optional.State); Assert.Equal(NodeState.UNKNOWN, childOptional.State); Assert.All(((IObjective)childOptional).GetUnknownDirectPossibilities().Cast <Possibility>(), p => Assert.Equal(NodeState.UNKNOWN, p.State)); Assert.Empty(fakePossibilities[0].DroppedFromObjectives); Assert.Empty(fakePossibilities[1].DroppedFromObjectives); Assert.Empty(parent.SelectedPossibilities); objective.DeselectPossibility(fakePossibilities[0].AttachedObjectives.First()); Assert.Equal(NodeState.UNKNOWN, optional.State); Assert.Equal(NodeState.UNKNOWN, childOptional.State); Assert.All(((IObjective)childOptional).GetUnknownDirectPossibilities().Cast <Possibility>(), p => Assert.Equal(NodeState.UNKNOWN, p.State)); Assert.Empty(fakePossibilities[0].DroppedFromObjectives); Assert.Empty(fakePossibilities[1].DroppedFromObjectives); Assert.Empty(parent.SelectedPossibilities); }
public void TrySelectPossibility_WhenRejectedByParent_LeavesUnchanged() { var fakePossibilities = new FakePossibility[] { new FakePossibility(), new FakePossibility(), }; var childOptional = OptionalObjective.CreateWithPossibilities( Possibilities.CreatePossibilities(new(), 2), 1); var optional = OptionalObjective.CreateWithPossibilities(fakePossibilities, 1); var linkToChildOptional = Link.CreateConnectedLink(childOptional, optional); var parent = new FakeObjective(isRequired: true); parent.CanSelectPossibilities = false; var linkToParent = Link.CreateConnectedLink(optional, parent); IPossibility possibility = optional; IObjective objective = optional; Assert.False(objective.TrySelectPossibility(fakePossibilities[0].AttachedObjectives.First())); Assert.Equal(NodeState.UNKNOWN, optional.State); Assert.Equal(NodeState.UNKNOWN, childOptional.State); Assert.All(((IObjective)childOptional).GetUnknownDirectPossibilities().Cast <Possibility>(), p => Assert.Equal(NodeState.UNKNOWN, p.State)); Assert.Empty(fakePossibilities[0].DroppedFromObjectives); Assert.Empty(fakePossibilities[1].DroppedFromObjectives); Assert.Empty(parent.SelectedPossibilities); }
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); }