def test_callbacks(self): # 'L' letter columns = [3, 1] rows = [1, 1, 2] board = BlackBoard(columns, rows) rows_updated = [] cols_updated = [] rounds = [] board.on_row_update = lambda index, **kwargs: rows_updated.append(index) board.on_column_update = lambda index, **kwargs: cols_updated.append(index) board.on_solution_round_complete = lambda **kwargs: rounds.append(1) propagation.solve(board) # the solution will go like following: # 1. draw the lower '_' in L (row 2) # 2. the column 0 updated # 3. during that update the row 0 updated # 4. during that update the column 1 updated assert rows_updated == [2, 0] # draw the vertical '|' in L # and fill the spaces on the second column assert cols_updated == [0, 1] # it takes only one round to solve that assert sum(rounds) == 1
def test_several_solutions(self, stream): columns = [3, None, 1, 1] rows = [ 1, '1 1', '1 1', ] board = BlackBoard(columns, rows, renderer=AsciiRenderer, stream=stream) propagation.solve(board) board.draw() assert stream.getvalue().rstrip() == '\n'.join([ '+---+---++---+---+---+---+', '| # | # || 3 | 0 | 1 | 1 |', '|===+===++===+===+===+===|', '| | 1 || # | | | |', '|---+---++---+---+---+---|', '| 1 | 1 || # | | ? | ? |', '|---+---++---+---+---+---|', '| 1 | 1 || # | | ? | ? |', '+---+---++---+---+---+---+', ]) assert board.solution_rate * 3 == 2.0
def test_bold_lines(self, stream): """ M letter """ columns = [5, 1, 1, 1, 5] rows = ['1 1', '2 2', '1 1 1', '1 1', '1 1'] renderer = AsciiRendererWithBold(stream=stream) renderer.BOLD_LINE_EVERY = 2 board = BlackBoard(columns, rows, renderer=renderer) propagation.solve(board) board.draw() assert stream.getvalue().rstrip() == '\n'.join([ '+---+---+---+++---+---++---+---++---+', '| # | # | # ||| 5 | 1 || 1 | 1 || 5 |', '|===+===+===+++===+===++===+===++===|', '| | 1 | 1 ||| # | || | || # |', '|---+---+---+++---+---++---+---++---|', '| | 2 | 2 ||| # | # || | # || # |', '|===+===+===+++===+===++===+===++===|', '| 1 | 1 | 1 ||| # | || # | || # |', '|---+---+---+++---+---++---+---++---|', '| | 1 | 1 ||| # | || | || # |', '|===+===+===+++===+===++===+===++===|', '| | 1 | 1 ||| # | || | || # |', '+---+---+---+++---+---++---+---++---+', ])
def test_solve_board(self): columns, rows = read_example('w') board = BlackBoard(columns, rows) propagation.solve(board, methods='simpson') assert board.is_solved_full
def test_smile(self): columns, rows = read_example('smile.txt') board = BlackBoard(columns, rows) propagation.solve(board) assert is_close(board.solution_rate, 0.6) # assert is_close(board.solution_rate, 407.0 / 625) Solver(board).solve() assert board.is_solved_full
def test_two_digits_bad_drawing(self, stream): width = 10 cols = [1] * width + [0, 1] rows = [[width, 1]] b = BlackBoard(cols, rows, renderer=BaseAsciiRenderer, stream=stream) b.draw() assert stream.getvalue().rstrip() == '\n'.join([ '# # 1 1 1 1 1 1 1 1 1 1 0 1', '101 _ _ _ _ _ _ _ _ _ _ _ _', ])
def test_many_solutions(self): # source: https://en.wikipedia.org/wiki/Nonogram#Contradictions columns = [3, 1, 2, 2, '1 1', '1 1'] rows = ['1 2', 1, 1, 3, 2, 2] board = BlackBoard(columns, rows) propagation.solve(board) assert board.solution_rate == 0 Solver(board).solve() assert is_close(board.solution_rate, 7.0 / 9) assert len(board.solutions) == 2
def test_space_hints_solving(): columns = [3, 1, 3] rows = [ 3, '1 1', '1 1', ] board = BlackBoard(columns, rows) _solve_on_space_hints(board, [[0], [0, 1], [0, 1]]) assert board.cells == [ [BOX, BOX, BOX], [BOX, SPACE, BOX], [BOX, SPACE, BOX], ]
def test_chessboard(self): # The real chessboard could be defined like this # # `columns = rows = [[1, 1, 1, 1]] * 8` # # but it really slows down the test. # # So we just use simple 2x2 chessboard here # with the same effect on test coverage columns = rows = [[1, 1, 1, 1]] * 8 board = BlackBoard(columns, rows) propagation.solve(board) assert board.solution_rate == 0 Solver(board).solve() assert board.solution_rate == 0
def test_hello(self): columns, rows = read_example('hello.txt') stream = StringIO() board = BlackBoard(columns, rows, renderer=BaseAsciiRenderer, stream=stream) propagation.solve(board) board.draw() assert stream.getvalue().rstrip() == '\n'.join([ '# # # # # # # # # 1 1 ', '# # # # # # # # # 1 1 1 1 5', '# # # # # # # # # 7 1 1 1 7 0 3 1 1 2 0 6 0 6 0 3 1 5 1 3 0 1', ' 1 1 1 X . . . X . . . . . . . . . . . . . . . . X', ' 1 1 1 1 1 X . . . X . . . . . . X . X . . . . . . . X', ' 1 1 2 1 1 3 1 X . . . X . . X X . . X . X . . X X X . . X', '5 1 1 1 1 1 1 1 1 X X X X X . X . . X . X . X . X . X . X . X', '1 1 4 1 1 1 1 1 1 X . . . X . X X X X . X . X . X . X . X . X', ' 1 1 1 1 1 1 1 1 X . . . X . X . . . . X . X . X . X . X . .', ' 1 1 2 1 1 3 1 X . . . X . . X X . . X . X . . X X X . . X', ]) assert board.is_solved_full
def test_columns_and_rows_does_not_match(self): with pytest.raises(ValueError) as ei: BlackBoard(columns=[1, 1], rows=[1, 2]) assert str(ei.value), \ 'Number of boxes differs: 3 (rows) and 2 (columns)'
def test_bad_row_value(self): with pytest.raises(ValueError) as ei: BlackBoard(columns=[2.0, 1], rows=[1, 2]) assert str(ei.value), 'Bad row: 2.0'
def test_row_does_not_fit(self): with pytest.raises(ValueError) as ei: BlackBoard(columns=[1, 1], rows=[1, [1, 1]]) assert str(ei.value), \ 'Cannot allocate row [1, 1] in just 2 cells'
def test_board_changed(self, renderer): prev_board = id(renderer.board) renderer.board_init(BlackBoard([], [])) assert prev_board != id(renderer.board)
def one_row_table(cls, width, stream): cols = [1] * width rows = [width] return BlackBoard(cols, rows, renderer=SvgRenderer, stream=stream)