def assert_expected_solver_output(self, puzzle, expected_done, solution_count, solution=None, constraints=None): puzzle_grid = SudokuGrid(puzzle) my_solution, done, info = SudokuSolver().solveSudoku(puzzle_grid, verbose=False, constraints=constraints) #self.assertEqual(info,"") self.assertEqual(done, expected_done) self.assertEqual(info['solutions'], solution_count) if solution: self.assertTrue(SudokuGrid(solution) == my_solution, msg=f'solution does not match. Actual: {my_solution}')
def test_get_indices_for_6x6_regions(self): grid = SudokuGrid(size=6) regions = grid.get_indices_for_regions() self.assertEqual(len(regions), 6) self.assertEqual(regions[0], [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]) self.assertEqual(regions[5], [(4, 3), (4, 4), (4, 5), (5, 3), (5, 4), (5, 5)])
def test_candidates_advanced(self): grid = [ [0, 8, 0, 0, 0, 1, 2, 0, 6], [0, 0, 0, 0, 2, 0, 0, 0, 0], [0, 2, 0, 3, 0, 5, 0, 4, 0], [0, 6, 0, 0, 1, 0, 9, 0, 0], [0, 0, 2, 0, 5, 0, 4, 0, 0], [0, 0, 8, 0, 0, 0, 0, 1, 0], [0, 3, 0, 7, 0, 4, 0, 5, 0], [0, 0, 0, 0, 3, 0, 0, 0, 0], [4, 0, 6, 1, 0, 0, 0, 8, 0] ] # June 7 Extreme 'https://www.sudokuwiki.org s = Sudoku(SudokuGrid().with_matrix(grid)) candidates = [ [{9, 3, 5, 7}, set(), {3, 4, 5, 7, 9}, {9, 4}, {9, 4, 7}, set(), set(), {9, 3, 7}, set()], [{1, 3, 5, 6, 7, 9}, {1, 4, 5, 7, 9}, {1, 3, 4, 5, 7, 9}, {8, 9, 4, 6}, set(), {8, 9, 6, 7}, {1, 3, 5, 7, 8}, {9, 3, 7}, {1, 3, 5, 7, 8, 9}], [{1, 9, 6, 7}, set(), {1, 9, 7}, set(), {8, 9, 6, 7}, set(), {8, 1, 7}, set(), {8, 1, 9, 7}], [{3, 5, 7}, set(), {3, 4, 5, 7}, {8, 2, 4}, set(), {8, 2, 3, 7}, set(), {2, 3, 7}, {2, 3, 5, 7, 8}], [{1, 3, 9, 7}, {1, 9, 7}, set(), {8, 9, 6}, set(), {3, 6, 7, 8, 9}, set(), {3, 6, 7}, {8, 3, 7}], [{9, 3, 5, 7}, {9, 4, 5, 7}, set(), {9, 2, 4, 6}, {9, 4, 6, 7}, {2, 3, 6, 7, 9}, {3, 5, 6, 7}, set(), {2, 3, 5, 7}], [{8, 1, 2, 9}, set(), {1, 9}, set(), {8, 9, 6}, set(), {1, 6}, set(), {1, 2, 9}], [{1, 2, 5, 7, 8, 9}, {1, 5, 9, 7}, {1, 5, 9, 7}, {2, 5, 6, 8, 9}, set(), {8, 9, 2, 6}, {1, 6, 7}, {9, 2, 6, 7}, {1, 2, 4, 7, 9}], [set(), {9, 5, 7}, set(), set(), {9}, {9, 2}, {3, 7}, set(), {9, 2, 3, 7}] ] self.assertTrue(self.candidates_equal(s.grid.candidates, candidates)) inds = [(i, 0) for i in range(9)] #self.assertEqual(s.get_pairs(inds), [([(6, 0), (7, 0)], (2, 8))]) uniques = s.get_unique(inds, type=[2])[0] uniques[0].sort() self.assertEqual(uniques, ([(6, 0), (7, 0)], (2, 8)) ) grid = [ [0, 0, 0, 0, 0, 1, 0, 3, 0], [2, 3, 1, 0, 9, 0, 0, 0, 0], [0, 6, 5, 0, 0, 3, 1, 0, 0], [6, 7, 8, 9, 2, 4, 3, 0, 0], [1, 0, 3, 0, 5, 0, 0, 0, 6], [0, 0, 0, 1, 3, 6, 7, 0, 0], [0, 0, 9, 3, 6, 0, 5, 7, 0], [0, 0, 6, 0, 1, 9, 8, 4, 3], [3, 0, 0, 0, 0, 0, 0, 0, 0] ] # https://www.sudokuwiki.org/Hidden_Candidates#HP s = Sudoku(SudokuGrid().with_matrix(grid)) inds = [(0, j) for j in range(9)] uniques = s.get_unique(inds, type=[3])[0] uniques[0].sort() self.assertEqual(uniques, ([(0, 3), (0, 6), (0, 8)], (2, 5, 6)) ) s.grid.candidates[0][8] = {2, 5} inds = [(i, 8) for i in range(9)] uniques = s.get_unique(inds, type=[3])[0] uniques[0].sort() self.assertEqual(uniques, ([(1, 8), (2, 8), (5, 8)], (4, 8, 7)) )
class SudokuSolver: grid: SudokuGrid = SudokuGrid() def load_grid(self, sudoku_grid): self.grid.load(sudoku_grid) def print_grid(self): self.grid.print() def main(self): grid = [ [4, 0, 0, 0, 0, 5, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 9, 8], [3, 0, 0, 0, 8, 2, 4, 0, 0], [0, 0, 0, 1, 0, 0, 0, 8, 0], [9, 0, 3, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 3, 0, 6, 7, 0], [0, 5, 0, 0, 0, 9, 0, 0, 0], [0, 0, 0, 2, 0, 0, 9, 0, 7], [6, 4, 0, 3, 0, 0, 0, 0, 0], ] self.load_grid(grid) # self.solve() self.print_grid()
def test_valid_9x9_grid_with_zeros(self): grid = SudokuGrid( '100020400035040900704000001800000000091032080000100097070900600000000000000450000' ) self.assertEqual(grid.size, 9) self.assertEqual( str(grid), '100020400035040900704000001800000000091032080000100097070900600000000000000450000' )
def test_valid_9x9_grid_with_dots(self): grid = SudokuGrid( '1...2.4...35.4.9..7.4.....18.........91.32.8....1...97.7.9..6..............45....' ) self.assertEqual(grid.size, 9) self.assertEqual( str(grid), '100020400035040900704000001800000000091032080000100097070900600000000000000450000' )
def test_impossible(self): # impossible puzzles = [ '.....5.8....6.1.43..........1.5........1.6...3.......553.....61........4.........', '12.......34...............5...........5..........................................', '11.......34...............5...........5..........................................', ] for puzzle in puzzles: puzzle = SudokuGrid(puzzle) s = Sudoku(puzzle) s.flush_candidates() self.assertFalse(s.check_possible()[0]) # possible puzzles = [ '280070309600104007745080006064830100102009800000201930006050701508090020070402050', '000010030009005008804006025000000600008004000120087000300900200065008000900000000', '1.....................................5..........................................', ] for puzzle in [puzzles[1]]: puzzle = SudokuGrid(puzzle) s = Sudoku(puzzle) s.flush_candidates() self.assertTrue(s.check_possible()[0])
def test_get_region_inds_with_6x6(self): grid = SudokuGrid(size=6) self.assertEqual(grid.get_region_inds(0, 0), [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]) self.assertEqual(grid.get_region_inds(1, 2), [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]) self.assertEqual(grid.get_region_inds(4, 3), [(4, 3), (4, 4), (4, 5), (5, 3), (5, 4), (5, 5)]) self.assertEqual(grid.get_region_inds(5, 5), [(4, 3), (4, 4), (4, 5), (5, 3), (5, 4), (5, 5)])
class SudokuGridTest(unittest.TestCase): g = SudokuGrid() def setUp(self): grid = [ [4, 0, 0, 0, 0, 5, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 9, 8], [3, 0, 0, 0, 8, 2, 4, 0, 0], [0, 0, 0, 1, 0, 0, 0, 8, 0], [9, 0, 3, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 3, 0, 6, 7, 0], [0, 5, 0, 0, 0, 9, 0, 0, 0], [0, 0, 0, 2, 0, 0, 9, 0, 7], [6, 4, 0, 3, 0, 0, 0, 0, 0], ] self.g.load(grid) def test_value_is_already_present(self): self.assertFalse(self.g.is_possible(0, 0, 4)) def test_in_line_is_true(self): self.assertTrue(self.g.is_possible(1, 0, 9)) def test_in_line_is_false(self): self.assertFalse(self.g.is_possible(1, 0, 5)) def test_in_column_is_true(self): self.assertTrue(self.g.is_possible(0, 1, 5)) def test_in_column_is_false(self): self.assertFalse(self.g.is_possible(0, 1, 6)) def test_in_square_is_true(self): self.assertTrue(self.g.is_possible(1, 1, 2)) def test_in_square_is_false(self): self.assertFalse(self.g.is_possible(1, 1, 3)) def test_base_printing(self): raised = False try: self.g.print() except: raised = True self.assertFalse(raised, "Printing should not raise an exception")
def test_find_options(self): grid = [ [5, 3, 0, 0, 7, 0, 0, 0, 0], [6, 0, 0, 1, 9, 5, 0, 0, 0], [0, 9, 8, 0, 0, 0, 0, 6, 0], [8, 0, 0, 0, 6, 0, 0, 0, 3], [4, 0, 0, 8, 0, 3, 0, 0, 1], [7, 0, 0, 0, 2, 0, 0, 0, 6], [0, 6, 0, 0, 0, 0, 2, 8, 0], [0, 0, 0, 4, 1, 9, 0, 0, 5], [0, 0, 0, 0, 8, 0, 0, 7, 9] ] s = Sudoku(SudokuGrid().with_matrix(grid)) self.assertEqual(s.find_options(0, 2), {1, 2, 4}) self.assertEqual(s.find_options(4, 4), {5}) self.assertEqual(s.find_options(5, 1), {1, 5}) self.assertEqual(s.find_options(8, 6), {1, 3, 4, 6})
class SudokuGridTestFirstIssue(unittest.TestCase): g = SudokuGrid() def setUp(self): grid = [ [4, 2, 1, 0, 0, 5, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 9, 8], [3, 0, 0, 0, 8, 2, 4, 0, 0], [0, 0, 0, 1, 0, 0, 0, 8, 0], [9, 0, 3, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 3, 0, 6, 7, 0], [0, 5, 0, 0, 0, 9, 0, 0, 0], [0, 0, 0, 2, 0, 0, 9, 0, 7], [6, 4, 0, 3, 0, 0, 0, 0, 0], ] self.g.load(grid) def test_is_false(self): self.assertFalse(self.g.is_possible(4, 0, 2))
def test_get_region_inds_with_9x9(self): grid = SudokuGrid(size=9) self.assertEqual(grid.get_region_inds(0, 0), [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]) self.assertEqual(grid.get_region_inds(2, 2), [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]) self.assertEqual(grid.get_region_inds(6, 6), [(6, 6), (6, 7), (6, 8), (7, 6), (7, 7), (7, 8), (8, 6), (8, 7), (8, 8)]) self.assertEqual(grid.get_region_inds(8, 8), [(6, 6), (6, 7), (6, 8), (7, 6), (7, 7), (7, 8), (8, 6), (8, 7), (8, 8)])
def test_candidates(self): grid = [ [5, 3, 0, 0, 7, 0, 0, 0, 0], [6, 0, 0, 1, 9, 5, 0, 0, 0], [0, 9, 8, 0, 0, 0, 0, 6, 0], [8, 0, 0, 0, 6, 0, 0, 0, 3], [4, 0, 0, 8, 0, 3, 0, 0, 1], [7, 0, 0, 0, 2, 0, 0, 0, 6], [0, 6, 0, 0, 0, 0, 2, 8, 0], [0, 0, 0, 4, 1, 9, 0, 0, 5], [0, 0, 0, 0, 8, 0, 0, 7, 9] ] candidates = [ [set(), set(), {1, 2, 4}, {2, 6}, set(), {8, 2, 4, 6}, {8, 1, 4, 9}, {1, 2, 4, 9}, {8, 2, 4}], [set(), {2, 4, 7}, {2, 4, 7}, set(), set(), set(), {8, 3, 4, 7}, {2, 3, 4}, {8, 2, 4, 7}], [{1, 2}, set(), set(), {2, 3}, {3, 4}, {2, 4}, {1, 3, 4, 5, 7}, set(), {2, 4, 7}], [set(), {1, 2, 5}, {1, 2, 5, 9}, {9, 5, 7}, set(), {1, 4, 7}, {9, 4, 5, 7}, {9, 2, 4, 5}, set()], [set(), {2, 5}, {9, 2, 5, 6}, set(), {5}, set(), {9, 5, 7}, {9, 2, 5}, set()], [set(), {1, 5}, {1, 3, 5, 9}, {9, 5}, set(), {1, 4}, {8, 9, 4, 5}, {9, 4, 5}, set()], [{1, 3, 9}, set(), {1, 3, 4, 5, 7, 9}, {3, 5, 7}, {3, 5}, {7}, set(), set(), {4}], [{2, 3}, {8, 2, 7}, {2, 3, 7}, set(), set(), set(), {3, 6}, {3}, set()], [{1, 2, 3}, {1, 2, 4, 5}, {1, 2, 3, 4, 5}, {2, 3, 5, 6}, set(), {2, 6}, {1, 3, 4, 6}, set(), set()] ] s = Sudoku(SudokuGrid().with_matrix(grid)) self.assertTrue(self.candidates_equal(s.grid.candidates, candidates)) # test uniques inds = [(0, j) for j in range(9)] # no unique candidates #self.assertEqual(s.get_unique(inds), []) self.assertEqual(s.get_unique(inds, type=[1]), [] ) inds = [(7, j) for j in range(9)] # uniques: 8 at (7, 1) and 6 at (7, 6) #self.assertEqual(s.get_unique(inds), [([(7, 6)], [6]), ([(7, 1)], [8])] ) #[(6, (7, 6)), (8, (7, 1))]) self.assertEqual(s.get_unique(inds, type=[1]), [([(7, 6)], [6]), ([(7, 1)], [8])] ) inds = s.grid.get_region_inds(5, 6) # middle right box. unique 8 at (5,6) #self.assertEqual(s.get_unique(inds), [([(5, 6)], [8])]) self.assertEqual(s.get_unique(inds, type=[1]), [([(5, 6)], [8])] ) # test erase function s.place_and_erase(0, 2, 1, constraint_prop=False) self.assertEqual(s.grid.candidates[0], [set(), set(), set(), {2, 6}, set(), {8, 2, 4, 6}, {8, 4, 9}, {2, 4, 9}, {8, 2, 4}]) col = [s.grid.candidates[i][2] for i in range(9)] self.assertEqual(col, [set(), {2, 4, 7}, set(), {2, 5 ,9}, {2, 5, 6, 9}, {3, 5, 9}, {3, 4, 5, 7, 9}, {2, 3, 7}, {2, 3, 4, 5}])
def test_get_indices_for_9x9_regions(self): grid = SudokuGrid(size=9) regions = grid.get_indices_for_regions() self.assertEqual(len(regions), 9) self.assertEqual(regions[4], [(3, 3), (3, 4), (3, 5), (4, 3), (4, 4), (4, 5), (5, 3), (5, 4), (5, 5)])
def test_invalid_length_string(self): with self.assertRaises(Exception): SudokuGrid('123443213412214300')
def test_invalid_digits(self): with self.assertRaises(Exception): SudokuGrid('1234432134122156')
def test_empty_grid(self): grid = SudokuGrid(size=4) self.assertEqual(grid.size, 4) self.assertEqual(str(grid), '0000000000000000')
def test_grid_list_for_6x6(self): grid = SudokuGrid(size=6) self.assertEqual(len(grid.grid_list), 6) self.assertEqual(len(grid.grid_list[0]), 6)
def test_invalid_size(self): with self.assertRaises(Exception) as cm: SudokuGrid(size=10) self.assertEqual(str(cm.exception), 'Size parameter must be 3..9')
def test_valid_4x4_grid(self): grid = SudokuGrid('1234432134122143') self.assertEqual(grid.size, 4) self.assertEqual(str(grid), '1234432134122143')