Solver working, basic test cases
This commit is contained in:
		
							parent
							
								
									999d97f565
								
							
						
					
					
						commit
						75da119da9
					
				
					 4 changed files with 270 additions and 6 deletions
				
			
		|  | @ -1,5 +1,7 @@ | |||
| package sudoku; | ||||
| 
 | ||||
| import java.util.stream.IntStream; | ||||
| 
 | ||||
| public class Solver implements SudokuSolver { | ||||
|     private int[][] board; | ||||
| 
 | ||||
|  | @ -16,17 +18,200 @@ public class Solver implements SudokuSolver { | |||
|     } | ||||
| 
 | ||||
|     public boolean solve() { | ||||
|         return solve(0, 0); | ||||
|     } | ||||
| 
 | ||||
|     public Boolean isSolved() { | ||||
|     /** | ||||
|      * Resets the board to all zeros | ||||
|      */ | ||||
|     public void reset() { | ||||
|         board = new int[9][9]; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Recursive helper method for solve() | ||||
|      *  | ||||
|      * @param row row to solve | ||||
|      * @param col column to solve | ||||
|      * @return true if solved | ||||
|      */ | ||||
|     private boolean solve(int row, int col) { | ||||
|         if (row < 0 || row > 9 || col < 0 || col > 9) { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         if (row == 9) { | ||||
|             row = 0; | ||||
|             if (++col == 9) { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (board[row][col] != 0) { | ||||
|             return solve(row + 1, col); | ||||
|         } | ||||
| 
 | ||||
|         for (int val = 1; val <= 9; ++val) { | ||||
|             if (legal(row, col, val)) { | ||||
|                 board[row][col] = val; | ||||
|                 if (solve(row + 1, col)) { | ||||
|                     return true; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         board[row][col] = 0; | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     public boolean legal(int row, int col, int nbr) { | ||||
|     /** | ||||
|      * Randomizes the board. This guarantees a solvable board. | ||||
|      */ | ||||
|     public void randomizeBoard() { | ||||
|         this.reset(); | ||||
|         for (int i = 0; i < 9; ++i) { | ||||
|             int row = (int) (Math.random() * 9); | ||||
|             int col = (int) (Math.random() * 9); | ||||
|             int val = (int) (Math.random() * 9) + 1; | ||||
|             if (legal(row, col, val)) { | ||||
|                 board[row][col] = val; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Sets the value of the board at the given position | ||||
|      *  | ||||
|      * @param row row to set | ||||
|      * @param col column to set | ||||
|      * @param val value to set | ||||
|      */ | ||||
|     public void setPos(int row, int col, int val) { | ||||
|         if (row < 9 && col < 9) { | ||||
|             board[row][col] = val; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Checks if val is legal in the given row, column, and 3x3 box | ||||
|      *  | ||||
|      * @param row row to check | ||||
|      * @param col column to check | ||||
|      * @param val value to check | ||||
|      * @return true if val is legal | ||||
|      */ | ||||
|     public boolean legal(int row, int col, int val) { | ||||
|         if (row < 0 || row >= 9 || col < 0 || col >= 9 || val < 1 || val > 9) { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         // Check if val is already in col | ||||
|         for (int i = 0; i < 9; ++i) { | ||||
|             if (val == board[i][col]) { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Check if val is already in row | ||||
|         for (int j = 0; j < 9; ++j) { | ||||
|             if (val == board[row][j]) { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Check the 3x3 box | ||||
|         int boxRowOffset = (row / 3) * 3; | ||||
|         int boxColOffset = (col / 3) * 3; | ||||
| 
 | ||||
|         for (int k = 0; k < 3; ++k) { | ||||
|             for (int m = 0; m < 3; ++m) { | ||||
|                 if (val == board[boxRowOffset + k][boxColOffset + m]) { | ||||
|                     return false; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // None of the above failed, so it is legal | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     public boolean isSolved() { | ||||
|         return isSolved(0, 0); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Recursive helper method for isSolved() | ||||
|      *  | ||||
|      * @param row | ||||
|      * @param col | ||||
|      * @return | ||||
|      */ | ||||
|     private boolean isSolved(int row, int col) { | ||||
|         // If we are at the 9th row and 0th column (the last cell), we are done | ||||
|         if (row == 9) { | ||||
|             row = 0; | ||||
|             if (++col == 9) { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // If we find a zero, the board is not solved | ||||
|         if (board[row][col] == 0) { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         for (int i = 0; i < 9; ++i) { | ||||
|             // Checks if there is a duplicate in the row | ||||
|             if (i != row && board[i][col] == board[row][col]) { | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             // Checks if there is a duplicate in the column | ||||
|             if (i != col && board[row][i] == board[row][col]) { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Checks if there is a duplicate in the 3x3 box | ||||
|         int boxRowOffset = (row / 3) * 3; | ||||
|         int boxColOffset = (col / 3) * 3; | ||||
| 
 | ||||
|         for (int k = 0; k < 3; ++k) { | ||||
|             for (int m = 0; m < 3; ++m) { | ||||
|                 int r = boxRowOffset + k; | ||||
|                 int c = boxColOffset + m; | ||||
|                 if ((r != row || c != col) && board[r][c] == board[row][col]) { | ||||
|                     return false; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns a string representation of the board | ||||
|      *  | ||||
|      * @return String representation of the board | ||||
|      */ | ||||
|     // Not particularly pretty, but it works | ||||
|     public String toString() { | ||||
|         final String divider = "-------+--------+--------\n"; | ||||
|         StringBuilder sb = new StringBuilder(); | ||||
|         sb.append(divider); | ||||
|         int rowcount = 0; | ||||
|         for (int[] row : board) { | ||||
|             int colcount = 0; | ||||
|             sb.append("| "); | ||||
|             for (int val : row) { | ||||
|                 colcount++; | ||||
|                 sb.append(val); | ||||
|                 sb.append(colcount % 3 == 0 ? " | " : " "); | ||||
|             } | ||||
|             rowcount++; | ||||
|             sb.append(rowcount % 3 == 0 ? "\n" : ""); | ||||
|             sb.append(rowcount % 3 == 0 ? divider : "\n"); | ||||
|         } | ||||
|         return sb.toString(); | ||||
|     } | ||||
| } | ||||
|  | @ -2,6 +2,11 @@ package sudoku; | |||
| 
 | ||||
| public class SolverMain { | ||||
|     public static void main(String[] args) { | ||||
|         System.out.println("Hello world!"); | ||||
|         Solver s = new Solver(); | ||||
|         System.out.println(s.toString()); | ||||
|         s.randomizeBoard(); | ||||
|         System.out.println(s.toString()); | ||||
|         s.solve(); | ||||
|         System.out.println(s.toString()); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,12 +1,86 @@ | |||
| package sudoku; | ||||
| 
 | ||||
| import org.junit.jupiter.api.Disabled; | ||||
| import org.junit.jupiter.api.Test; | ||||
| import static org.junit.jupiter.api.Assertions.*; | ||||
| import java.util.stream.IntStream; | ||||
| 
 | ||||
| class SolverTest { | ||||
|     @Test void boardTest() { | ||||
|     @Test | ||||
|     void constructorTest() { | ||||
|         Solver solver = new Solver(); | ||||
|         solver.solve(); | ||||
|         assertNotNull(solver); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     void setBoardTest() { | ||||
|         Solver solver = new Solver(); | ||||
|         int[][] board = new int[9][9]; | ||||
|         solver.setBoard(board); | ||||
|         assertEquals(board, solver.getBoard()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     void randomizeBoardTest() { | ||||
|         int[][] board = new int[9][9]; | ||||
|         Solver solver = new Solver(); | ||||
|         solver.randomizeBoard(); | ||||
|         assertNotEquals(board, solver.getBoard()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     void legalTest() { | ||||
|         Solver solver = new Solver(); | ||||
|         assertTrue(solver.legal(0, 0, 1)); | ||||
|         solver.setPos(0, 0, 1); | ||||
| 
 | ||||
|         IntStream.range(0, 9).forEach(i -> { | ||||
|             assertFalse(solver.legal(0, i, 1)); | ||||
|             assertFalse(solver.legal(i, 0, 1)); | ||||
|         }); | ||||
| 
 | ||||
|         assertTrue(solver.legal(5, 5, 1)); | ||||
|         assertTrue(solver.legal(8, 8, 9)); | ||||
|         assertTrue(solver.legal(8, 8, 1)); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     void solverTest() { | ||||
|         Solver solver = new Solver(); | ||||
|         assertFalse(solver.isSolved()); | ||||
|         assertTrue(solver.solve()); | ||||
|         assertTrue(solver.isSolved()); | ||||
| 
 | ||||
|         solver.reset(); | ||||
|         solver.randomizeBoard(); | ||||
|         assertFalse(solver.isSolved()); | ||||
|         assertTrue(solver.solve()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     void resetTest() { | ||||
|         Solver solver = new Solver(); | ||||
|         assertTrue(solver.solve()); | ||||
|         solver.randomizeBoard(); | ||||
|         solver.reset(); | ||||
|         assertFalse(solver.isSolved()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     void legalWithInvalidInputsTest() { | ||||
|         Solver solver = new Solver(); | ||||
|         assertFalse(solver.legal(-1, 0, 1)); | ||||
|         assertFalse(solver.legal(0, -1, 1)); | ||||
|         assertFalse(solver.legal(0, 0, -1)); | ||||
|         assertFalse(solver.legal(0, 0, 10)); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     @Disabled | ||||
|     void unsolvableTest() { | ||||
|         Solver solver = new Solver(); | ||||
|         solver.setPos(0, 0, 1); | ||||
|         solver.setPos(0, 1, 1); | ||||
|         assertFalse(solver.solve()); | ||||
|     } | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Imbus
						Imbus