/// <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);
        }
Exemple #3
0
        /// <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);
        }
Exemple #6
0
 public override bool IsImpossible(int cell, int value) => Takens[cell][value - Parent.MinValue] || Parent.IsImpossible(cell, value);
Exemple #7
0
        /// <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);
        }