def test_play_all_games(self): """Plays multiple games in test data at different puzzle sizes""" for i, puz in enumerate(TEST_PUZZLE_STRINGS): with self.subTest(f"Puzzle {i} (len={len(puz)})"): p = su.SudokuPuzzle(starting_grid=ls.from_string(puz)) s = su.SudokuPuzzle( starting_grid=ls.from_string(TEST_SOLUTION_STRINGS[i])) self.assertFalse(p.is_solved()) self.assertTrue(s.is_solved()) for m in p.next_empty_cell(): p.set(*m, s.get(*m)) self.assertTrue(p.is_solved()) return
def test_class_init_empty(self): """Class init can create an empty grid""" p = su.SudokuPuzzle() for x in range(p.max_value): for y in range(p.max_value): self.assertTrue(p.is_empty(x, y)) return
def test_puzzle_sizes(self): """Different puzzle sizes are supported""" # Initialise all test puzzles, at different sizes for i, puz in enumerate(TEST_PUZZLE_STRINGS): with self.subTest(f"Test Puzzle {i} init (len={len(puz)})"): p = su.SudokuPuzzle(starting_grid=ls.from_string(puz)) self.assertTrue(p.is_valid()) self.assertEqual(len(puz), p.num_cells) return
def test_all_solvers_all_sizes(self): """Solvers can solve different sizes of puzzles""" for m in su.SOLVERS: solver = su.SudokuSolver(method=m) for i, puz in enumerate(TEST_PUZZLE_STRINGS): # Skip backtracking on larger puzzles if m == 'backtracking' and len(puz) > 81: continue with self.subTest(f"Method {m}; Puzzle {i} (len={len(puz)})"): p = su.SudokuPuzzle(starting_grid=ls.from_string(puz)) s = su.SudokuPuzzle( starting_grid=ls.from_string(TEST_SOLUTION_STRINGS[i])) self.assertTrue(p.is_valid()) self.assertFalse(p.is_solved()) self.assertTrue(solver.solve(p)) self.assertTrue(p.is_solved()) self.assertEqual(str(s), str(p)) return
def test_all_solvers_all_puzzles(self): """Test that all available solvers can solve all test puzzles in sudoku.py""" for x in su.SOLVERS: if x == 'backtracking': continue solver = su.SudokuSolver(method=x) for p in su.SAMPLE_PUZZLES: with self.subTest(f"Method {x} on puzzle {p['label']}"): puz = su.SudokuPuzzle( starting_grid=ls.from_string(p['puzzle'])) self.assertTrue(solver.solve(puz)) self.assertTrue(puz.is_solved()) return
def test_box_num_toxy(self): """Conversion of box numbers to (x,y) positions 0 (0,0) 1 (0, 3) 2 (0, 6) 3 (3,0) 4 (3, 3) 5 (3, 6) 6 (6,0) 7 (6, 3) 8 (6, 6) """ with self.subTest("9x9 grid (3x3 box)"): correct_values = [ (0, 0), (0, 3), (0, 6), (3, 0), (3, 3), (3, 6), (6, 0), (6, 3), (6, 6), ] p = su.SudokuPuzzle(grid_size=9) for i in range(p.max_value): with self.subTest(f"Cage {i} at {correct_values[i]}"): self.assertEqual(correct_values[i], p.box_num_to_xy(i)) self.assertEqual(i, p.box_xy_to_num(*correct_values[i])) with self.subTest("4x4 grid (2x2 box)"): correct_values = [ (0, 0), (0, 2), (2, 0), (2, 2), ] p = su.SudokuPuzzle(grid_size=4) for i in range(p.max_value): with self.subTest(f"Cage {i} at {correct_values[i]}"): self.assertEqual(correct_values[i], p.box_num_to_xy(i)) self.assertEqual(i, p.box_xy_to_num(*correct_values[i])) return
def setUp(self): self.p = su.SudokuPuzzle(su.DEFAULT_SUDOKU_SIZE, EASY_PUZZLE) self.s = su.SudokuPuzzle(su.DEFAULT_SUDOKU_SIZE, EASY_SOLUTION) self.legal_moves = EASY_MOVES_LEGAL self.illegal_moves = EASY_MOVES_ILLEGAL return
def setUp(self): """Handy to have an unsolved (p) and already solved puzzle (s) for later tests""" self.p = su.SudokuPuzzle(su.DEFAULT_SUDOKU_SIZE, EASY_PUZZLE) self.s = su.SudokuPuzzle(su.DEFAULT_SUDOKU_SIZE, EASY_SOLUTION) return