From 79f3472ce2889dc5d536b39e5605d4a9b0b7ce25 Mon Sep 17 00:00:00 2001 From: Stevo Date: Sat, 16 Mar 2024 11:18:36 +0000 Subject: [PATCH 1/6] WIP --- src/Sudoku/Extensions/IntArrayExtensions.cs | 5 ++ src/Sudoku/Extensions/SpanIntExtensions.cs | 6 +- src/Sudoku/Generator.cs | 64 +++++++++++++++++++-- 3 files changed, 68 insertions(+), 7 deletions(-) diff --git a/src/Sudoku/Extensions/IntArrayExtensions.cs b/src/Sudoku/Extensions/IntArrayExtensions.cs index 8650ed2..4dec26a 100644 --- a/src/Sudoku/Extensions/IntArrayExtensions.cs +++ b/src/Sudoku/Extensions/IntArrayExtensions.cs @@ -2,6 +2,11 @@ namespace Sudoku.Extensions; public static class IntArrayExtensions { + public static bool IsValidSudoku(this int[] puzzle) + { + return SpanIntExtensions.IsValidSudoku(puzzle); + } + public static void DumpToConsole(this int[] array, int left = -1, int top = -1) { SetPosition(left, top, 0); diff --git a/src/Sudoku/Extensions/SpanIntExtensions.cs b/src/Sudoku/Extensions/SpanIntExtensions.cs index 3be728f..f445831 100644 --- a/src/Sudoku/Extensions/SpanIntExtensions.cs +++ b/src/Sudoku/Extensions/SpanIntExtensions.cs @@ -20,14 +20,14 @@ public static bool IsValidSudoku(this Span puzzle) for (var x = 0; x < 9; x++) { - if (puzzle[x + y * 9] != 0) + if (puzzle[x + y * 9] > 0) { uniqueRow.Add(puzzle[x + y * 9]); countRow++; } - if (puzzle[y + x * 9] != 0) + if (puzzle[y + x * 9] > 0) { uniqueColumn.Add(puzzle[y + x * 9]); @@ -55,7 +55,7 @@ public static bool IsValidSudoku(this Span puzzle) { for (var y = 0; y < 3; y++) { - if (puzzle[(yO + y) * 9 + xO + x] != 0) + if (puzzle[(yO + y) * 9 + xO + x] > 0) { uniqueBox.Add(puzzle[(yO + y) * 9 + xO + x]); diff --git a/src/Sudoku/Generator.cs b/src/Sudoku/Generator.cs index ec1aae6..9741fd5 100644 --- a/src/Sudoku/Generator.cs +++ b/src/Sudoku/Generator.cs @@ -4,23 +4,79 @@ namespace Sudoku; public class Generator { + private readonly List _positions = new(); + private readonly List[] _candidates = new List[81]; + private int[] _puzzle; + private readonly Random _rng = Random.Shared; private readonly Solver _solver = new(HistoryType.None, SolveMethod.FindUnique); public int[] Generate(int cluesToLeave = 30) { - var puzzle = new int[81]; + _puzzle = new int[81]; + + GeneratePositions(cluesToLeave); + + FillPositions(cluesToLeave); + + return _puzzle; + } + + private void GeneratePositions(int cluesToLeave) + { + _positions.Clear(); + for (var i = 0; i < cluesToLeave; i++) + { + var position = _rng.Next(81); + + while (_puzzle[position] != 0) + { + position = _rng.Next(81); + } + + _puzzle[position] = -1; + + _positions.Add(position); + } + } + + private bool FillPositions(int cluesToLeave, int position = 0) + { InitialiseCandidates(); - CreateSolvedPuzzle(puzzle); + var cell = _positions[position]; + + while (_candidates[cell].Count > 0) + { + var index = _rng.Next(_candidates[cell].Count); + + _puzzle[cell] = _candidates[cell][index]; + + _candidates[cell].RemoveAt(index); - RemoveCells(puzzle, 81 - cluesToLeave); + if (_puzzle.IsValidSudoku()) + { + if (position + 1 == cluesToLeave) + { + if (_solver.Solve(_puzzle).Solved) + { + return true; + } + } + + return FillPositions(cluesToLeave, position + 1); + } + } + + _puzzle[cell] = -1; + + _candidates[cell] = [1, 2, 3, 4, 5, 6, 7, 8, 9]; - return puzzle; + return FillPositions(cluesToLeave, position - 1); } private void RemoveCells(int[] puzzle, int cellsToRemove) From 8c7cadcb626c18380c9ac4036a7dca914e8a8e07 Mon Sep 17 00:00:00 2001 From: Stevo Date: Sat, 16 Mar 2024 11:20:07 +0000 Subject: [PATCH 2/6] WIP --- src/Sudoku/Generator.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Sudoku/Generator.cs b/src/Sudoku/Generator.cs index 9741fd5..47674db 100644 --- a/src/Sudoku/Generator.cs +++ b/src/Sudoku/Generator.cs @@ -66,6 +66,8 @@ private bool FillPositions(int cluesToLeave, int position = 0) { return true; } + + return false; } return FillPositions(cluesToLeave, position + 1); From d48495fff422ebab94bbbb2d88a1a59b7b92ea0b Mon Sep 17 00:00:00 2001 From: Stevo Date: Sat, 16 Mar 2024 11:24:19 +0000 Subject: [PATCH 3/6] WIP --- src/Sudoku/Generator.cs | 74 ----------------------------------------- 1 file changed, 74 deletions(-) diff --git a/src/Sudoku/Generator.cs b/src/Sudoku/Generator.cs index 47674db..e60b229 100644 --- a/src/Sudoku/Generator.cs +++ b/src/Sudoku/Generator.cs @@ -81,80 +81,6 @@ private bool FillPositions(int cluesToLeave, int position = 0) return FillPositions(cluesToLeave, position - 1); } - private void RemoveCells(int[] puzzle, int cellsToRemove) - { - var copy = new int[81]; - - for (var i = 0; i < 81; i++) - { - copy[i] = puzzle[i]; - } - - var filledCells = new List(); - - for (var i = 0; i < 81; i++) - { - filledCells.Add(i); - } - - while (true) - { - for (var i = 0; i < cellsToRemove; i++) - { - var cell = filledCells[_rng.Next(filledCells.Count)]; - - filledCells.Remove(cell); - - puzzle[cell] = 0; - } - - if (_solver.Solve(puzzle).Solved) - { - return; - } - - for (var i = 0; i < 81; i++) - { - if (puzzle[i] == 0) - { - filledCells.Add(i); - - puzzle[i] = copy[i]; - } - } - } - } - - private bool CreateSolvedPuzzle(Span puzzle, int cell = 0) - { - while (_candidates[cell].Count > 0) - { - var candidateIndex = _rng.Next(_candidates[cell].Count); - - var candidate = _candidates[cell][candidateIndex]; - - _candidates[cell].RemoveAt(candidateIndex); - - puzzle[cell] = candidate; - - if (puzzle.IsValidSudoku()) - { - if (cell == 80) - { - return true; - } - - return CreateSolvedPuzzle(puzzle, cell + 1); - } - } - - puzzle[cell] = 0; - - _candidates[cell] = [1, 2, 3, 4, 5, 6, 7, 8, 9]; - - return CreateSolvedPuzzle(puzzle, cell - 1); - } - private void InitialiseCandidates() { for (var i = 0; i < 81; i++) From 76486d6e432ba4d25b871ff6353a7448bb96a027 Mon Sep 17 00:00:00 2001 From: Stevo Date: Sat, 16 Mar 2024 11:52:26 +0000 Subject: [PATCH 4/6] WIP --- src/Sudoku.Tests/GeneratorTests.cs | 11 +++++++++++ src/Sudoku/Generator.cs | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/src/Sudoku.Tests/GeneratorTests.cs b/src/Sudoku.Tests/GeneratorTests.cs index 0149339..d9d63b0 100644 --- a/src/Sudoku.Tests/GeneratorTests.cs +++ b/src/Sudoku.Tests/GeneratorTests.cs @@ -17,4 +17,15 @@ public void GeneratesAValidSudokuPuzzle() // This test is asserted by your eyes. } + + [Fact] + public void GeneratesManyValidSudokuPuzzles() + { + for (var i = 0; i < 1000; i++) + { + var generator = new Generator(); + + generator.Generate(); + } + } } \ No newline at end of file diff --git a/src/Sudoku/Generator.cs b/src/Sudoku/Generator.cs index e60b229..851a813 100644 --- a/src/Sudoku/Generator.cs +++ b/src/Sudoku/Generator.cs @@ -74,6 +74,11 @@ private bool FillPositions(int cluesToLeave, int position = 0) } } + if (position == 0) + { + return false; + } + _puzzle[cell] = -1; _candidates[cell] = [1, 2, 3, 4, 5, 6, 7, 8, 9]; From e7b143228fb1c5a388ffae1e56eec4e0a9071706 Mon Sep 17 00:00:00 2001 From: Stevo Date: Sat, 16 Mar 2024 12:27:27 +0000 Subject: [PATCH 5/6] WIP --- src/Sudoku/Generator.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/Sudoku/Generator.cs b/src/Sudoku/Generator.cs index 851a813..6f8deb7 100644 --- a/src/Sudoku/Generator.cs +++ b/src/Sudoku/Generator.cs @@ -60,14 +60,9 @@ private bool FillPositions(int cluesToLeave, int position = 0) if (_puzzle.IsValidSudoku()) { - if (position + 1 == cluesToLeave) + if (position == cluesToLeave - 1) { - if (_solver.Solve(_puzzle).Solved) - { - return true; - } - - return false; + return _solver.Solve(_puzzle).Solved; } return FillPositions(cluesToLeave, position + 1); From 11f9bf32d549832985829735238501c5f4d5dab2 Mon Sep 17 00:00:00 2001 From: Stevo Date: Sat, 16 Mar 2024 12:49:12 +0000 Subject: [PATCH 6/6] WIP --- src/Sudoku.Tests/GeneratorTests.cs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/Sudoku.Tests/GeneratorTests.cs b/src/Sudoku.Tests/GeneratorTests.cs index d9d63b0..0149339 100644 --- a/src/Sudoku.Tests/GeneratorTests.cs +++ b/src/Sudoku.Tests/GeneratorTests.cs @@ -17,15 +17,4 @@ public void GeneratesAValidSudokuPuzzle() // This test is asserted by your eyes. } - - [Fact] - public void GeneratesManyValidSudokuPuzzles() - { - for (var i = 0; i < 1000; i++) - { - var generator = new Generator(); - - generator.Generate(); - } - } } \ No newline at end of file