/// <summary> /// This method takes a point that has two possible values, picks the first value, and tries to solve the grid using that value. If that value is wrong, the method goes back and tries the other value. /// </summary> /// <returns>True if the grid was solved by this method; false otherwise.</returns> private bool Guess() { //If there are no points with at least 1 possible value left, a successful guess cannot be made if (points.Where(p => p.possibleValues.Count > 0).FirstOrDefault() == null) { return(false); } //Make a "copy" of the grid before guessing, to reset if needed later string gridString = GridString(); //Select the first point that has the minimal number of possible values left int minPossible = points.Where(p => p.possibleValues.Count > 0).Select(p => p.possibleValues.Count).Min(); SudokuPoint toGuess = points.Where(p => p.possibleValues.Count == minPossible).FirstOrDefault(); //If there are no points with possible values left, that means the grid is no longer valid, and the last guess was unsuccessful if (toGuess == null) { return(false); } //Save the index of the point guessed, the value guessed, and the value not guessed int indexGuessed = toGuess.index; //Create a list of possible guesses (the same list as the possible values for the point being guessed) List <int> possibleGuesses = new List <int>(); foreach (int i in toGuess.possibleValues) { possibleGuesses.Add(i); } //Continue to guess until all options for the point being guessed have been exhausted while (possibleGuesses.Count > 0) { points[indexGuessed].value = possibleGuesses.FirstOrDefault(); if (SolveAllPoints()) { //If the grid could be solved from this guess, the guess was successful return(true); } else { //If the grid could not be solved from this guess, reset the grid to before the guess, //remove the last value guessed, and try again SetPoints(gridString); possibleGuesses.Remove(possibleGuesses.FirstOrDefault()); } } //If the grid could not be solved from either guess, the guess is unsuccessful return(false); }
/// <summary> /// Recalculates the possible values for a given point, checking all used values in that point's row, column, and box /// </summary> /// <param name="point">The point to recalculate possible values for</param> private void RecalculatePossibleValues(SudokuPoint point) { if (point.value != 0) { point.possibleValues = new List <int>(); return; } var impossibleValues = points.Where(p => p.box == point.box || p.column == point.column || p.row == point.row).Select(p => p.value).Distinct(); point.possibleValues = digits.Where(d => !impossibleValues.Contains(d)).ToList(); }
/// <summary> /// Sets all points in the grid to values given /// </summary> /// <param name="pointValues">An array of integers containing the values to go in the grid, numbered from 0 (top left) to 80 (bottom right)</param> private void SetPoints(int[] pointValues) { if (pointValues.Length != 81) { return; } points = new SudokuPoint[81]; for (int i = 0; i < pointValues.Length; i++) { points[i] = new SudokuPoint(i, pointValues[i]); } }
/// <summary> /// Sets all points in the grid to values given /// </summary> /// <param name="pointValues">An array of integers containing the values to go in the grid, numbered from 0 (top left) to 80 (bottom right)</param> private void SetPoints(int[] pointValues) { if (pointValues.Length != 81) return; points = new SudokuPoint[81]; for (int i = 0; i < pointValues.Length; i++) points[i] = new SudokuPoint(i, pointValues[i]); }
/// <summary> /// Recalculates the possible values for a given point, checking all used values in that point's row, column, and box /// </summary> /// <param name="point">The point to recalculate possible values for</param> private void RecalculatePossibleValues(SudokuPoint point) { if (point.value != 0) { point.possibleValues = new List<int>(); return; } var impossibleValues = points.Where(p => p.box == point.box || p.column == point.column || p.row == point.row).Select(p => p.value).Distinct(); point.possibleValues = digits.Where(d => !impossibleValues.Contains(d)).ToList(); }