/// <summary>Override; see base.</summary> public override ConstraintResult Process(SolverState state) { if (state.LastPlacedCell == null) { return(null); } var unknowns = AffectedCells.Count(af => state[af] == null); if (unknowns != 1) { return(null); } var unknown = AffectedCells.First(af => state[af] == null); state.MarkImpossible(unknown, value => !IsValid( state[AffectedCells[0]] ?? value, state[AffectedCells[1]] ?? value, state[AffectedCells[2]] ?? value, state[AffectedCells[3]] ?? value, state[AffectedCells[4]] ?? value, state[AffectedCells[5]] ?? value )); return(null); }
/// <summary>Override; see base.</summary> public override ConstraintResult Process(SolverState state) { if (state.LastPlacedCell == null) { return(null); } foreach (var parity in _parities) { var count = AffectedCells.Count(cell => state[cell] != null && state[cell].Value % 2 == parity); if (count == AffectedCells.Length / 2) { foreach (var cell in AffectedCells) { if (state[cell] == null) { for (var v = state.MinValue; v <= state.MaxValue; v++) { if (v % 2 == parity) { state.MarkImpossible(cell, v); } } } } } } return(null); }
public override bool Verify(int[] grid) { var p1 = AffectedCells.IndexOf(ix => grid[ix] == Digit1); var p2 = AffectedCells.IndexOf(ix => grid[ix] == Digit2); if (p1 == -1 || p2 == -1) { return(false); } return(AffectedCells.Skip(p1 + 1).Take(p2 - 1 - 1).Sum(ix => grid[ix]) == Clue); }
/// <summary>Override; see base.</summary> public override ConstraintResult Process(SolverState state) { if (state.LastPlacedCell != null && !AffectedCells.Contains(state.LastPlacedCell.Value)) { return(null); } var innerTakens = new bool[Subconstraints.Length][][]; List <Constraint> newSubconstraints = null; for (var sc = 0; sc < Subconstraints.Length; sc++) { var substate = new SolverStateImpl { Parent = state, Takens = Ut.NewArray <bool>(state.GridSize, state.MaxValue - state.MinValue + 1) }; var result = Subconstraints[sc].Process(substate); innerTakens[sc] = substate.Takens; if (result is ConstraintReplace) { throw new NotImplementedException("The OrConstraint does not support subconstraints that replace themselves with new constraints."); } else if (result is ConstraintViolation) { if (newSubconstraints == null) { newSubconstraints = new List <Constraint>(Subconstraints.Take(sc)); } } else if (newSubconstraints != null) { newSubconstraints.Add(Subconstraints[sc]); } } foreach (var cell in AffectedCells) { state.MarkImpossible(cell, value => innerTakens.All(taken => taken == null || taken[cell][value - state.MinValue])); } if (newSubconstraints != null) { return new[] { new OrConstraint(newSubconstraints) } } ; return(null); } }
/// <summary>Override; see base.</summary> public override ConstraintResult Process(SolverState state) { if (state.LastPlacedCell != null) { var i = AffectedCells.IndexOf(state.LastPlacedCell.Value); var v = state.LastPlacedValue; state.MarkImpossible(AffectedCells[((i + v) % AffectedCells.Length + AffectedCells.Length) % AffectedCells.Length], v); state.MarkImpossible(AffectedCells[((i - v) % AffectedCells.Length + AffectedCells.Length) % AffectedCells.Length], v); } else { for (var i = 0; i < AffectedCells.Length; i++) { state.MarkImpossible(AffectedCells[i], v => (i + v) % AffectedCells.Length == i); } } return(null); }
/// <summary>Override; see base.</summary> public override ConstraintResult Process(SolverState state) { if (state.LastPlacedCell == null) { return(null); } var unknowns = AffectedCells.Count(af => state[af] == null); if (unknowns == 1) { var unknown = AffectedCells.First(af => state[af] == null); state.MarkImpossible(unknown, value => !IsValid( state[AffectedCells[0]] ?? value, state[AffectedCells[1]] ?? value, state[AffectedCells[2]] ?? value, state[AffectedCells[3]] ?? value )); } else if (unknowns == 2) { var unkn1 = AffectedCells.First(af => state[af] == null); var unkn1Ix = AffectedCells.IndexOf(unkn1); var unkn2 = AffectedCells.Last(af => state[af] == null); var numValues = state.MaxValue - state.MinValue + 1; var possibles = new bool[numValues * numValues]; for (var val1 = state.MinValue; val1 <= state.MaxValue; val1++) { for (var val2 = state.MinValue; val2 <= state.MaxValue; val2++) { possibles[(val1 - state.MinValue) + numValues * (val2 - state.MinValue)] = IsValid( state[AffectedCells[0]] ?? (unkn1Ix == 0 ? val1 : val2), state[AffectedCells[1]] ?? (unkn1Ix == 1 ? val1 : val2), state[AffectedCells[2]] ?? (unkn1Ix == 2 ? val1 : val2), state[AffectedCells[3]] ?? (unkn1Ix == 3 ? val1 : val2)); } } state.MarkImpossible(unkn1, value1 => Enumerable.Range(0, numValues).All(value2 => !possibles[(value1 - state.MinValue) + numValues * value2])); state.MarkImpossible(unkn2, value2 => Enumerable.Range(0, numValues).All(value1 => !possibles[value1 + numValues * (value2 - state.MinValue)])); } return(null); }
protected override bool InternalApply() { var containedTraps = Fight.GetTriggers().OfType <Trap>().Where(entry => entry.VisibleState == GameActionFightInvisibilityStateEnum.INVISIBLE && Caster.IsEnnemyWith(entry.Caster) && AffectedCells.Contains(entry.Shape.Cell)); foreach (var trap in containedTraps) { trap.VisibleState = GameActionFightInvisibilityStateEnum.VISIBLE; ContextHandler.SendGameActionFightMarkCellsMessage(Fight.Clients, trap); } foreach (var target in GetAffectedActors().Where(target => target.VisibleState == GameActionFightInvisibilityStateEnum.INVISIBLE && target.IsEnnemyWith(Caster))) { target.SetInvisibilityState(GameActionFightInvisibilityStateEnum.VISIBLE); } return(true); }
/// <summary>Override; see base.</summary> public override ConstraintResult Process(SolverState state) { var minPossibleSum = AffectedCells.Sum(state.MinPossible); var maxPossibleSum = AffectedCells.Sum(state.MaxPossible); for (var ix = 0; ix < AffectedCells.Length; ix++) { var cell = AffectedCells[ix]; if (state[cell] != null) { continue; } var minOther = minPossibleSum - state.MinPossible(cell); var maxOther = maxPossibleSum - state.MaxPossible(cell); state.MarkImpossible(cell, value => minOther + value > Sum || maxOther + value < Sum); } return(null); }
/// <summary>Override; see base.</summary> public override IEnumerable <Constraint> MarkTakens(bool[][] takens, int?[] grid, int?ix, int minValue, int maxValue) { if (ix == null) { return(null); } // “slot” is the value we just placed (index into AffectedCells, 0–2) var slot = Array.IndexOf(AffectedCells, ix.Value); if (slot == -1) { return(null); } // “unknown” is the value that is yet to be placed (index into AffectedCells, 0–2) var unknown = AffectedCells.IndexOf(af => grid[af] == null); if (unknown == -1) { return(null); } // Make sure that there is a second already-placed value if (grid[AffectedCells[3 - slot - unknown]] == null) { return(null); } for (var v = 0; v < takens[AffectedCells[unknown]].Length; v++) { if (!IsValid( (grid[AffectedCells[0]] ?? v) + minValue, (grid[AffectedCells[1]] ?? v) + minValue, (grid[AffectedCells[2]] ?? v) + minValue )) { takens[AffectedCells[unknown]][v] = true; } } return(null); }
/// <summary>Override; see base.</summary> public override ConstraintResult Process(SolverState state) { if (state.LastPlacedCell != null && !AffectedCells.Contains(state.LastPlacedCell.Value)) { return(null); } var productAlready = 1; var cellsLeftToFill = 0; foreach (var cell in AffectedCells) { if (state[cell] is int value) { productAlready *= value; } else { cellsLeftToFill++; } } if (cellsLeftToFill == 0 || (productAlready == 0 && Product == 0)) { return(null); } var alreadyBroken = productAlready == 0 || (Product % productAlready != 0); foreach (var cell in AffectedCells) { state.MarkImpossible(cell, value => alreadyBroken || // The last remaining cell must have the exact required value (cellsLeftToFill == 1 && productAlready * value != Product) || // The remaining cells must be factors of whatever is left to multiply (cellsLeftToFill > 1 && value == 0 ? (Product != 0) : ((Product / productAlready) % value != 0))); } return(null); }
public override ConstraintResult Process(SolverState state) { if (state.LastPlacedCell == null) { // The focus cell cannot be so large that it points outside the grid, // nor can it have a value that points at a cell that already contains something other than a 9 state.MarkImpossible(AffectedCells[0], v => v > AffectedCells.Length - 1 || state.IsImpossible(AffectedCells[v], 9)); } else if (state.LastPlacedCell.Value == AffectedCells[0]) { // The focus cell has been set, therefore place the 9 in the correct position state.MustBe(AffectedCells[state.LastPlacedValue], 9); for (var i = 1; i < AffectedCells.Length; i++) { if (i != state.LastPlacedValue) { state.MarkImpossible(AffectedCells[i], 9); } } } else if (AffectedCells.Contains(state.LastPlacedCell.Value)) { var index = AffectedCells.IndexOf(state.LastPlacedCell.Value); if (state.LastPlacedValue == 9) { // A 9 has been placed somewhere, therefore set the focus cell to the correct value // (This is the main difference with FindTheValueConstraint; it’s an optimization that assumes uniqueness) state.MustBe(AffectedCells[0], index); } else { // A value other than 9 has been placed somewhere, therefore the focus cell cannot point at it anymore state.MarkImpossible(AffectedCells[0], index); } } 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) { if (state.LastPlacedCell is int cell) { var innerCell = AffectedCells == null ? cell : AffectedCells.IndexOf(cell); var x = innerCell % SideLength; var y = innerCell / SideLength; var numUnknownsInColumn = Enumerable.Range(0, SideLength).Count(row => state[coord(x, row)] == null); if (numUnknownsInColumn < 2) { // We just placed the last or second-last value in this column. // If it’s the last, we need to make sure that no almost-complete column is about to be filled with the same parities. // If it’s the second-last, we need to make sure that THIS column isn’t going to be filled with the same parities as another equal column. for (var col = 0; col < SideLength; col++) { if (col == x) { continue; } var discrepantRow = -1; for (var row = 0; row < SideLength; row++) { if (state[coord(numUnknownsInColumn == 0 ? col : x, row)] == null && state[coord(numUnknownsInColumn == 0 ? x : col, row)] != null) { if (discrepantRow == -1) { discrepantRow = row; } else { goto nextColumn; } } else if (state[coord(col, row)] == null || state[coord(col, row)].Value % 2 != state[coord(x, row)].Value % 2) { goto nextColumn; } } for (var v = state.MinValue; v <= state.MaxValue; v++) { if (v % 2 == state[coord(numUnknownsInColumn == 0 ? x : col, discrepantRow)].Value % 2) { state.MarkImpossible(coord(numUnknownsInColumn == 0 ? col : x, discrepantRow), v); } } nextColumn :; } } var numUnknownsInRow = Enumerable.Range(0, SideLength).Count(col => state[coord(col, y)] == null); if (numUnknownsInRow < 2) { // See comment above for columns for (var row = 0; row < SideLength; row++) { if (row == y) { continue; } var discrepantCol = -1; for (var col = 0; col < SideLength; col++) { if (state[coord(col, numUnknownsInRow == 0 ? row : y)] == null && state[coord(col, numUnknownsInRow == 0 ? y : row)] != null) { if (discrepantCol == -1) { discrepantCol = col; } else { goto nextRow; } } else if (state[coord(col, row)] == null || state[coord(col, row)].Value % 2 != state[coord(col, y)].Value % 2) { goto nextRow; } } for (var v = state.MinValue; v <= state.MaxValue; v++) { if (v % 2 == state[coord(discrepantCol, numUnknownsInRow == 0 ? y : row)].Value % 2) { state.MarkImpossible(coord(discrepantCol, numUnknownsInRow == 0 ? row : y), v); } } nextRow :; } } } return(null); }