/// <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) { state.MustBe(Cell, Value); return(ConstraintResult.Remove); }
/// <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); }