public SudokuPuzzle GenerateSudoku(SudokuDifficuty difficulty, int length = 9) { // get randomly filled out sudoku SudokuPuzzle solution = SolveSudoku(new SudokuPuzzle()); SudokuPuzzle sudoku = (SudokuPuzzle)solution.Clone(); // check how many fields need to be removed (depending on desired difficulty) int fieldsToRemove = ((length * length) - (int)difficulty); while (fieldsToRemove > 0) { int freeFieldsCount = sudoku.GetFreeFields().Count; foreach (var field in sudoku.GetSetFields().Shuffle()) { if (fieldsToRemove > 0 && isFieldDetermined(sudoku, solution, field.RowIndex, field.ColumnIndex)) { field.SetValue(0); fieldsToRemove--; } } // check if progress was made (if not => try with another sudoku puzzle) if ((freeFieldsCount - sudoku.GetFreeFields().Count) == 0) { sudoku = GenerateSudoku(difficulty, length); break; } } // check if the generated sudoku is unique. if not create a new one. return((HasSudokuUniqueSolution(sudoku)) ? sudoku : GenerateSudoku(difficulty, length)); }
public bool HasSudokuUniqueSolution(SudokuPuzzle sudoku) { // sudokus with 16 or less determinded fields cannot have a unique solution // source: https://www.technologyreview.com/s/426554/mathematicians-solve-minimum-sudoku-problem/ bool ret = (sudoku.GetSetFields()?.Count > 16); if (ret) { // solve sudoku (gets one solution out of possibly many solutions) var solution = SolveSudoku(sudoku); ret = (solution != null); if (ret) { var temp = (SudokuPuzzle)sudoku.Clone(); // go through all empty fields (filled out fields are ignored) while (ret && !temp.IsSolved()) { // choose a free field with a minimum amount of remaining possibilities int minPossibleValuesCount = temp.GetFreeFields().Select(x => x.GetPossibleValuesCount()).Min(); var field = temp.GetFreeFields().Where(x => x.GetPossibleValuesCount() == minPossibleValuesCount).ChooseRandom(); // check if the field is determined; if not, there is a second solution => return false ret = isFieldDetermined(temp, solution, field); // apply the determined value to the sudoku => less possibilities field.SetValue(solution.Fields[field.RowIndex, field.ColumnIndex].Value); } } } return(ret); }
private bool removeField(SudokuPuzzle sudoku, SudokuPuzzle solution) { foreach (SudokuField field in sudoku.GetSetFields().Shuffle()) { // clone sudoku and set the field value to 0 SudokuPuzzle temp = (SudokuPuzzle)sudoku.Clone(); SudokuField tempField = temp.Fields[field.RowIndex, field.ColumnIndex]; tempField.SetValue(0); if (HasSudokuUniqueSolution(temp)) { field.SetValue(0); return(true); } } return(false); }