예제 #1
0
        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);
        }
예제 #2
0
 /// <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);
 }
예제 #3
0
        /// <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);
        }
        /// <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);
        }
예제 #5
0
            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);
            }
예제 #6
0
        /// <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);
        }