def test_peers() -> None: """Peers for non diagonal board for 'A1'""" peer = 'A1' a1_peers = ['A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'B1', 'B2', 'B3', 'C1', 'C2', 'C3', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1'] board = SB() assert board.peers(peer) == set(a1_peers)
def test_performance_beta(board_size): """ Tests time performance of local hill climbing using restarts Displays the results :param board_size: size of a board to test on """ # init test board board = Board(size=board_size) print( f'\nTesting overall time performance of beta hill climbing with board of size {board_size}:' ) if not board.set_init_state(): print('Failed to load the board, quitting..') return # measure times solver = CustomBetaHC(board, 1, MAX_ITER_BETA_STATIC, N_PROB_STATIC, BETA_PROB_STATIC, stop_if_found=True) times = _engine.test_time_perfect(solver, SOLUTIONS_NUM) # print results _print_times(*times)
def test_beta_prob(board_size): """ Tests beta probability for beta hill climbing Displays the results :param board_size: size of a board to test on """ # init test board board = Board(size=board_size) print( f'\nTesting steps distribution for basic hill climb with board of size {board_size}:' ) if not board.set_init_state(): print('Failed to load the board, quitting..') return # start with probability of 30% and decrease beta = 0.3 while True: print(f'[beta probability = {beta:.2f}]:') # analyze current steps distribution solver = CustomBetaHC(board, RESTARTS_BETA_STATIC, MAX_ITER_BETA_STATIC, N_PROB_STATIC, beta) # print the result _print_analysis(_engine.analyze_solver(solver)) # update beta beta = beta - 0.2 if beta > 0.1 else beta - 0.01 beta = round(beta, 2) if beta < 0.01: break
def test_value1(self): board = Board([[None]*Board.COLS]*Board.ROWS) res = ([[0,0,0,1,1,1,2,2,2]]*3 + [[3,3,3,4,4,4,5,5,5]]*3 + [[6,6,6,7,7,7,8,8,8]]*3) for i in range(Board.ROWS): for j in range(Board.COLS): assert_equal(board.getGridIndex(i,j),res[i][j])
def test_peers_diagonal() -> None: """Peers for diagonal board for 'A1'""" peer = 'A1' a1_peers = ['A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'B1', 'B2', 'B3', 'C1', 'C2', 'C3', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1', 'I9', 'H8', 'D4', 'E5', 'F6', 'G7'] board = SB(diagonal_mode=True) assert board.peers(peer) == set(a1_peers)
def test_value1(self): board = Board([[None] * Board.COLS] * Board.ROWS) res = ([[0, 0, 0, 1, 1, 1, 2, 2, 2]] * 3 + [[3, 3, 3, 4, 4, 4, 5, 5, 5]] * 3 + [[6, 6, 6, 7, 7, 7, 8, 8, 8]] * 3) for i in range(Board.ROWS): for j in range(Board.COLS): assert_equal(board.getGridIndex(i, j), res[i][j])
class TestBoard(TestCase): def setUp(self): self.matrix = [ 9, 0, 0, 0, 8, 0, 3, 0, 0, 0, 0, 0, 2, 5, 0, 7, 0, 0, 0, 2, 0, 3, 0, 0, 0, 0, 4, 0, 9, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 0, 5, 6, 0, 7, 0, 5, 0, 6, 0, 4, 0, 0, 0, 0, 7, 8, 0, 3, 9, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 2, ] self.board = Board(self.matrix) self.row0 = [9, 0, 0, 0, 8, 0, 3, 0, 0] self.column0 = [9, 0, 0, 0, 0, 7, 0, 0, 3] def test_get_cell(self): assert 9 == self.board.get_cell(0, 0) assert 3 == self.board.get_cell(0, 8) assert 2 == self.board.get_cell(8, 8) def test_get_column(self): assert self.column0 == self.board.get_column(0) def test_columns(self): columns = list(self.board.columns) assert 9 == len(columns) assert self.column0 == columns[0] def test_get_row(self): assert self.row0 == self.board.get_row(0) def test_rows(self): rows = list(self.board.rows) assert 9 == len(rows) assert self.row0 == rows[0] def test_squares(self): square00 = [9, 0, 0, 0, 0, 0, 0, 2, 0] squares = list(self.board.squares) assert 9 == len(squares) assert square00 == squares[0] def get_square_by_cell(self): square00 = [9, 0, 0, 0, 0, 0, 0, 2, 0] square22 = [8, 0, 3, 0, 0, 0, 0, 0, 0] assert square00 == self.board.get_square_by_cell(2, 2) assert square22 == self.board.get_square_by_cell(7, 8)
def test_reduce_puzzle_fail() -> None: """Given an empty board reduce will fail and return none""" board_string = '.' * SB.num_boxes() board = SB.grid_values(board_string) sbrd = SB() solution = sbrd.reduce_puzzle(board) assert solution is None
def test_diagonal() -> None: diagonal_grid = ('2.............62....1....7...6..8...3...9...7...6..4...4' '....8....52.............3') sbrd = SB(diagonal_mode=True) board = sbrd.grid_values(diagonal_grid) result = sbrd.search(board) assert result == solved_diag_sudoku
def test_display_board(capsys: Any) -> None: """Ensure display method prints ascii board correctly""" board_string = ('483921657967345821251876493548132976729564138136798245' '372689514814253769695417382') # display stdout for printing sudoku board with capsys.disabled(): print('\n') SB.display(SB.grid_values(board_string)) print('\n')
def test_validate() -> None: """Validation function correctly validates complete board""" board_string = ('..3.2.6..9..3.5..1..18.64....81.29..7.......8..67.82..' '..26.95..8..2.3..9..5.1.3..') board = SB.grid_values(board_string) sbrd = SB() solution = sbrd.reduce_puzzle(board) valid = sbrd.validate(solution) assert valid is True
def test_diagonal() -> None: """Solve problem with diagonal constraint enabled""" diagonal_grid = ('2.............62....1....7...6..8...3...9...7...6..4...4' '....8....52.............3') sbrd = SB(diagonal_mode=True) board = sbrd.grid_values(diagonal_grid) result = sbrd.search(board) assert result == solved_diag_sudoku
def test_naked_multi_4() -> None: quad_board = naked_multi_board_1.copy() quad_board['A1'] = quad_board['A1'] + '2' # give it a 2 to clear quad_board['A5'] = quad_board['A5'] + '2' # give it a 2 to clear quad_board['F1'] = quad_board['F1'] + '1' # give it a 1 to clear sbrd = SB() board = sbrd.naked_multi(quad_board, 4) assert board == naked_multi_board_1
def test_validate_fail() -> None: """Validation function correctly fails on incomplete board""" board_string = ('4.....8.5.3..........7......2.....6.....8.4......1.......' '6.3.7.5..2.....1.4......') board = SB.grid_values(board_string) sbrd = SB() solution = sbrd.reduce_puzzle(board) valid = sbrd.validate(solution) assert valid is False
def test_naked_multi_3() -> None: """Solve first naked twin board with naked triplets""" triplet_board = naked_multi_board_1.copy() triplet_board['A5'] = triplet_board['A5'] + '3' # give it a 3 to clear triplet_board['I2'] = triplet_board['I2'] + '7' # give it a 7 to clear triplet_board['G2'] = triplet_board['G2'] + '3' # give it a 3 to clear sbrd = SB() board = sbrd.naked_multi(triplet_board, 3) assert board == naked_multi_board_1
def test_board_to_str() -> None: """Ensure board dictionary to comma string is correct""" board_string = ('..3.2.6..9..3.5..1..18.64....81.29..7.......8..67.82..' '..26.95..8..2.3..9..5.1.3..') str_list = list(board_string) str_list = list(item.replace('.', '123456789') for item in str_list) expected_string = ','.join(str_list) board = SB.grid_values(board_string) string = SB.board_to_str(board) assert string == expected_string
def test_naked_multi_3() -> None: """Solve first naked twin board with naked triplets""" triplet_board = naked_multi_board_1.copy() # add some numbers to the board that the existing triples can clear triplet_board['A5'] = triplet_board['A5'] + '3' # give it a 3 to clear triplet_board['I2'] = triplet_board['I2'] + '7' # give it a 7 to clear triplet_board['G2'] = triplet_board['G2'] + '3' # give it a 3 to clear sbrd = SB() board = sbrd.naked_multi(triplet_board, 3) assert board == naked_multi_board_1
def test_naked_multi_4() -> None: """Solve first naked twin board with naked quads""" quad_board = naked_multi_board_1.copy() # add some numbers to the board that the existing quads can clear quad_board['A1'] = quad_board['A1'] + '2' # give it a 2 to clear quad_board['A5'] = quad_board['A5'] + '2' # give it a 2 to clear quad_board['F1'] = quad_board['F1'] + '1' # give it a 1 to clear sbrd = SB() board = sbrd.naked_multi(quad_board, 4) assert board == naked_multi_board_1
def test_reduce_puzzle() -> None: """Ensure board state after recursive reduce is correct""" board_string = ('..3.2.6..9..3.5..1..18.64....81.29..7.......8..67.82..' '..26.95..8..2.3..9..5.1.3..') expected_string = ('4,8,3,9,2,1,6,5,7,9,6,7,3,4,5,8,2,1,2,5,1,8,7,6,4,9,3,' '5,4,8,1,3,2,9,7,6,7,2,9,5,6,4,1,3,8,1,3,6,7,9,8,2,4,5,' '3,7,2,6,8,9,5,1,4,8,1,4,2,5,3,7,6,9,6,9,5,4,1,7,3,8,2') board = SB.grid_values(board_string) sbrd = SB() solution = sbrd.reduce_puzzle(board) solution_string = sbrd.board_to_str(solution) assert solution_string == expected_string
def _beta_operator(self, board: Board): """ ß-operator of the ß-climbing, introduces exploration to the algorithm :param board: Neighbouring state of the board :return: New state of the board """ values = board.values() # scan the board for pos in board.unfilled_positions(): # regenerate the value if it meets the probability of beta if self._with_probability(self._beta_prob): values[pos.y, pos.x] = self._generate_fill_number() # fill the board board.fill_board(values) return board
def _step(self, board: Board) -> Board: """ Performs one hill climb step :param board: Current state of the board to step from :return: Board after the step """ # select random line from unfilled ones unfilled = board.unfilled_by_row() row = list(unfilled.keys())[random.randint(0, len(unfilled) - 1)] line = board.values()[row] # swap 2 characters in it self._swap_in_line(line, unfilled[row]) # update original board board.fill_line(row, line) return board
def test_only_choice() -> None: """Ensure board state after single only choice is correct""" board_string = ('..3.2.6..9..3.5..1..18.64....81.29..7.......8..67.82..' '..26.95..8..2.3..9..5.1.3..') expected_string = ('45,8,3,9,2,1,6,5789,57,9,6,47,3,4,5,8,278,1,2,257,1,8,' '7,6,4,23579,2357,345,345,8,1,3456,2,9,34567,34567,7,2,' '9,5,34569,4,1,13456,8,1345,13459,6,7,3459,8,2,1345,' '345,134,1347,2,6,8,9,5,1478,47,8,1467,47,2,5,3,17,6,9,' '6,9,5,4,1,7,3,8,2') board_dict = SB.grid_values(board_string) sbrd = SB() eliminated_board = sbrd.eliminate(board_dict) only_choice_board = sbrd.only_choice(eliminated_board) only_choice_string = SB.board_to_str(only_choice_board) assert only_choice_string == expected_string
def test_diagonal_units() -> None: """Ensure diagonal units are the correct ones""" units = [['A1', 'B2', 'C3', 'D4', 'E5', 'F6', 'G7', 'H8', 'I9'], ['I1', 'H2', 'G3', 'F4', 'E5', 'D6', 'C7', 'B8', 'A9']] # pylint: disable=protected-access diagonal_units = SB._diagonal_units() assert diagonal_units == units
def test_remove_values_in_boxes() -> None: """Ensure removal of values from boxes""" board_dict = {'A1': '123', 'A2': '123'} expected_dict = {'A1': '3', 'A2': '123'} # pylint: disable=protected-access board = SB._remove_values_in_boxes(board_dict, set('1') | set('2'), ['A1']) assert board == expected_dict
def test_eliminate() -> None: """Ensure board state after single elimination is correct""" board_string = ('..3.2.6..9..3.5..1..18.64....81.29..7.......8..67.82..' '..26.95..8..2.3..9..5.1.3..') # eliminated board in comma separated format for easy comparison expected_string = ('45,4578,3,49,2,147,6,5789,57,9,24678,47,3,47,5,78,278,' '1,25,257,1,8,79,6,4,23579,2357,345,345,8,1,3456,2,9,' '34567,34567,7,123459,49,459,34569,4,1,13456,8,1345,' '13459,6,7,3459,8,2,1345,345,134,1347,2,6,478,9,5,1478,' '47,8,1467,47,2,457,3,17,1467,9,46,4679,5,4,1,47,3,' '24678,2467') board = SB.grid_values(board_string) eliminated_board = SB().eliminate(board) eliminated_string = SB.board_to_str(eliminated_board) assert eliminated_string == expected_string
def setUp(self): self.matrix = [ 1, 2, 0, 4, 3, 4, 0, 0, 2, 1, 0, 4, 4, 4, 1, 3, ] self.board = Board(self.matrix)
def test_diagonal_board() -> None: """Ensure diagonal board mode boolean constructor works""" sbrd = SB() sbrd_diagonal = SB(diagonal_mode=True) assert sbrd.all_units() != sbrd_diagonal.all_units() # pylint: disable=protected-access assert sbrd.all_units() + SB._diagonal_units() == sbrd_diagonal.all_units()
def setUp(self): self.matrix = [ 1, 2, 0, 4, 3, 4, 0, 0, 2, 1, 0, 4, 4, 3, 4, 3, ] self.board = Board(self.matrix) self.rules = RuleHandler()
class TestRulesHandler(TestCase): def setUp(self): self.matrix = [ 1, 2, 0, 4, 3, 4, 0, 0, 2, 1, 0, 4, 4, 3, 4, 3, ] self.board = Board(self.matrix) self.rules = RuleHandler() def test_rules(self): cell = self.board.get_cell(1, 1) assert self.rules.is_valid(self.board, cell) cell = self.board.get_cell(1, 2) assert self.rules.is_valid(self.board, cell) cell = self.board.get_cell(2, 3) assert not self.rules.is_valid(self.board, cell)
def _neighbouring_operator(self, board: Board): """ N-operator of the ß-climbing, introduces exploitation to the algorithm :param board: State of the board :return: Neighbouring state """ values = board.values() # iterate modifiable tiles for pos in board.unfilled_positions(): # modify the tile if it meets the probability of n if self._with_probability(self._n_prob): values[pos.y, pos.x] = self._neighbouring_val(values[pos.y, pos.x]) # fill the board board.fill_board(values) return board
def test_reduce_puzzle_incomplete() -> None: """Ensure given a more complex puzzle reduce terminates incomplete""" board_string = ('4.....8.5.3..........7......2.....6.....8.4......1.......' '6.3.7.5..2.....1.4......') expected_string = ('4,1679,12679,139,2369,269,8,1239,5,26789,3,1256789,' '14589,24569,245689,12679,1249,124679,2689,15689,' '125689,7,234569,245689,12369,12349,123469,3789,2,' '15789,3459,34579,4579,13579,6,13789,3679,15679,15679,' '359,8,25679,4,12359,12379,36789,4,56789,359,1,25679,' '23579,23589,23789,289,89,289,6,459,3,1259,7,12489,5,' '6789,3,2,479,1,69,489,4689,1,6789,4,589,579,5789,' '23569,23589,23689') board = SB.grid_values(board_string) sbrd = SB() solution = sbrd.reduce_puzzle(board) solution_string = sbrd.board_to_str(solution) assert solution_string == expected_string
def main(): board = Board(readSudokuFile('input.txt')) solver = Solver(board) solver.solve() #print "Final --" #print repr(board) print "-----" solver.solve() print board
def _beta_operator(self, board: Board): """ ß-operator of the ß-climbing, introduces exploration to the algorithm :param board: Neighbouring state of the board :return: New state of the board """ # go through modifiable rows unfilled = board.unfilled_by_row() for row in unfilled: # regenerate the row with probability of beta if self._with_probability(self._beta_prob): line = board.values()[row] # clear for index in unfilled[row]: line[index] = 0 # refill board.fill_line(row, np.array(self._fill_line_unique(line))) return board
def _neighbouring_operator(self, board: Board): """ N-operator of the ß-climbing, introduces exploitation to the algorithm :param board: State of the board :return: Neighbouring state """ values = board.values() # iterate rows unfilled = board.unfilled_by_row() for row in unfilled: # only modify the rows when they meet the probability of n if self._with_probability(self._n_prob): # swap 2 tiles self._swap_in_line(values[row], unfilled[row]) # update original board board.fill_board(values) return board
def test_invalid(self): print "------" board = Board(readSudokuFile("test-input/test-invalid1.txt")) print "Board:" print board print "Checking for: ", repr(board[(0,6)]), "$" res = Solver.getAffectedFilledCells(board,board[(0,6)]) print "Final:", repr(res) if len(set(res)) != len(res): raise InvalidSudokuStateError("Cell @" + repr(cell)) print "-------" #No asserts, stdout check
class TestRules(TestCase): def setUp(self): self.matrix = [ 1, 2, 0, 4, 3, 4, 0, 0, 2, 1, 0, 4, 4, 4, 1, 3, ] self.board = Board(self.matrix) def test_unique_in_row(self): cell = self.board.get_cell(1, 0) assert unique_in_row(self.board, cell) cell = self.board.get_cell(1, 3) assert not unique_in_row(self.board, cell) def test_unique_in_column(self): cell = self.board.get_cell(0, 1) assert unique_in_column(self.board, cell) cell = self.board.get_cell(3, 0) assert not unique_in_column(self.board, cell) def test_unique_in_square(self): cell = self.board.get_cell(1, 1) assert unique_in_square(self.board, cell) cell = self.board.get_cell(0, 3) assert not unique_in_square(self.board, cell)
def __init__(self, puzzle, slow): """ Constructor for the Solver class. The key members of this class are: finished: Flag to track if solution is found. board: Board object. This enforces the rules of Sudoku. moves: Track what moves have been tried so that they can be rolled back. The remaining members support display options. """ self.iteration = 0 self.finished = False self.slow = slow self.board = Board.factory(puzzle, slow) self.moves = [Move() for i in xrange(81)]
def setUp(self): self.matrix = [ 9, 0, 0, 0, 8, 0, 3, 0, 0, 0, 0, 0, 2, 5, 0, 7, 0, 0, 0, 2, 0, 3, 0, 0, 0, 0, 4, 0, 9, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 0, 5, 6, 0, 7, 0, 5, 0, 6, 0, 4, 0, 0, 0, 0, 7, 8, 0, 3, 9, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 2, ] self.board = Board(self.matrix) self.row0 = [9, 0, 0, 0, 8, 0, 3, 0, 0] self.column0 = [9, 0, 0, 0, 0, 7, 0, 0, 3]
# This file is part of Pydoku. # # Pydoku is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Pydoku is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Pydoku. If not, see <http://www.gnu.org/licenses/>. import os from sudoku.board import Board board = Board("board6.txt") n = board.pre_solve() print board board.solve() print board board.fields # 0.143
def test_getCellsInGrid(self): board = Board(readSudokuFile("test-input/test-input.txt")) for i in range(9): print "For %d"%i print repr(board.getCellsInGrid(i))