From 0dd21db9075deaa5ac5c5346a42aa45449c2d147 Mon Sep 17 00:00:00 2001 From: IronicJuice <81492870+IronicJuice@users.noreply.github.com> Date: Wed, 25 Sep 2024 17:21:17 +0200 Subject: [PATCH 1/5] Moved the succes condition for solveRec up before skipping lowest candidates --- SudoScript.Core/Solver.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SudoScript.Core/Solver.cs b/SudoScript.Core/Solver.cs index ffcccf0..d983c63 100644 --- a/SudoScript.Core/Solver.cs +++ b/SudoScript.Core/Solver.cs @@ -42,14 +42,14 @@ private static bool SolveRec(Board board, [NotNullWhen(true)] out Board? solvedB orderedCells = orderedCells.SkipWhile(c => c.CandidateCount <= 1); // The first cell contains the smallest amount of candidates. int lowestCandidateCount = orderedCells.FirstOrDefault()?.CandidateCount ?? 1; - // Take all cells with the least amount of candidates. - orderedCells = orderedCells.TakeWhile(c => c.CandidateCount == lowestCandidateCount); // If there are no cells with more than 1 candidate, the board is solved. if (lowestCandidateCount == 1) { solvedBoard = board; return true; } + // Take all cells with the least amount of candidates. + orderedCells = orderedCells.TakeWhile(c => c.CandidateCount == lowestCandidateCount); Cell cell = orderedCells.First(); foreach (int candidate in cell.Candidates()) From 4473955f65bd2c398323fe2b4b5752475d38392b Mon Sep 17 00:00:00 2001 From: IronicJuice <81492870+IronicJuice@users.noreply.github.com> Date: Wed, 25 Sep 2024 18:17:53 +0200 Subject: [PATCH 2/5] Implemented IsSatisfactory. Changed the easy board in SolverTests to also be satisfactory. --- SudoScript.Core.Test/SolverTests.cs | 48 ++++++++++++++++++++++------- SudoScript.Core/Solver.cs | 14 +++++++-- 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/SudoScript.Core.Test/SolverTests.cs b/SudoScript.Core.Test/SolverTests.cs index 5797310..a0281b4 100644 --- a/SudoScript.Core.Test/SolverTests.cs +++ b/SudoScript.Core.Test/SolverTests.cs @@ -6,17 +6,7 @@ namespace SudoScript.Core.Test; internal sealed class SolverTests { - [Test()] - public void CanSolveEmptySudoku() - { - Board board = Util.CreateStandardEmpty(); - Assert.DoesNotThrow(() => board = Solver.Solve(board)); - Assert.IsTrue(board.ValidateRules()); - Assert.IsFalse(board.Cells().Any(c => c.Digit == Cell.EmptyDigit)); - } - - [Test] - public void CanSolveGeneratedSudoku() + public Board CreateEasyBoard() { Board board = Util.CreateStandardEmpty(); // Sudoku givens generated by https://sudoku.com/ @@ -39,6 +29,7 @@ public void CanSolveGeneratedSudoku() board[8, 4].Digit = 8; board[3, 5].Digit = 4; + board[4, 7].Digit = 2; board[3, 6].Digit = 6; board[5, 6].Digit = 7; @@ -50,6 +41,7 @@ public void CanSolveGeneratedSudoku() board[8, 7].Digit = 3; board[9, 7].Digit = 5; + board[3, 9].Digit = 1; board[2, 8].Digit = 9; board[4, 8].Digit = 7; board[5, 8].Digit = 4; @@ -59,6 +51,23 @@ public void CanSolveGeneratedSudoku() board[7, 9].Digit = 9; board[8, 9].Digit = 7; + return board; + } + + [Test()] + public void CanSolveEmptySudoku() + { + Board board = Util.CreateStandardEmpty(); + Assert.DoesNotThrow(() => board = Solver.Solve(board)); + Assert.IsTrue(board.ValidateRules()); + Assert.IsFalse(board.Cells().Any(c => c.Digit == Cell.EmptyDigit)); + } + + [Test] + public void CanSolveGeneratedSudoku() + { + Board board = CreateEasyBoard(); + Console.WriteLine(board.ToString()); Console.WriteLine("-------------------------------------------------"); @@ -68,4 +77,21 @@ public void CanSolveGeneratedSudoku() Console.WriteLine(board.ToString()); } + + [Test] + public void IsSatisfactoryTest() + { + Board board = CreateEasyBoard(); + + Assert.IsTrue(Solver.IsSatisfactory(board)); + } + + [Test] + public void IsNotSatisfactoryTest() + { + Board board = Util.CreateStandardEmpty(); + + Assert.IsFalse(Solver.IsSatisfactory(board)); + } + } diff --git a/SudoScript.Core/Solver.cs b/SudoScript.Core/Solver.cs index d983c63..4695c82 100644 --- a/SudoScript.Core/Solver.cs +++ b/SudoScript.Core/Solver.cs @@ -76,9 +76,19 @@ public static Board GenerateSolveable(Board board) throw new NotImplementedException(); } - public static bool IsSatisfactory(Board board) + public static bool IsSatisfactory(Board board) // Certain methods for eliminating candidates using inference are not currently implemented. Implementing them would make this function more acurate. { - throw new NotImplementedException(); + // Eliminate candidates from all rules untill nothing changes. + while (board.EliminateCandidates()); + // If the board is solved, it does not require trial and error. + foreach (Cell cell in board.Cells()) + { + if (cell.CandidateCount > 1) + { + return false; + } + } + return true; } public static bool IsProper(Board board) From 3d0756ade2ef8d00fb940eb570e937b406a2d6df Mon Sep 17 00:00:00 2001 From: IronicJuice <81492870+IronicJuice@users.noreply.github.com> Date: Wed, 25 Sep 2024 18:32:05 +0200 Subject: [PATCH 3/5] Added documentation for IsSatisfactory --- SudoScript.Core/Solver.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/SudoScript.Core/Solver.cs b/SudoScript.Core/Solver.cs index 4695c82..8ea9e47 100644 --- a/SudoScript.Core/Solver.cs +++ b/SudoScript.Core/Solver.cs @@ -76,6 +76,11 @@ public static Board GenerateSolveable(Board board) throw new NotImplementedException(); } + /// + /// Checks if the board can be solved by just using the EliminateCandidates methods from units. + /// + /// + /// True if the board can be solved without trial and error guessing. public static bool IsSatisfactory(Board board) // Certain methods for eliminating candidates using inference are not currently implemented. Implementing them would make this function more acurate. { // Eliminate candidates from all rules untill nothing changes. From 2cdf711ba9ea9d7a939b0dd3d334d6620bca0734 Mon Sep 17 00:00:00 2001 From: IronicJuice <81492870+IronicJuice@users.noreply.github.com> Date: Wed, 25 Sep 2024 18:34:57 +0200 Subject: [PATCH 4/5] changed the solve check to actually use the function from Board --- SudoScript.Core/Solver.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/SudoScript.Core/Solver.cs b/SudoScript.Core/Solver.cs index 8ea9e47..4b1fe80 100644 --- a/SudoScript.Core/Solver.cs +++ b/SudoScript.Core/Solver.cs @@ -86,14 +86,7 @@ public static Board GenerateSolveable(Board board) // Eliminate candidates from all rules untill nothing changes. while (board.EliminateCandidates()); // If the board is solved, it does not require trial and error. - foreach (Cell cell in board.Cells()) - { - if (cell.CandidateCount > 1) - { - return false; - } - } - return true; + return board.IsSolved(); } public static bool IsProper(Board board) From 8ba8763dc7cb83b0430e1061a802ce90697232bc Mon Sep 17 00:00:00 2001 From: IronicJuice <81492870+IronicJuice@users.noreply.github.com> Date: Wed, 25 Sep 2024 18:39:45 +0200 Subject: [PATCH 5/5] spelling error --- SudoScript.Core/Solver.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SudoScript.Core/Solver.cs b/SudoScript.Core/Solver.cs index 4b1fe80..4bc9726 100644 --- a/SudoScript.Core/Solver.cs +++ b/SudoScript.Core/Solver.cs @@ -20,7 +20,7 @@ public static Board Solve(Board board) private static bool SolveRec(Board board, [NotNullWhen(true)] out Board? solvedBoard) { - // Eliminate candidates from all rules untill nothing changes. + // Eliminate candidates from all rules until nothing changes. while (board.EliminateCandidates()) ; // We hit an invalid state, and must backtrack.