/// <summary>Override; see base.</summary> public override ConstraintResult Process(SolverState state) { for (var ix = 0; ix < Area1.Length; ix++) { state.MarkImpossible(Area1[ix], value => state.IsImpossible(Area2[ix], value)); state.MarkImpossible(Area2[ix], value => state.IsImpossible(Area1[ix], value)); } return(null); }
/// <summary>Override; see base.</summary> public override ConstraintResult Process(SolverState state) { // Determine if we know the offset for (var i = 0; i < Area1.Length; i++) { if (state[Area1[i]] != null && state[Area2[i]] != null) { // We found the offset. Process the entire region and stop here. var offset = state[Area2[i]].Value - state[Area1[i]].Value; for (var ix = 0; ix < Area1.Length; ix++) { state.MarkImpossible(Area1[ix], value => state.IsImpossible(Area2[ix], value + offset)); state.MarkImpossible(Area2[ix], value => state.IsImpossible(Area1[ix], value - offset)); } return(null); } } // We do not know the offset. return(null); }
/// <summary>Override; see base.</summary> public override ConstraintResult Process(SolverState state) { state.MarkImpossible(AffectedCells[0], value => value < 0 || value >= AffectedCells.Length || state.IsImpossible(AffectedCells[value], Value)); if (state.LastPlacedCell == AffectedCells[0]) { // The focus cell has been set, therefore place the value in the correct position state.MustBe(AffectedCells[state.LastPlacedValue], Value); } return(null); }
/// <summary>Override; see base.</summary> public override ConstraintResult Process(SolverState state) { // This will determine which values are still possible in which of the affected cells. var poss = Ut.NewArray(AffectedCells.Length, i => new bool[state.MaxValue - state.MinValue + 1]); // If any combination can be ruled out, this will contain the remaining combinations still available. List <int?[]> newComb = null; for (var i = 0; i < Combinations.Length; i++) { // Can this combination be ruled out? if (AffectedCells.Any((cellIx, lstIx) => Combinations[i][lstIx] != null && (state[cellIx] == null ? state.IsImpossible(cellIx, Combinations[i][lstIx].Value) : (state[cellIx].Value != Combinations[i][lstIx].Value)))) { if (newComb == null) { newComb = new List <int?[]>(Combinations.Take(i)); } } else { if (newComb != null) { newComb.Add(Combinations[i]); } // Remember the possibilities for each cell for (var lstIx = 0; lstIx < Combinations[i].Length; lstIx++) { if (Combinations[i][lstIx] == null) { poss[lstIx] = null; } else if (poss[lstIx] != null) { poss[lstIx][Combinations[i][lstIx].Value - state.MinValue] = true; } } } } // Mark any cell values that are no longer possible as taken for (var lstIx = 0; lstIx < poss.Length; lstIx++) { if (state[AffectedCells[lstIx]] == null && poss[lstIx] != null) { for (var v = 0; v < poss[lstIx].Length; v++) { if (!poss[lstIx][v] && !state.IsImpossible(AffectedCells[lstIx], v + state.MinValue)) { state.MarkImpossible(AffectedCells[lstIx], v + state.MinValue); } } } } if (newComb != null) { return new[] { new CombinationsConstraint(AffectedCells, newComb.ToArray()) } } ; return(null); }
/// <summary>Override; see base.</summary> public override ConstraintResult Process(SolverState state) { int req; // Do we know the parity yet? switch (Type) { case OddEvenType.AllEven: req = 0; break; case OddEvenType.AllOdd: req = 1; break; case OddEvenType.AllSame: // Check if any of the affected cells knows its parity for (var ix = 0; ix < AffectedCells.Length; ix++) { var cell = AffectedCells[ix]; if (state[cell] != null) { req = state[cell].Value % 2; goto found; } int?parity = null; for (var value = state.MinValue; value <= state.MaxValue; value++) { if (!state.IsImpossible(cell, value)) { if (parity == null) { parity = value % 2; } else if (parity.Value != value % 2) { goto busted; } } } if (parity != null) { req = parity.Value; goto found; } busted :; } return(null); default: throw new InvalidOperationException(string.Format(@"OddEvenConstraint.Type has unknown value: {0}", Type)); } found: // Mark all the cells of the wrong parity as taken. After this, we don’t need the constraint anymore. foreach (var cell in AffectedCells) { state.MarkImpossible(cell, value => value % 2 != req); } return(ConstraintResult.Remove); }
public override bool IsImpossible(int cell, int value) => Takens[cell][value - Parent.MinValue] || Parent.IsImpossible(cell, value);
/// <summary>Override; see base.</summary> public override ConstraintResult Process(SolverState state) { if (state.LastPlacedCell != null) { foreach (var cell in AffectedCells) { if (cell != state.LastPlacedCell.Value) { state.MarkImpossible(cell, state.LastPlacedValue); } } } else { // In case this constraint was returned from another constraint when some of the grid is already filled in, make sure to enforce uniqueness correctly. foreach (var cell1 in AffectedCells) { if (state[cell1] != null) { foreach (var cell2 in AffectedCells) { if (cell2 != cell1) { state.MarkImpossible(cell2, state[cell1].Value); } } } } } // Special case: if the number of values equals the number of cells, we can detect further optimizations if (state.MaxValue - state.MinValue + 1 == AffectedCells.Length) { if (_optimizationList == null || _optimizationList.Length != state.MaxValue - state.MinValue + 1) { _optimizationList = new List <int> [state.MaxValue - state.MinValue + 1]; } var cells = _optimizationList; for (var i = 0; i < cells.Length; i++) { if (cells[i] != null) { cells[i].Clear(); } } foreach (var cell in AffectedCells) { for (var v = state.MinValue; v <= state.MaxValue; v++) { if (!state.IsImpossible(cell, v)) { if (cells[v - state.MinValue] == null) { cells[v - state.MinValue] = new List <int>(); } cells[v - state.MinValue].Add(cell); } } } for (var v1 = 0; v1 <= state.MaxValue - state.MinValue; v1++) { // Detect if a value can only be in one place if (cells[v1]?.Count == 1) { state.MustBe(cells[v1][0], v1 + state.MinValue); } for (var v2 = v1 + 1; v2 <= state.MaxValue - state.MinValue; v2++) { // Detect if two values can only be in two places (“pair”) if (cells[v1]?.Count == 2 && cells[v2]?.Count == 2 && cells[v1].All(cells[v2].Contains)) { foreach (var c in cells[v1]) { state.MarkImpossible(c, v => v != v1 + state.MinValue && v != v2 + state.MinValue); } } for (var v3 = v2 + 1; v3 <= state.MaxValue - state.MinValue; v3++) { // Detect if three values can only be in three places (“triplet”) if (cells[v1]?.Count <= 3 && cells[v2]?.Count <= 3 && cells[v3]?.Count <= 3) { var hashSet = new HashSet <int>(cells[v1]); hashSet.AddRange(cells[v2]); hashSet.AddRange(cells[v3]); if (hashSet.Count <= 3) { foreach (var c in hashSet) { state.MarkImpossible(c, v => v != v1 + state.MinValue && v != v2 + state.MinValue && v != v3 + state.MinValue); } } } } } } } return(null); }