/// <summary> /// Add a <see cref="ConstraintHeader"/> connecting all the /// <see cref="PossibleValue"/>s at the given <paramref name="valueIndex"/> on the /// given <paramref name="squares"/>. Skips null squares, null possible values, and any /// possible values in a known state (i.e. dropped or selected). /// </summary> /// <param name="squares">The squares to add possible square values from.</param> /// <param name="valueIndex"> /// The value index of the possible value within the squares. /// </param> /// <param name="matrix">The matrix for the current puzzle being solved.</param> public static void AddConstraintHeadersForValueIndex( ReadOnlySpan <Square?> squares, int valueIndex, ExactCoverMatrix matrix) { var possibleSquares = new PossibleValue[squares.Length]; int numPossibleSquares = 0; for (int i = 0; i < squares.Length; i++) { Square?square = squares[i]; if (square is null) { continue; } PossibleValue?possibleSquare = square.GetPossibleValue(valueIndex); if (possibleSquare is null || possibleSquare.State != PossibleSquareState.UNKNOWN) { continue; } possibleSquares[numPossibleSquares++] = possibleSquare; } ConstraintHeader.CreateConnectedHeader( matrix, new ReadOnlySpan <PossibleValue>(possibleSquares, 0, numPossibleSquares)); }
public void CreateConnectedLink_WithExistingLinks_ConnectsCorrectly() { var puzzle = new Puzzle(4); var matrix = new ExactCoverMatrix(puzzle); var square = new Square(new Coordinate(0, 0), 2); var possibleSquare = new PossibleValue(square, 1); var constraintHeader = new ConstraintHeader(matrix); var firstLink = Link.CreateConnectedLink(possibleSquare, constraintHeader); var link = Link.CreateConnectedLink(possibleSquare, constraintHeader); Assert.Same(firstLink, link.Up); Assert.Same(firstLink, link.Down); Assert.Same(firstLink, link.Right); Assert.Same(firstLink, link.Left); Assert.Same(link, firstLink.Up); Assert.Same(link, firstLink.Down); Assert.Same(link, firstLink.Right); Assert.Same(link, firstLink.Left); Assert.Same(possibleSquare, link.PossibleSquare); Assert.Same(constraintHeader, link.Constraint); Assert.Equal(2, constraintHeader.Count); Assert.Same(firstLink, constraintHeader.FirstLink); Assert.Same(firstLink, possibleSquare.FirstLink); }
public void TrySelect_DropsConstraintConnectedSquareValues() { var puzzle = new Puzzle(4); var matrix = new ExactCoverMatrix(puzzle); new RowUniquenessConstraint().Constrain(puzzle, matrix); new ColumnUniquenessConstraint().Constrain(puzzle, matrix); int valueIndex = 0; PossibleValue possibleValue = matrix.GetSquare(new Coordinate(0, 1)).GetPossibleValue(valueIndex); Assert.True(possibleValue.TrySelect()); ConstraintHeader constraintA = possibleValue.FirstLink.Constraint; ConstraintHeader constraintB = possibleValue.FirstLink.Right.Constraint; Assert.Equal(4, constraintA.GetLinks().Count()); Assert.Equal(4, constraintB.GetLinks().Count()); foreach (Link link in constraintA.GetLinks()) { if (link.PossibleSquare == possibleValue) { continue; } Assert.Equal(PossibleSquareState.DROPPED, link.PossibleSquare.State); } foreach (Link link in constraintB.GetLinks()) { if (link.PossibleSquare == possibleValue) { continue; } Assert.Equal(PossibleSquareState.DROPPED, link.PossibleSquare.State); } }
public void Return_WithSatisfiedConstraint_UndropsTheRowAsExpected() { var puzzle = new Puzzle(4); var matrix = new ExactCoverMatrix(puzzle); new RowUniquenessConstraint().Constrain(puzzle, matrix); new ColumnUniquenessConstraint().Constrain(puzzle, matrix); int valueIndex = 0; Square square = matrix.GetSquare(new Coordinate(0, 0)); PossibleValue possibleValue = square.GetPossibleValue(valueIndex); Link linkA = possibleValue.FirstLink; Link linkB = linkA.Right; ConstraintHeader constraintA = linkA.Constraint; ConstraintHeader constraintB = linkB.Constraint; Assert.True(constraintB.TrySatisfyFrom(possibleValue.FirstLink.Right.Up)); possibleValue.Return(); Assert.Equal(4, square.NumPossibleValues); Assert.Equal(PossibleSquareState.UNKNOWN, possibleValue.State); Assert.Equal(4, constraintA.Count); Assert.Equal(4, constraintB.Count); Assert.Contains(linkA, constraintA.GetLinks()); Assert.Contains(linkB, constraintB.GetLinks()); }
public void TryDrop_LeavesUnchangedOnFailure() { var puzzle = new Puzzle(4); var matrix = new ExactCoverMatrix(puzzle); new RowUniquenessConstraint().Constrain(puzzle, matrix); new ColumnUniquenessConstraint().Constrain(puzzle, matrix); int valueIndex = 0; Assert.True(matrix.GetSquare(new Coordinate(0, 0)).GetPossibleValue(valueIndex).TryDrop()); Assert.True(matrix.GetSquare(new Coordinate(0, 1)).GetPossibleValue(valueIndex).TryDrop()); Assert.True(matrix.GetSquare(new Coordinate(0, 2)).GetPossibleValue(valueIndex).TryDrop()); Square square = matrix.GetSquare(new Coordinate(0, 3)); PossibleValue possibleValue = square.GetPossibleValue(valueIndex); Link linkA = possibleValue.FirstLink; Link linkB = linkA.Right; ConstraintHeader constraintA = linkA.Constraint; ConstraintHeader constraintB = linkB.Constraint; Assert.False(possibleValue.TryDrop()); Assert.Equal(4, square.NumPossibleValues); Assert.Equal(PossibleSquareState.UNKNOWN, possibleValue.State); Assert.Equal(1, constraintA.Count); Assert.Equal(4, constraintB.Count); Assert.Same(linkA, constraintA.FirstLink); Assert.Contains(linkB, constraintB.GetLinks()); }
internal static Link CreateConnectedLink(PossibleValue possibleSquare, ConstraintHeader header) { var squareLink = new Link(possibleSquare, header); possibleSquare.Attach(squareLink); header.Attach(squareLink); return(squareLink); }
public static void AssertPossibleValueIsOnConstraint( PossibleValue possibleValue, ConstraintHeader constraint) { Link link = constraint.FirstLink; do { if (link.PossibleSquare == possibleValue) { return; } link = link.Down; } while (link != constraint.FirstLink); Assert.True(false, "No matching possible square value found."); }
public void TrySelect_SelectsSquare() { var puzzle = new Puzzle(4); var matrix = new ExactCoverMatrix(puzzle); new RowUniquenessConstraint().Constrain(puzzle, matrix); new ColumnUniquenessConstraint().Constrain(puzzle, matrix); int valueIndex = 0; Square square = matrix.GetSquare(new Coordinate(0, 1)); PossibleValue possibleValue = square.GetPossibleValue(valueIndex); Assert.True(possibleValue.TrySelect()); Assert.Equal(PossibleSquareState.SELECTED, possibleValue.State); }
public void Deselect_WithSelectedValue_SetsStateAndSquareCountCorrectly() { var puzzle = new Puzzle(4); var matrix = new ExactCoverMatrix(puzzle); new RowUniquenessConstraint().Constrain(puzzle, matrix); new ColumnUniquenessConstraint().Constrain(puzzle, matrix); int valueIndex = 0; Square square = matrix.GetSquare(new Coordinate(0, 1)); PossibleValue possibleValue = square.GetPossibleValue(valueIndex); Assert.True(possibleValue.TrySelect()); possibleValue.Deselect(); Assert.Equal(PossibleSquareState.UNKNOWN, possibleValue.State); Assert.Equal(4, square.NumPossibleValues); }
public void Deselect_WithSelectedValue_ReturnsDroppedRows() { var puzzle = new Puzzle(4); var matrix = new ExactCoverMatrix(puzzle); new RowUniquenessConstraint().Constrain(puzzle, matrix); new ColumnUniquenessConstraint().Constrain(puzzle, matrix); int valueIndex = 0; Square square = matrix.GetSquare(new Coordinate(0, 1)); PossibleValue possibleValue = square.GetPossibleValue(valueIndex); Assert.True(possibleValue.TrySelect()); possibleValue.Deselect(); Link linkA = possibleValue.FirstLink; Link linkB = linkA.Right; ConstraintHeader constraintA = linkA.Constraint; ConstraintHeader constraintB = linkB.Constraint; Assert.False(constraintA.IsSatisfied); Assert.False(constraintB.IsSatisfied); Assert.Equal(4, constraintA.Count); Assert.Equal(4, constraintB.Count); foreach (Link link in constraintA.GetLinks()) { if (link != linkA) { Assert.Equal(PossibleSquareState.UNKNOWN, link.PossibleSquare.State); } } foreach (Link link in constraintB.GetLinks()) { if (link != linkB) { Assert.Equal(PossibleSquareState.UNKNOWN, link.PossibleSquare.State); } } }
public void TrySelect_SatisfiesConstraints() { var puzzle = new Puzzle(4); var matrix = new ExactCoverMatrix(puzzle); new RowUniquenessConstraint().Constrain(puzzle, matrix); new ColumnUniquenessConstraint().Constrain(puzzle, matrix); int valueIndex = 0; PossibleValue possibleValue = matrix.GetSquare(new Coordinate(0, 1)).GetPossibleValue(valueIndex); Assert.True(possibleValue.TrySelect()); ConstraintHeader constraintA = possibleValue.FirstLink.Constraint; ConstraintHeader constraintB = possibleValue.FirstLink.Right.Constraint; Assert.True(constraintA.IsSatisfied); Assert.True(constraintB.IsSatisfied); Assert.Equal(4, constraintA.Count); Assert.Equal(4, constraintB.Count); Assert.DoesNotContain(constraintA, matrix.GetUnsatisfiedConstraintHeaders()); Assert.DoesNotContain(constraintB, matrix.GetUnsatisfiedConstraintHeaders()); }
public void TryDrop_DropsOnSuccess() { var puzzle = new Puzzle(4); var matrix = new ExactCoverMatrix(puzzle); new RowUniquenessConstraint().Constrain(puzzle, matrix); new ColumnUniquenessConstraint().Constrain(puzzle, matrix); int valueIndex = 1; Square square = matrix.GetSquare(new Coordinate(1, 0)); PossibleValue possibleValue = square.GetPossibleValue(valueIndex); Link linkA = possibleValue.FirstLink; Link linkB = linkA.Right; ConstraintHeader constraintA = linkA.Constraint; ConstraintHeader constraintB = linkB.Constraint; Assert.True(possibleValue.TryDrop()); Assert.Equal(3, square.NumPossibleValues); Assert.Equal(PossibleSquareState.DROPPED, possibleValue.State); Assert.Equal(3, constraintA.Count); Assert.Equal(3, constraintB.Count); Assert.DoesNotContain(linkA, constraintA.GetLinks()); Assert.DoesNotContain(linkB, constraintB.GetLinks()); }
internal PipelineVariable(XmlNode node) { id = node.Attributes["id"].Value.Trim(); name = Banshee.Base.Localization.SelectSingleNode(node, "name").InnerText.Trim(); control_type = StringToControlType(node.SelectSingleNode("control-type").InnerText.Trim()); XmlAttribute enables_attr = node.Attributes["enables"]; if(enables_attr != null && enables_attr.Value != null) { string [] vars = enables_attr.Value.Split(','); if(vars != null && vars.Length > 0) { enables = new string[vars.Length]; for(int i = 0; i < vars.Length; i++) { enables[i] = vars[i].Trim(); } } } XmlAttribute disables_attr = node.Attributes["disables"]; if(disables_attr != null && disables_attr.Value != null) { string [] vars = disables_attr.Value.Split(','); if(vars != null && vars.Length > 0) { disables = new string[vars.Length]; for(int i = 0; i < vars.Length; i++) { disables[i] = vars[i].Trim(); } } } try { XmlNode unit_node = node.SelectSingleNode("unit"); if(unit_node != null) { unit = node.SelectSingleNode("unit").InnerText.Trim(); } } catch { } try { XmlNode advanced_node = node.SelectSingleNode("advanced"); if(advanced_node != null) { advanced = ParseAdvanced(advanced_node.InnerText); } } catch { } default_value = ReadValue(node, "default-value"); min_value = ToDouble(ReadValue(node, "min-value")); max_value = ToDouble(ReadValue(node, "max-value")); min_label = ReadValue(node, "min-label", true); max_label = ReadValue(node, "max-label", true); string step_value_str = ReadValue(node, "step-value"); if(step_value_str != null) { bool zeros = true; step_precision = step_value_str.IndexOf(".") + 1; for(int i = step_precision; i > 0 && i < step_value_str.Length; i++) { if(step_value_str[i] != '0') { zeros = false; break; } } step_precision = zeros ? 0 : step_value_str.Length - step_precision; step_value = ToDouble(step_value_str); } if(default_value != null && default_value != String.Empty && (current_value == null || current_value == String.Empty)) { current_value = default_value; } foreach(XmlNode possible_value_node in Banshee.Base.Localization.SelectNodes(node, "possible-values/value")) { try { string value = possible_value_node.Attributes["value"].Value.Trim(); string display = possible_value_node.InnerText.Trim(); PossibleValue possible_value = new PossibleValue(value, display); XmlAttribute attr = possible_value_node.Attributes["enables"]; if(attr != null && attr.Value != null) { string [] vars = attr.Value.Split(','); if(vars != null && vars.Length > 0) { possible_value.Enables = new string[vars.Length]; for(int i = 0; i < vars.Length; i++) { possible_value.Enables[i] = vars[i].Trim(); } } } attr = possible_value_node.Attributes["disables"]; if(attr != null && attr.Value != null) { string [] vars = attr.Value.Split(','); if(vars != null && vars.Length > 0) { possible_value.Disables = new string[vars.Length]; for(int i = 0; i < vars.Length; i++) { possible_value.Disables[i] = vars[i].Trim(); } } } if(!possible_values.ContainsKey(value)) { possible_values.Add(value, possible_value); possible_values_keys.Add(value); } } catch { } } }
private Link(PossibleValue possibleSquare, ConstraintHeader constraint) { PossibleSquare = possibleSquare; Constraint = constraint; Up = Down = Right = Left = this; }
internal PipelineVariable(XmlNode node) { id = node.Attributes["id"].Value.Trim(); name = Banshee.Base.Localization.SelectSingleNode(node, "name").InnerText.Trim(); control_type = StringToControlType(node.SelectSingleNode("control-type").InnerText.Trim()); XmlAttribute enables_attr = node.Attributes["enables"]; if (enables_attr != null && enables_attr.Value != null) { string [] vars = enables_attr.Value.Split(','); if (vars != null && vars.Length > 0) { enables = new string[vars.Length]; for (int i = 0; i < vars.Length; i++) { enables[i] = vars[i].Trim(); } } } XmlAttribute disables_attr = node.Attributes["disables"]; if (disables_attr != null && disables_attr.Value != null) { string [] vars = disables_attr.Value.Split(','); if (vars != null && vars.Length > 0) { disables = new string[vars.Length]; for (int i = 0; i < vars.Length; i++) { disables[i] = vars[i].Trim(); } } } try { XmlNode unit_node = node.SelectSingleNode("unit"); if (unit_node != null) { unit = node.SelectSingleNode("unit").InnerText.Trim(); } } catch { } try { XmlNode advanced_node = node.SelectSingleNode("advanced"); if (advanced_node != null) { advanced = ParseAdvanced(advanced_node.InnerText); } } catch { } default_value = ReadValue(node, "default-value"); min_value = ToDouble(ReadValue(node, "min-value")); max_value = ToDouble(ReadValue(node, "max-value")); min_label = ReadValue(node, "min-label", true); max_label = ReadValue(node, "max-label", true); string step_value_str = ReadValue(node, "step-value"); if (step_value_str != null) { bool zeros = true; step_precision = step_value_str.IndexOf(".") + 1; for (int i = step_precision; i > 0 && i < step_value_str.Length; i++) { if (step_value_str[i] != '0') { zeros = false; break; } } step_precision = zeros ? 0 : step_value_str.Length - step_precision; step_value = ToDouble(step_value_str); } if (default_value != null && default_value != String.Empty && (current_value == null || current_value == String.Empty)) { current_value = default_value; } foreach (XmlNode possible_value_node in Banshee.Base.Localization.SelectNodes(node, "possible-values/value")) { try { string value = possible_value_node.Attributes["value"].Value.Trim(); string display = possible_value_node.InnerText.Trim(); PossibleValue possible_value = new PossibleValue(value, display); XmlAttribute attr = possible_value_node.Attributes["enables"]; if (attr != null && attr.Value != null) { string [] vars = attr.Value.Split(','); if (vars != null && vars.Length > 0) { possible_value.Enables = new string[vars.Length]; for (int i = 0; i < vars.Length; i++) { possible_value.Enables[i] = vars[i].Trim(); } } } attr = possible_value_node.Attributes["disables"]; if (attr != null && attr.Value != null) { string [] vars = attr.Value.Split(','); if (vars != null && vars.Length > 0) { possible_value.Disables = new string[vars.Length]; for (int i = 0; i < vars.Length; i++) { possible_value.Disables[i] = vars[i].Trim(); } } } if (!possible_values.ContainsKey(value)) { possible_values.Add(value, possible_value); possible_values_keys.Add(value); } } catch { } } }