def _color_code(cls, cell): if is_color_cell(cell): single_colors = two_powers(cell) if len(single_colors) > 3: # allow two and three colors # multiple colors return UNKNOWN return cell
def __init__(self, value, renderer, colored=False): super(GridCell, self).__init__() self.renderer = renderer self.colored = colored if self.colored: self.value = tuple(two_powers(value)) else: self.value = value
def match(self, word): one_color_word = [] for letter in word: letter = two_powers(letter) if len(letter) == 1: letter = letter[0] one_color_word.append(letter) return super(NonogramFSMColored, self).match(one_color_word)
def test_random(self): for i in range(100): n = random.randint(1, 10**9) factors = two_powers(n) assert len(factors) > 0 # factors are unique assert len(set(factors)) == len(factors) assert sum(factors) == n for f in factors: b = bin(f) assert b == '0b1' + '0' * (len(b) - 3)
def block_ranges_left(cls, description, line): """ Shift the blocks to the left and find valid start positions """ # line_colors = set(block.color for block in description) allowed_colors_positions = defaultdict(list) for index, cell in enumerate(line): for single_color in two_powers(cell): allowed_colors_positions[single_color].append(index) min_start_indexes = cls.calc_block_sum(description)[1:] LOG.debug(min_start_indexes) for block_index, block in enumerate(description): color = block.color # do not do `zip(desc, min_indexes)` because min_indexes changes min_index = min_start_indexes[block_index] rang = [ index for index in allowed_colors_positions[color] if index >= min_index ] if not rang: raise NonogramError( 'The #{} block ({}) cannot be placed'.format( block_index, block)) min_index_shift = min(rang) - min_index if min_index_shift > 0: LOG.info( 'Minimum starting index for block #%i (%r) updated: %i --> %i', block_index, block, min_index, min_index + min_index_shift) min_start_indexes[block_index:] = [ i + min_index_shift for i in min_start_indexes[block_index:] ] yield rang LOG.debug(min_start_indexes)
def _types_for_cell(cls, cell): return two_powers(cell)
def starting_solved(cls, description, line): """ Trim off the solved cells from the beginning of the line. Also fix the description respectively. Return the pair (number of solved cells, number of solved blocks) """ space = SPACE_COLORED block_index = 0 last_block = len(description) - 1 pos = 0 last_pos = len(line) - 1 while pos <= last_pos: # skip definite spaces if line[pos] == space: pos += 1 continue cell = line[pos] cell_colors = two_powers(cell) if len(cell_colors) > 1: break color = cell_colors[0] if block_index > last_block: raise NonogramError('Bad block index {} ' 'for description {!r}'.format( block_index, description)) block = description[block_index] if color != block.color: raise NonogramError( 'Color {!r} at the position {!r} of the line {!r}' 'does not match the color of the corresponding block {!r} ' 'in description {!r}'.format(color, pos, line, block, description)) size = block.size if size == BlottedBlock: end_pos = pos + 1 while end_pos <= last_pos and line[end_pos] == color: end_pos += 1 if end_pos <= last_pos: cell_colors = two_powers(line[end_pos]) # can't say definitely whether the blotted block ends here if color in cell_colors: # the partially solved blotted block can be reduced to one cell pos = end_pos - 1 break pos = end_pos block_index += 1 else: if pos + size > last_pos + 1: raise NonogramError( 'The {}-th block {!r} cannot be allocated in the line {!r}' .format(block_index, block, line)) if line[pos:pos + size] != [color] * size: break if block_index < last_block: next_block = description[block_index + 1] if next_block.color == color: try: if line[pos + size] != space: break except IndexError: raise NonogramError( 'The next ({}-th) block {!r} ' 'cannot be allocated in the line {!r}'.format( block_index + 1, next_block, line)) pos += size block_index += 1 return pos, block_index
def test_round_trip(self): for i in range(100): n = random.randint(1, 10**9) factors = two_powers(n) assert from_two_powers(factors) == n
def test_simple(self): assert two_powers(42) == (2, 8, 32) assert two_powers(103) == (1, 2, 4, 32, 64)
def test_one(self): assert two_powers(1) == (1, )
def test_zero(self): assert two_powers(0) == ()
def is_solved(cls, description, line): if any(len(two_powers(cell)) > 1 for cell in line): return False return BlottedBlock.matches(description, line)