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); } } } } } }
/// <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); } } } } } } }