Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
0dd21db
Moved the succes condition for solveRec up before skipping lowest can…
IronicJuice Sep 25, 2024
4473955
Implemented IsSatisfactory. Changed the easy board in SolverTests to …
IronicJuice Sep 25, 2024
3d0756a
Added documentation for IsSatisfactory
IronicJuice Sep 25, 2024
2cdf711
changed the solve check to actually use the function from Board
IronicJuice Sep 25, 2024
8ba8763
spelling error
IronicJuice Sep 25, 2024
c64bff3
Added a validate function to Board, and first implementation of Solve…
IronicJuice Sep 26, 2024
40401e3
Removed solutionCount for now. May not be practical to implement
IronicJuice Sep 26, 2024
ff885e7
Created FindSolutionsTest. It fails, as FindSolutions does not purge …
IronicJuice Sep 26, 2024
feaa9c5
Implemented Hash for Board and Cell, and used them in the Solver
IronicJuice Oct 3, 2024
48956ca
Added Equals to Cell. Tests still fail when comparing boards
IronicJuice Oct 3, 2024
c58a977
Fixed the faulty cell comparison in Board.Equals()
IronicJuice Oct 8, 2024
35e633d
Changed the tests for the solver to actually be passable
IronicJuice Oct 8, 2024
2e9b8c0
Implemented a limit to number of solutions
IronicJuice Oct 8, 2024
40a8fd2
Implemented a return limit so the correct number of solutions are alw…
IronicJuice Oct 8, 2024
bf0adef
Added ValidateBoardTest()
IronicJuice Oct 8, 2024
e221687
Initialized new project and moved the easy board to Util
IronicJuice Oct 8, 2024
b70c8c4
reverted an accidental commit
IronicJuice Oct 8, 2024
5a73406
Split ValidateBoardTest into 3 tests
IronicJuice Oct 8, 2024
73a7bd8
Changed the default number of solutions returned to int.MaxValue
IronicJuice Oct 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 136 additions & 0 deletions SudoScript.Core.Test/BoardTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
using NUnit.Framework;
using SudoScript.Core;
using SudoScript.Core.Data;

namespace SudoScript.Core.Test;

internal sealed class BoardTests
{
[Test]
public void ValidateBoardInvalidRuleTest()
{
Board board = Util.CreateStandardEmpty();
board[5, 1].Digit = 2;
board[4, 8].Digit = 7;
board[5, 2].Digit = 2;
board[8, 4].Digit = 4;

Assert.That(board.Validate(), Is.False);
}

[Test]
public void ValidateBoardValidRuleTest()
{
Board board = Util.CreateStandardEmpty();
board[5, 1].Digit = 2;
board[4, 8].Digit = 7;
board[8, 4].Digit = 4;
board[5, 2].Digit = 3;

Assert.That(board.Validate(), Is.True);
}

[Test]
public void ValidateBoardNoCandidatesTest()
{
Board board = Util.CreateStandardEmpty();

board[9, 9].EliminateCandidate(1);
board[9, 9].EliminateCandidate(2);
board[9, 9].EliminateCandidate(3);
board[9, 9].EliminateCandidate(4);
board[9, 9].EliminateCandidate(5);
board[9, 9].EliminateCandidate(6);
board[9, 9].EliminateCandidate(7);
board[9, 9].EliminateCandidate(8);
board[9, 9].EliminateCandidate(9);

Assert.That(board.Validate(), Is.False);
}

[Test]
public void BoardEqualsTest()
{
Board board = Util.CreateStandardEmpty();
board[5, 1].Digit = 2;
board[4, 8].Digit = 7;
board[5, 2].Digit = 3;
board[8, 4].Digit = 4;

Board board2 = Util.CreateStandardEmpty();
board2[5, 1].Digit = 2;
board2[4, 8].Digit = 7;
board2[5, 2].Digit = 3;
board2[8, 4].Digit = 4;

Assert.That(board2, Is.EqualTo(board));
}

[Test]
public void BoardNotEqualsTest()
{
Board board = Util.CreateStandardEmpty();
board[1, 1].Digit = 2;
board[4, 8].Digit = 7;
board[5, 3].Digit = 3;
board[8, 4].Digit = 4;

Board board2 = Util.CreateStandardEmpty();
board2[1, 1].Digit = 1;
board2[4, 8].Digit = 7;
board2[5, 3].Digit = 3;
board2[8, 4].Digit = 4;

Assert.That(board2, Is.Not.EqualTo(board));
}

[Test]
public void BoardHashTest()
{
Board board = Util.CreateStandardEmpty();
board[5, 1].Digit = 2;
board[4, 8].Digit = 7;
board[5, 2].Digit = 3;
board[8, 4].Digit = 4;

Board board2 = Util.CreateStandardEmpty();
board2[5, 1].Digit = 2;
board2[4, 8].Digit = 7;
board2[5, 2].Digit = 3;
board2[8, 4].Digit = 4;

Assert.That(board2.GetHashCode(), Is.EqualTo(board.GetHashCode()));
}

[Test]
public void BoardHashNotEqualTest()
{
Board board = Util.CreateStandardEmpty();
board[5, 1].Digit = 2;
board[4, 8].Digit = 7;
board[5, 2].Digit = 3;
board[8, 4].Digit = 4;

Board board2 = Util.CreateStandardEmpty();
board2[5, 1].Digit = 2;
board2[4, 9].Digit = 7;
board2[5, 2].Digit = 3;
board2[8, 4].Digit = 4;

Assert.That(board2.GetHashCode(), Is.Not.EqualTo(board.GetHashCode()));
}

[Test]
public void CloneTest()
{
Board board = Util.CreateStandardEmpty();
board[5, 1].Digit = 2;
board[4, 8].Digit = 7;
board[5, 2].Digit = 3;
board[8, 4].Digit = 4;

Board clonedBoard = board.Clone();

Assert.That(board, Is.EqualTo(clonedBoard));
}
}
85 changes: 74 additions & 11 deletions SudoScript.Core.Test/SolverTests.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,14 @@
using NUnit.Framework;
using StandardLibrary;
using SudoScript.Core;
using SudoScript.Core.Data;
using System.Data;

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/
Expand All @@ -39,6 +31,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;
Expand All @@ -50,6 +43,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;
Expand All @@ -59,6 +53,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("-------------------------------------------------");
Expand All @@ -68,4 +79,56 @@ 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));
}

