def test_colors_conflict(self): columns, rows, colors = color_board_def() rows[0] = '3g' with pytest.raises(KeyError) as ie: make_board(columns, rows, colors) assert str(ie.value).endswith("'g'")
def test_bad_description(self): columns = [(('1', 'r', 1),)] rows = [((1, 'r'),), 0, '1'] colors = ColorMap() colors.make_color('r', 'red', 'X') with pytest.raises(ValueError, match='Bad description block:'): make_board(columns, rows, colors)
def test_same_boxes_in_a_row(self): columns = [['1r', (1, 'b'), (1, 'b')]] * 3 rows = ['3r', '3b', '3b'] colors = ColorMap() for color in [('r', 'red', 'X'), ('b', 'blue', '*')]: colors.make_color(*color) with pytest.raises(ValueError, match='Cannot allocate clue .+ in just 3 cells'): make_board(columns, rows, colors)
def test_color_renderer(self, stream): columns = [['1r', 1]] * 3 rows = [((3, 'r'),), 0, '3'] colors = ColorMap() colors.make_color('r', 'red', '%') renderer = BaseAsciiRenderer(stream=stream) board = make_board(columns, rows, colors, renderer=renderer) for i in range(3): board.cells[0][i] = 4 board.cells[2][i] = Color.black().id_ # cannot do simply: # board.cells[2] = [True, True, True] # because of # ValueError: could not broadcast input array from shape (3) into shape (3,2) board.draw() assert stream.getvalue().rstrip() == '\n'.join([ '# 1 1 1', '# 1 1 1', '3 % % %', '0 ', '3 X X X', ])
def test_basic(self): board = make_board(*Pbn.read(19407)) assert board.has_blots assert board.rows_descriptions[1] == (BlottedBlock,) propagation.solve(board) assert board.is_solved_full
def test_black_and_white(self): columns = [3, None, 1, 1] rows = [ 1, '1 1', '1 1', ] b = make_board(columns, rows) assert isinstance(b, BlackBoard)
def test_depth_search(self): board = make_board(*Pbn.read(3469)) propagation.solve(board) assert board.solution_rate == 0 assert len(board.solutions) == 0 Solver(board, max_solutions=2, timeout=600).solve() assert board.is_solved_full assert len(board.solutions) == 1 assert board.is_finished
def get_board(cls, _id, create_mode, **renderer_params): """Generates a board using given ID and mode""" if create_mode == 'local': board_def = read_example(_id) elif create_mode == 'pbn': board_def = Pbn.read(_id) elif create_mode == 'nonograms.org': board_def = NonogramsOrg.read(_id) else: raise tornado.web.HTTPError(400, 'Bad mode: %s', create_mode) return make_board(*board_def, **renderer_params)
def test_depth_search_colored(self, stream): renderer = BaseAsciiRenderer(stream=stream) board = make_board(*Pbn.read(5260), renderer=renderer) propagation.solve(board) assert board.solution_rate == 0.9375 assert len(board.solutions) == 0 Solver(board, max_solutions=2, timeout=600).solve() assert board.solution_rate == 0.9375 assert len(board.solutions) == 2 assert board.is_finished board.draw_solutions() example_solution = [ '# # # # # # 1 1 ', '# # # # # # 1 1 ', '# # # # # # 1 1 1 1 1 1 ', '# # # # # # 1 1 1 1 1 1 1 1 1 1 ', '# # # # # # 6 1 2 1 2 1 2 1 1 2 1 2 1 2 1 6 ', '# # # # # # 1 1 1 1 1 2 0 1 2 1 1 2 1 0 2 1 1 1 1 1', ' 1 X . . . . . . . . . . . . . . . . . . .', ' 1 6 1 . X . . . . . % % % % % % . . . . . X .', ' 1 1 1 1 . . X . . . . . % . . % . . . X . . . .', ' 1 2 1 . . . . X . . . . % % . . . . . X . . .', ' 1 1 1 1 . . . X . @ . . . . . . . . @ . . X . .', ' 2 2 . . . . @ @ . . . . . . . . @ @ . . . .', ' 0 . . . . . . . . . . . . . . . . . . . .', ' 1 1 . % . . . . . . . . . . . . . . . . % .', ' 2 2 . % % . . . . . . . . . . . . . . % % .', '1 1 1 1 1 1 . % . % . . . . . * % . . . . . % . % .', '1 1 1 1 1 1 . % . % . . . . . X * . . . . . % . % .', ' 2 2 . % % . . . . . . . . . . . . . . % % .', ' 1 1 . % . . . . . . . . . . . . . . . . % .', ' 0 . . . . . . . . . . . . . . . . . . . .', ' 2 2 . . . . @ @ . . . . . . . . @ @ . . . .', ' 1 1 1 1 . X . . . @ . . . . . . . . @ . . X . .', ' 1 2 1 . . X . . . . . . % % . . . . . X . . .', ' 1 1 1 1 . . . . X . . . % . . % . . . . . . X .', ' 1 6 1 . . . X . . . % % % % % % . . X . . . .', ' 1 . . . . . . . . . . . . . . . . . . . X', ] actual_drawing = stream.getvalue().rstrip().split('\n') sol1, sol2 = actual_drawing[:26], actual_drawing[26:] # header assert sol1[:6] == sol2[:6] == example_solution[:6] # central assert sol1[11:21] == sol2[11:21] == example_solution[11:21]
def test_color(self): board = make_board(*Pbn.read(19647)) assert board.has_blots assert board.rows_descriptions[15] == ( (1, 2), (BlottedBlock, 8), (BlottedBlock, 8), (2, 2), (2, 2), (2, 8), ) propagation.solve(board) assert board.is_solved_full
def test_colored(self): board = make_board(*Pbn.read(10282)) propagation.solve(board) assert len(board.solutions) == 0 Solver(board, max_solutions=2, timeout=600).solve() assert is_close(board.solution_rate, 0.91625) assert len(board.solutions) == 2 assert len(board.solved_rows[0]) == 3 assert len(board.solved_rows[1]) == 2 assert len(board.solved_columns[0]) == 5 assert len(board.solved_columns[1]) == 9
def draw_solution(board_def, draw_final=False, box_symbol=None, curses_animation=False, **solver_args): """Solve the given board in terminal with animation""" with ignored(locale.Error): # to correctly print non-ASCII box symbols locale.setlocale(locale.LC_ALL, 'en_US.UTF-8') if curses_animation: if draw_final: logging.warning('No need to use curses with draw_final=True') curses_animation = False if curses_animation: board_queue = queue.Queue() d_board = make_board(*board_def, renderer=CursesRenderer, stream=board_queue) if box_symbol is not None: d_board.renderer.icons.update({BOX: box_symbol}) thread = Thread(target=solve, args=(d_board, ), kwargs=solver_args) thread.daemon = True thread.start() curses.wrapper(PagerWithUptime.draw, board_queue) else: d_board = make_board(*board_def, renderer=BaseAsciiRenderer) if box_symbol is not None: d_board.renderer.icons.update({BOX: box_symbol}) solve(d_board, draw_final=draw_final, **solver_args)
def test_black_and_white(self): board = make_board(*Pbn.read(2903)) propagation.solve(board) assert len(board.solutions) == 0 Solver(board, max_solutions=2, timeout=600).solve() assert board.is_solved_full assert len(board.solutions) == 1 assert len(board.solved_rows[0]) == 6 assert len(board.solved_rows[1]) == 6 assert len(board.solved_columns[0]) == 4 assert len(board.solved_columns[1]) == 0 assert board.is_finished
def test_normalize(self): columns = [['1r', 1]] * 3 rows = [((3, 'r'),), 0, '3'] colors = ColorMap() colors.make_color('r', 'red', 'X') board = make_board(columns, rows, colors) assert board.rows_descriptions == ( ((3, 4),), (), ((3, 2),), ) assert board.columns_descriptions == ( ((1, 4), (1, 2)), ((1, 4), (1, 2)), ((1, 4), (1, 2)), )
def tested_board(renderer=BaseAsciiRenderer, **kwargs): """ Very simple demonstration board with the 'P' letter source: https://en.wikipedia.org/wiki/Nonogram#Example """ columns = [[], 9, [9], [2, 2], (2, 2), 4, '4', ''] rows = [ None, 4, 6, '2 2', [2] * 2, 6, 4, 2, [2], 2, 0, ] return make_board(columns, rows, renderer=renderer, **kwargs)
def test_backtracking(self): board = make_board(*Pbn.read(4581)) propagation.solve(board, methods=self.method_name()) assert is_close(board.solution_rate, 0.75416666667) assert len(board.solutions) == 0
def test_black(self): board = make_board(*Pbn.read(20029)) assert board.rows_descriptions[2] == (BlottedBlock, 1) propagation.solve(board) assert board.is_solved_full
def test_color_solved(self, stream): b = make_board(*color_board_def(), renderer=SvgRenderer, stream=stream) propagation.solve(b) b.draw() table = [line.strip() for line in stream.getvalue().split('\n')] svg_def = ''' <svg baseProfile="full" height="90" version="1.1" width="75" xmlns=" http://www.w3.org/2000/svg" xmlns:ev= "http://www.w3.org/2001/xml-events" xmlns:xlink="http://www.w3.org/1999/xlink"> <defs> <style type="text/css"> <![CDATA[ g.grid-lines line { stroke-width: 1} g.grid-lines line.bold { stroke-width: 2} g.header-clues text, g.side-clues text { font-size: 9.000000} ]]> </style> <symbol id="color-b"> <rect fill="blue" height="15" width="15" x="0" y="0" /> </symbol> <symbol id="color-black"> <rect fill="#000" height="15" width="15" x="0" y="0" /> </symbol> <symbol id="color-r"> <rect fill="red" height="15" width="15" x="0" y="0" /> </symbol> <symbol id="x2-b-black"> <polygon fill="blue" points="0,0 0,15 15,0" /> <polygon fill="#000" points="0,15 15,0 15,15" /> </symbol> <symbol id="x2-b-r"> <polygon fill="blue" points="0,0 0,15 15,0" /> <polygon fill="red" points="0,15 15,0 15,15" /> </symbol> <symbol id="x2-b-white"> <polygon fill="blue" points="0,0 0,15 15,0" /> <polygon fill="#fff" points="0,15 15,0 15,15" /> </symbol> <symbol id="x2-black-r"> <polygon fill="#000" points="0,0 0,15 15,0" /> <polygon fill="red" points="0,15 15,0 15,15" /> </symbol> <symbol id="x2-black-white"> <polygon fill="#000" points="0,0 0,15 15,0" /> <polygon fill="#fff" points="0,15 15,0 15,15" /> </symbol> <symbol id="x2-r-white"> <polygon fill="red" points="0,0 0,15 15,0" /> <polygon fill="#fff" points="0,15 15,0 15,15" /> </symbol> <symbol id="x3-b-black-r"> <rect fill="blue" height="15" width="15" x="0" y="0" /> <polygon fill="#000" points="0,0 0,10.61 10.61,0" /> <polygon fill="red" points="15,4.39 4.39,15 15,15" /> </symbol> <symbol id="x3-b-black-white"> <rect fill="blue" height="15" width="15" x="0" y="0" /> <polygon fill="#000" points="0,0 0,10.61 10.61,0" /> <polygon fill="#fff" points="15,4.39 4.39,15 15,15" /> </symbol> <symbol id="x3-b-r-white"> <rect fill="blue" height="15" width="15" x="0" y="0" /> <polygon fill="red" points="0,0 0,10.61 10.61,0" /> <polygon fill="#fff" points="15,4.39 4.39,15 15,15" /> </symbol> <symbol id="x3-black-r-white"> <rect fill="#000" height="15" width="15" x="0" y="0" /> <polygon fill="red" points="0,0 0,10.61 10.61,0" /> <polygon fill="#fff" points="15,4.39 4.39,15 15,15" /> </symbol> <symbol id="space"><circle cx="0" cy="0" r="1.5" /></symbol> <symbol fill="none" id="check" stroke="green"> <circle cx="50" cy="50" r="40" stroke-width="10" /> <polyline points="35,35 35,55 75,55" stroke-width=" 12" transform="rotate(-45 50 50)" /> </symbol> </defs> <rect class="nonogram-thumbnail" height="30" width="15" x="0" y="0" /> <rect class="nonogram-header" height="30" width="45" x="15" y="0" /> <g class="header-clues"> <rect class="solved" height="30" width="15" x="15" y="0" /> <use x="15" xlink:href="#color-b" y="15" /> <text x="27.75" y="25.5">1</text> <use x="15" xlink:href="#color-r" y="0" /> <text x="27.75" y="10.5">1</text> <rect class="solved" height="30" width="15" x="30" y="0" /> <use x="30" xlink:href="#color-b" y="15" /> <text x="42.75" y="25.5">1</text> <use x="30" xlink:href="#color-r" y="0" /> <text x="42.75" y="10.5">1</text> <rect class="solved" height="30" width="15" x="45" y="0" /> <use x="45" xlink:href="#color-b" y="15" /> <text x="57.75" y="25.5">1</text> <use x="45" xlink:href="#color-r" y="0" /> <text x="57.75" y="10.5">1</text> </g> <rect class="nonogram-side" height="45" width="15" x="0" y="30" /> <g class="side-clues"> <rect class="solved" height="15" width="15" x="0" y="30" /> <use x="0" xlink:href="#color-r" y="30" /> <text x="10.5" y="41.25">3</text> <rect class="solved" height="15" width="15" x="0" y="45" /> <rect class="solved" height="15" width="15" x="0" y="60" /> <use x="0" xlink:href="#color-b" y="60" /> <text x="10.5" y="71.25">3</text> </g> <use x="0" xlink:href="#check" y="0" /> <rect class="nonogram-grid" height="45" width="45" x="15" y="30" /> <g class="space"> <use x="22.5" xlink:href="#space" y="52.5" /> <use x="37.5" xlink:href="#space" y="52.5" /> <use x="52.5" xlink:href="#space" y="52.5" /> </g> <g class="color-black" /> <g class="x2-black-white" /> <g class="color-r"> <use x="15" xlink:href="#color-r" y="30" /> <use x="30" xlink:href="#color-r" y="30" /> <use x="45" xlink:href="#color-r" y="30" /> </g> <g class="x2-r-white" /> <g class="x2-black-r" /> <g class="x3-black-r-white" /> <g class="color-b"> <use x="15" xlink:href="#color-b" y="60" /> <use x="30" xlink:href="#color-b" y="60" /> <use x="45" xlink:href="#color-b" y="60" /> </g> <g class="x2-b-white" /> <g class="x2-b-black" /> <g class="x3-b-black-white" /> <g class="x2-b-r" /> <g class="x3-b-r-white" /> <g class="x3-b-black-r" /> <g class="grid-lines"> <line class="bold" x1="0" x2="60" y1="30" y2="30" /> <line x1="0" x2="60" y1="45" y2="45" /> <line x1="0" x2="60" y1="60" y2="60" /> <line class="bold" x1="0" x2="60" y1="75" y2="75" /> <line class="bold" x1="15" x2="15" y1="0" y2="75" /> <line x1="30" x2="30" y1="0" y2="75" /> <line x1="45" x2="45" y1="0" y2="75" /> <line class="bold" x1="60" x2="60" y1="0" y2="75" /> </g> </svg>''' assert table[0] == '<?xml version="1.0" encoding="utf-8" ?>' svg_def = ''.join([ line for line in [line.strip() for line in svg_def.split('\n')] if line ]) assert table[1] == svg_def
def test_solve_contradictions(self): board = make_board(*Pbn.read(2021)) Solver(board).solve() assert board.is_solved_full assert board.is_finished
def color_board(renderer=BaseAsciiRenderer, **kwargs): return make_board(*color_board_def(), renderer=renderer, **kwargs)
def test_bad_make_board(self): with pytest.raises(ValueError, match='Bad number of \*args'): # noqa: W605 make_board(color_board_def()[0])
def test_color_boxes_differ(self): columns, rows, colors = color_board_def() rows[0] = '2r' with pytest.raises(ValueError, match='Color boxes differ:'): make_board(columns, rows, colors)
def test_color_not_defined(self): columns, rows, colors = color_board_def() del colors['r'] with pytest.raises(ValueError, match='Some colors not defined:'): make_board(columns, rows, colors)
def test_colors(self): board = make_board(*color_board_def()) assert board.symbol_for_color_id('r') == 'X' assert board.rgb_for_color_name('b') == 'blue'
def board(self): board_def = read_example('uk') return make_board(*board_def)