public void Solve(Grid grid)
        {
            var boxCols = grid.GetBoxColumns();
            var boxRows = grid.GetBoxRows();

            for (var digit = 1; digit <= 9; ++digit)
            {
                for (var boxRow = 1; boxRow <= 3; ++boxRow)
                {
                    var topRow = boxRows[boxRow].Item1;
                    var middleRow = boxRows[boxRow].Item1 + 1;
                    var bottomRow = boxRows[boxRow].Item2;

                    var possibleDigitRows = grid.FindThePotentialDigitInTheBoxRows(boxCols, digit, topRow, middleRow,
                        bottomRow);
                    if (possibleDigitRows.Values.All(v => v.Count != 1)) continue;

                    foreach (var possibleDigitRow in possibleDigitRows)
                    {
                        if (possibleDigitRow.Value.Count != 1) continue;
                        var rowToClear = possibleDigitRow.Value[0];

                        for (var otherBoxCol = 1; otherBoxCol <= 3; ++otherBoxCol)
                        {
                            if (otherBoxCol == possibleDigitRow.Key) continue;

                            for (var colIdx = boxCols[otherBoxCol].Item1;
                                colIdx <= boxCols[otherBoxCol].Item2;
                                ++colIdx)
                            {
                                if (grid.Squares[rowToClear, colIdx].IsSolved) continue;
                                grid.Squares[rowToClear, colIdx].RemovePossibleDigit(digit);
                            }
                        }
                    }
                }
            }
        }
        public void Solve(Grid grid)
        {
            var boxCols = grid.GetBoxColumns();
            var boxRows = grid.GetBoxRows();

            for (var digit = 1; digit <= 9; ++digit)
            {
                for (var boxCol = 1; boxCol <= 3; ++boxCol)
                {
                    var leftColumn = boxCols[boxCol].Item1;
                    var middleColumn = boxCols[boxCol].Item1 + 1;
                    var rightColumn = boxCols[boxCol].Item2;

                    var possibleDigitBoxColumns = grid.FindThePotentialDigitInTheBoxColumns(boxRows, digit, leftColumn, middleColumn, rightColumn);
                    if (possibleDigitBoxColumns.Values.All(v => v.Count != 1)) continue;

                    // Where there is only one possible column for a digit within the box, remove it from that column for other boxes
                    foreach (var possibleDigitBoxColumn in possibleDigitBoxColumns)
                    {
                        if (possibleDigitBoxColumn.Value.Count != 1) continue;
                        var columnToClear = possibleDigitBoxColumn.Value[0];

                        for (var otherBoxRow = 1; otherBoxRow <= 3; ++otherBoxRow)
                        {
                            if (otherBoxRow == possibleDigitBoxColumn.Key) continue;

                            for (var rowIdx = boxRows[otherBoxRow].Item1;
                                rowIdx <= boxRows[otherBoxRow].Item2;
                                ++rowIdx)
                            {
                                if (grid.Squares[rowIdx, columnToClear].IsSolved) continue;
                                grid.Squares[rowIdx, columnToClear].RemovePossibleDigit(digit);
                            }
                        }
                    }
                }
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Given that you need to place a certain digit in two of the three boxes in a row (i.e. it has already been placed in one box)
        /// Can you eliminate one of the rows because all three squares within a particular box have been filled with other digits?
        /// 
        /// e.g.
        /// 100 920 000
        /// 524 017 009
        /// 000 004 271
        /// 
        /// - in this the digit 5 has only been positioned once (the middle row).  So theoretically in the other two boxes
        ///   it will appear in either the top or the bottom row.  However it can't appear in the bottom row in the third box
        ///   because all three squares have been taken.  Therefore despite not knowing which of the top row squares in the third box 
        ///   it will appear in, you know that it can't appear in the top row in the middle box and therefore it must be in 
        ///   the bottom row for the middle box
        ///   i.e. the only remaining possibilities for 5 are marked as ? and it can be removed as a possibility from the square X
        ///    100 92X ???
        ///    524 017 009
        ///    000 ??4 271
        /// </summary>
        /// <param name="grid"></param>
        public void Solve(Grid grid)
        {
            var boxCols = grid.GetBoxColumns();
            var boxRows = grid.GetBoxRows();

            for (var digit = 1; digit <= 9; ++digit)
            {
                // Top box row then middle box row then bottom box row (of 3x3 squares)
                for (var boxRow = 1; boxRow <= 3; ++boxRow)
                {
                    // Square rows within the box row
                    var topSquareRow = boxRows[boxRow].Item1;
                    var middleSquareRow = boxRows[boxRow].Item1 + 1;
                    var bottomSquareRow = boxRows[boxRow].Item2;

                    // Key is the box number (i.e. left, middle, right) and value is the row
                    // in which the digit is found (if at all)
                    var rowInBox = grid.FindTheDigitWithinEachBoxInTheBoxRow(boxCols, digit, topSquareRow, middleSquareRow, bottomSquareRow);

                    // If the current digit has been placed in exactly one box in the current box row
                    // then there is potential to eliminate it as a possibility from one of the square rows
                    // in the remaining two boxes
                    var numberOfBoxesPlaced = rowInBox.Count(kvp => kvp.Value != GridDigitInBoxExtensions.NotFound);
                    if (numberOfBoxesPlaced != 1) continue;

                    var digitPlacedBoxCombo = rowInBox.First(kvp => kvp.Value != GridDigitInBoxExtensions.NotFound);
                    var boxWhereDigitPlaced = digitPlacedBoxCombo.Key;
                    var digitPlacedInRow = digitPlacedBoxCombo.Value;
                    int firstRowToCheck;
                    int secondRowToCheck;
                    if (digitPlacedInRow == topSquareRow)
                    {
                        firstRowToCheck = middleSquareRow;
                        secondRowToCheck = bottomSquareRow;
                    }
                    else if (digitPlacedInRow == middleSquareRow)
                    {
                        firstRowToCheck = topSquareRow;
                        secondRowToCheck = bottomSquareRow;
                    }
                    else
                    {
                        firstRowToCheck = topSquareRow;
                        secondRowToCheck = middleSquareRow;
                    }

                    // Key is box number, value is whether or not all squares in that
                    var completeFirstRowInBox = new Dictionary<int, int> {{1, 0}, {2, 0}, {3, 0}};
                    var completeSecondRowInBox = new Dictionary<int, int> { { 1, 0 }, { 2, 0 }, { 3, 0 } };

                    for (var boxCol = 1; boxCol <= 3; ++boxCol)
                    {
                        if (rowInBox[boxCol] != GridDigitInBoxExtensions.NotFound)
                        {
                            continue;
                        }

                        var firstRowSolvedSquares = 0;
                        var secondRowSolvedSquares = 0;
                        for (var colIdx = boxCols[boxCol].Item1; colIdx <= boxCols[boxCol].Item2; ++colIdx)
                        {
                            if (grid.Squares[firstRowToCheck, colIdx].IsSolved)
                            {
                                firstRowSolvedSquares++;
                            }
                            if (grid.Squares[secondRowToCheck, colIdx].IsSolved)
                            {
                                secondRowSolvedSquares++;
                            }
                        }
                        if (firstRowSolvedSquares == 3)
                        {
                            completeFirstRowInBox[boxCol] = boxCol;
                        }
                        if (secondRowSolvedSquares == 3)
                        {
                            completeSecondRowInBox[boxCol] = boxCol;
                        }
                    }

                    var boxToClear = 0;
                    var rowToClear = 0;

                    // If there is any row within a box (unsolved for the digit) that is complete
                    // then there is no room for the digit and then for that row it *must* be in the third box
                    if (completeFirstRowInBox.Any(kvp => kvp.Value != 0))
                    {
                        rowToClear = secondRowToCheck;

                        var boxWhereComplete = completeFirstRowInBox.First(kvp => kvp.Value != 0).Key;
                        boxToClear = FindBoxToClear(boxWhereDigitPlaced, boxWhereComplete);
                    }

                    if (completeSecondRowInBox.Any(kvp => kvp.Value != 0))
                    {
                        rowToClear = firstRowToCheck;

                        var boxWhereComplete = completeSecondRowInBox.First(kvp => kvp.Value != 0).Key;
                        boxToClear = FindBoxToClear(boxWhereDigitPlaced, boxWhereComplete);
                    }

                    if (boxToClear != 0)
                    {
                        for (var colIdx = boxCols[boxToClear].Item1; colIdx <= boxCols[boxToClear].Item2; ++colIdx)
                        {
                            grid.CheckIfTestCase(rowToClear, colIdx, digit);
                            grid.Squares[rowToClear, colIdx].RemovePossibleDigit(digit);
                        }
                    }
                }
            }
        }
        public void Solve(Grid grid)
        {
            const int IgnoreColumn = -1;

            var boxRows = grid.GetBoxRows();
            var boxCols = grid.GetBoxColumns();

            for (var digit = 1; digit <= 9; ++digit)
            {
                for (var boxCol = 1; boxCol <= 3; ++boxCol)
                {
                    var leftColumn = boxCols[boxCol].Item1;
                    var middleColumn = boxCols[boxCol].Item1 + 1;
                    var rightColumn = boxCols[boxCol].Item2;

                    var possibleDigitBoxColumns = grid.FindThePotentialDigitInTheBoxColumns(boxRows, digit, leftColumn, middleColumn, rightColumn);
                    var countOfColumnBoxPairs = possibleDigitBoxColumns.Count(pb => pb.Value.Count == 2);
                    if (countOfColumnBoxPairs < 2) continue;

                    foreach (var possibleDigitBoxColumn in possibleDigitBoxColumns)
                    {
                        var firstBox = possibleDigitBoxColumn.Key;
                        if (possibleDigitBoxColumn.Value.Count == 0) continue;
                        if (possibleDigitBoxColumn.Value.Count > 2) continue;
                        var firstColumn = possibleDigitBoxColumn.Value[0];
                        var secondColumn = possibleDigitBoxColumn.Value.Count > 1
                            ? possibleDigitBoxColumn.Value[1]
                            : IgnoreColumn;

                        foreach (var otherDigitBoxColumn in possibleDigitBoxColumns)
                        {
                            if (otherDigitBoxColumn.Key == possibleDigitBoxColumn.Key) continue;
                            if (otherDigitBoxColumn.Value.Count > 2) continue;
                            if (otherDigitBoxColumn.Value.Count == 0) continue;
                            if (!otherDigitBoxColumn.Value.Contains(firstColumn)) continue;
                            if (secondColumn != IgnoreColumn && !otherDigitBoxColumn.Value.Contains(secondColumn)) continue;
                            var secondBox = otherDigitBoxColumn.Key;
                            if (secondColumn == IgnoreColumn && otherDigitBoxColumn.Value.Count > 1)
                            {
                                secondColumn = otherDigitBoxColumn.Value[1];
                            }

                            // Digit is restricted to two particular columns between two boxes
                            // Therefore remove from the third
                            var thirdBox = possibleDigitBoxColumns.Single(pb => pb.Key != firstBox && pb.Key != secondBox);

                            for (var rowIdx = boxRows[thirdBox.Key].Item1;
                                rowIdx <= boxRows[thirdBox.Key].Item2;
                                ++ rowIdx)
                            {
                                grid.Squares[rowIdx, firstColumn].RemovePossibleDigit(digit);
                                if (secondColumn != IgnoreColumn)
                                {
                                    grid.Squares[rowIdx, secondColumn].RemovePossibleDigit(digit);
                                }
                            }

                        }
                    }
                }
            }
        }