[Test]
public void FindSolutionsTwoUniqueCellsTest()
{

Board board = new(new List<Cell>{ new Cell(1, 1), new Cell(1, 2) },
new List<Unit> {
new Unit(new List<CellReference> {
new CellReference(1, 1),
new CellReference(1,2) },
new List<IRule> { new Unique { } })});

List<Board>? boardList = Solver.FindSolutions(board);
List<Board>? randomBoardList = Solver.FindSolutions(board, int.MaxValue, true);

Assert.IsNotNull(boardList);
Assert.That(boardList.Count(), Is.EqualTo(72));
Assert.IsNotNull(randomBoardList);
Assert.That(boardList.Count(), Is.EqualTo(randomBoardList.Count()));
}

[Test]
public void FindNumberOfSolutionsTest()
{
Board board = new(new List<Cell> { new Cell(1, 1), new Cell(1, 2) },
new List<Unit> {
new Unit(new List<CellReference> {
new CellReference(1, 1),
new CellReference(1,2) },
new List<IRule> { new Unique { } })});

List<Board>? boardList = Solver.FindSolutions(board, 25);

Assert.IsNotNull(boardList);
Assert.That(boardList.Count(), Is.EqualTo(25));
}
}
57 changes: 57 additions & 0 deletions SudoScript.Core/Data/Board.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,22 @@ public bool ValidateRules()
return true;
}

public bool Validate()
{
if ((_cells == null) || !this.ValidateRules())
{
return false;
}
foreach (Cell cell in this.Cells())
{
if (cell.CandidateCount < 1)
{
return false;
}
}
return true;
}

public bool IsSolved()
{
return ValidateRules() && Cells().All(c => c.Digit != Cell.EmptyDigit);
Expand Down Expand Up @@ -120,4 +136,45 @@ public override string ToString()

return s.ToString();
}

public override bool Equals(object? obj)
{
if (obj == null || GetType() != obj.GetType())
{
return false;
}

Board other = (Board)obj;

if (other.Cells().Count() != _cells.Count)
{
return false;
}

foreach (Cell cell1 in _cells.Values)
{
if (!other.TryGetCell(cell1.X, cell1.Y, out Cell? cell2))
{
// Compared board does not contain cell with these coordinates
return false;
}
// Compare cells
if (!cell1.Equals(cell2))
{
return false;
}
}

return true;
}

public override int GetHashCode()
{
int hash = 17;
foreach (var cell in _cells.Values)
{
hash = hash * 31 + cell.GetHashCode();
}
return hash;
}
}
42 changes: 42 additions & 0 deletions SudoScript.Core/Data/Cell.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,46 @@ public string ToString(string format)
.Replace("Y", Y.ToString());
}

public override bool Equals(object? obj)
{
if (obj == null || GetType() != obj.GetType())
{
return false;
}

Cell other = (Cell)obj;

// Check coordinates and digit
if (!((this.Y == other.Y) && (this.X == other.X) && (this.Digit == other.Digit)))
{
return false;
}

// Check candidates
for (int i = 1; i <= 9; i++)
{
if (this.HasCandidate(i) != other.HasCandidate(i))
{
return false;
}
if (this.IsGiven != other.IsGiven)
{
return false;
}
}
return true;
}

public override int GetHashCode()
{
unchecked
{
int hash = 17;
hash = hash * 23 + X.GetHashCode();
hash = hash * 23 + Y.GetHashCode();
hash = hash * 23 + Digit.GetHashCode();
return hash;
}
}

}
Loading