def test_bad_two_blocks(self): with pytest.raises(NonogramError, match='^The next .+ cannot be allocated'): f( [ColorBlock(2, 2), ColorBlock(1, 2)], [2, 2], )
def parse(self): """ Find and parse the colors and solution of a 'nonograms.org' puzzle by id """ colors, solution = self.definition() columns, rows = clues(solution, white_color_code=0) if len(colors) == 1: return columns, rows color_map = ColorMap() # reassign the IDs id_map = {} for old_id, color in enumerate(colors, 1): is_black = (color == '000000') if is_black: name = Color.black().name else: name = 'color-{}'.format(old_id) color_map.make_color(name, color) id_map[old_id] = name columns = [[ ColorBlock(size, id_map[old_color]) for size, old_color in col ] for col in columns] rows = [[ColorBlock(size, id_map[old_color]) for size, old_color in r] for r in rows] return columns, rows, color_map
def test_solved_partial_three_blocks(self): assert f([ ColorBlock(2, 2), ColorBlock(1, 4), ColorBlock(2, 4), ColorBlock(2, 2) ], [2, 2, 4, space, 4, 4, 2, space | 2]) == (6, 3)
def test_bad_not_enough_line_for_block(self): with pytest.raises(NonogramError, match='^The 0-th block .+ cannot be allocated'): f( [ColorBlock(2, 2)], [space, space, 2], )
def test_19787(self): """13 column from http://webpbn/19787""" desc = ( ColorBlock(size=BlottedBlock, color=16), ColorBlock(size=BlottedBlock, color=2), ColorBlock(size=BlottedBlock, color=16), ColorBlock(size=1, color=2), ColorBlock(size=BlottedBlock, color=8), ColorBlock(size=BlottedBlock, color=8), ColorBlock(size=BlottedBlock, color=16), ) line = ( 17, 17, 19, 19, 19, 19, 17, 17, 27, 19, 19, 19, 11, 8, 9, 9, 9, 9, 9, 9, 8, 8, 9, 9, 25, 9, 17, 17, 17, 17, ) assert BguColoredBlottedSolver.block_ranges(desc, line) == [ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [2, 3, 4, 5, 8, 9, 10], [3, 4, 5, 6, 7, 8, 9, 10, 11], [4, 5, 8, 9, 10, 11, 12], [8, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23], [12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25], [24, 26, 27, 28, 29], ]
def replace_with_1(cls, description): """ Every blotted block spans a minimum of 1 cell """ for block in description: if is_list_like(block): if block.size == cls: block = ColorBlock(1, block.color) elif block == cls: block = 1 yield block
def _line_clues(line, white_color_code): size = len(line) description = [] colors = set() index = 0 while index < size: block_begin = index color_number = line[index] while (index < size) and (line[index] == color_number): index += 1 block_size = index - block_begin if (block_size > 0) and (color_number != white_color_code): colors.add(color_number) description.append(ColorBlock(block_size, color_number)) return description, colors
def test_solved_fully_different_colors_without_space(self): assert f([ColorBlock(2, 2), ColorBlock(2, 4)], [space, 2, 2, 4, 4]) == (5, 2)
def test_solved_fully_same_colors(self): assert f([ColorBlock(2, 2), ColorBlock(1, 2)], [space, 2, 2, space, 2, space]) == (6, 2)
def test_solved_fully_one_block_surrounded_spaces(self): assert f([ColorBlock(2, 2)], [space] * 2 + [2, 2] + [space]) == (5, 1)
def test_solved_fully_one_block_leading_spaces(self): assert f([ColorBlock(2, 2)], [space] * 2 + [2, 2]) == (4, 1)
def test_same_color(self, colors): desc = [ColorBlock(1, 4), ColorBlock(1, 4)] line = [colors] * 3 assert tuple(self.solve_as_color_sets(desc, line)) == (4, SPACE_C, 4)
def test_solved_partial_different_colors_without_space(self): assert f([ColorBlock(2, 2), ColorBlock(1, 4)], [2, 2, space | 4]) == (2, 1)
def test_solved_partial_same_colors(self): assert f([ColorBlock(2, 2), ColorBlock(1, 2)], [space, 2, 2, space, space | 2]) == (4, 1)
def test_solved_partial_same_colors_both_blots(self): assert f([ColorBlock(BB, 2), ColorBlock(BB, 2)], [space, 2, 2, space, space | 2]) == (4, 1)
def test_solved_fully_different_colors_with_space_both_blots(self): assert f([ColorBlock(BB, 2), ColorBlock(BB, 4)], [space, 2, 2, space, 4, 4]) == (6, 2)
def test_lengthy(self, colors): desc = [ColorBlock(2, 4), ColorBlock(1, 4), ColorBlock(1, 8)] line = [colors] * 5 assert tuple(self.solve_as_color_sets(desc, line)) == ( 4, 4, SPACE_C, 4, 8)
def test_different_colors(self, colors): desc = [ColorBlock(1, 4), ColorBlock(1, 8)] line = [colors] * 3 assert tuple(self.solve_as_color_sets(desc, line)) == ( 4 | SPACE_C, 4 | 8 | SPACE_C, 8 | SPACE_C)
def test_solved_fully_three_colors(self): assert f([ColorBlock(2, 2), ColorBlock(1, 4), ColorBlock(2, 8)], [space, 2, 2, 4, space, space, 8, 8] + [space] * 4) == (12, 3)
def test_solved_partial_different_colors_with_space(self): assert f([ColorBlock(BB, 2), ColorBlock(BB, 4)], [space, 2, 2, space, space | 4]) == (4, 1)
def test_solved_partial_one_block(self): assert f([ColorBlock(2, 2), ColorBlock(1, 2)], [space] * 3 + [space | 2] * 3) == (3, 0)
def test_simplest(self, colors): desc = [ColorBlock(1, 4)] line = [colors] assert tuple(self.solve_as_color_sets(desc, line)) == (4,)
def test_solved_partial_same_colors_second_block_not_full(self): assert f([ColorBlock(2, 2), ColorBlock(2, 2)], [2, 2, space, 2, space | 2]) == (3, 1)
def test_bad(self, colors): desc = [ColorBlock(2, 4), ColorBlock(1, 4), ColorBlock(1, 8)] line = [colors] * 4 with pytest.raises(NonogramError): tuple(self.solve_as_color_sets(desc, line))
def test_lengthy_undefined(self, colors): desc = [ColorBlock(2, 4), ColorBlock(1, 4), ColorBlock(1, 8)] line = [colors] * 6 assert tuple(self.solve_as_color_sets(desc, line)) == ( 4 | SPACE_C, 4, 4 | SPACE_C, 4 | SPACE_C, 4 | 8 | SPACE_C, 8 | SPACE_C)
def test_undefined(self, colors): desc = [ColorBlock(1, 4)] line = [colors] * 2 assert tuple(self.solve_as_color_sets(desc, line)) == (4 | SPACE_C, 4 | SPACE_C)
def test_solved_partial_remove_prefix(self): assert f([ColorBlock(BB, 2), ColorBlock(BB, 4)], [space, 2, 2, 3, space, 4, 4, space | 5]) == (2, 0)
def test_first_not_space(self, colors): desc = (ColorBlock(2, 4), ColorBlock(1, 8)) line = [4] + [colors] * 3 assert tuple(self.solve_as_color_sets(desc, line)) == ( 4, 4, 8 | SPACE_C, 8 | SPACE_C)
def test_solved_fully_one_block(self): assert f([ColorBlock(2, 2)], [2, 2]) == (2, 1)
def _update_block(cls, current, increase): return ColorBlock(current.size + increase, current.color)