def step_many(self, step_count: int, debugger: Debugger = Debugger(enabled=False)): """ >>> print("!" + Life.from_life_text( ... ".#.#.#\\n" ... "...##.\\n" ... "#....#\\n" ... "..#...\\n" ... "#.#..#\\n" ... "####..\\n" ... ).step_many(4).show()) !...... ...... ..##.. ..##.. ...... ...... """ current = self debugger.reset() for _ in debugger.stepping(range(step_count)): current = current.step() debugger.default_report_if() return current
def add_rows(self, count: int, debugger: Debugger = Debugger(enabled=False)): """ >>> print("!" + Minefield.from_rows_text('..^^.').add_rows(2).show()) !..^^. .^^^^ ^^..^ >>> print("!" + Minefield.from_rows_text( ... '.^^.^.^^^^').add_rows(9).show()) !.^^.^.^^^^ ^^^...^..^ ^.^^.^.^^. ..^^...^^^ .^^^^.^^.^ ^^..^.^^.. ^^^^..^^^. ^..^^^^.^^ .^^^..^.^^ ^^.^^^..^^ """ debugger.reset() total_target = len(self.rows) + count for _ in range(count): self.add_row() debugger.step() if debugger.should_report(): debugger.default_report( f"rows: {len(self.rows)}/{total_target}") return self
def solve( self, node_set: 'NodeSetExtended', target: Point2D = Point2D.ZERO_POINT, debugger: Debugger = Debugger(enabled=False), ) -> List['NodeSetExtended']: stack = [node_set] previous_map: PreviousMap = {node_set: None} duplicate_count = 0 debugger.reset() target_position_map = self.get_target_positions(node_set) debugger.reset() while debugger.step_if(stack): current_node_set = stack.pop(0) next_states = self.get_next_states( current_node_set, target_position_map) for next_node_set in next_states: if next_node_set in previous_map: duplicate_count += 1 continue previous_map[next_node_set] = current_node_set if next_node_set.position == target: return self.get_solution(next_node_set, previous_map) stack.append(next_node_set) if debugger.should_report(): debugger.default_report( f"stack: {len(stack)}, pruned: {duplicate_count}") raise Exception(f"Could not find solution")
def get_next_password( self, debugger: Debugger = Debugger(enabled=False), ) -> 'Password': """ >>> Password('abcdefgh').get_next_password() 'abcdffaa' >>> Password('ghijklmn').get_next_password() 'ghjaabcc' """ debugger.reset() for password in debugger.stepping(self.get_next_password_candidates()): if password.is_valid(): return password debugger.default_report_if(password)
def step_many( self, sequence: str, step_count: int = 40, debugger: Debugger = Debugger(enabled=False)) -> str: """ >>> LookAndSay().step_many("1", 5) '312211' """ debugger.reset() result = sequence for step in debugger.stepping(range(step_count)): result = self.step(result) if debugger.should_report(): debugger.default_report(f"step {step}/{step_count}") return result
def step_many(self, step_count: Optional[int] = None, debugger: Debugger = Debugger(enabled=False)): if step_count is None: steps = count() else: steps = range(step_count) debugger.reset() for _ in debugger.stepping(steps): self.step() if self.has_finished(): break if debugger.should_report(): debugger.default_report( f"remaining: {len(self.get_remaining_positions())}, " f"position: {self.position}") return self
def get_lowest_index_with_zeros( self, start: int = 1, zero_count: int = 5, debugger: Debugger = Debugger(enabled=False)) -> int: """ >>> Hasher("abcdef").get_lowest_index_with_zeros() 609043 >>> Hasher("pqrstuv").get_lowest_index_with_zeros() 1048970 """ prefix = '0' * zero_count debugger.reset() for index in debugger.stepping(count(start)): if self.does_index_give_hash_prefix(index, prefix): return index debugger.default_report_if(index)
def apply( self, matrix: Optional[MatrixT] = None, debugger: Debugger = Debugger(enabled=False) ) -> MatrixT: """ >>> InstructionSet.from_instructions_text( ... "turn on 0,0 through 999,999").apply().get_brightness_total() 2000000 """ if matrix is None: matrix_class = self.get_matrix_class() matrix = matrix_class() debugger.reset() for instruction in debugger.stepping(self.instructions): instruction.apply(matrix) debugger.default_report_if() return matrix
def apply_extended( self, state: Optional[StateExtended] = None, debugger: Debugger = Debugger(enabled=False), ) -> StateExtended: """ >>> def check(instructions_text, state_values=None, program_counter=0): ... _state = InstructionSetExtended\\ ... .from_instructions_text(instructions_text)\\ ... .apply_extended(StateExtended( ... state_values or {}, program_counter)) ... # noinspection PyUnresolvedReferences ... values = { ... name: value ... for name, value in _state.values.items() ... if value ... } ... return values, _state.program_counter >>> check( ... "cpy 2 a\\n" ... "tgl a\\n" ... "tgl a\\n" ... "tgl a\\n" ... "cpy 1 a\\n" ... "dec a\\n" ... "dec a\\n" ... ) ({'a': 3}, 7) """ if state is None: state = StateExtended() state.instructions = list(self.instructions) debugger.reset() while debugger.step_if( 0 <= state.program_counter < len(state.instructions)): self.step(state) if debugger.should_report(): debugger.default_report( f"values: {state.values}, pc: {state.program_counter}") return state
def get_min_house_number_with_at_least_present_count( self, min_present_count: int, debugger: Debugger = Debugger(enabled=False) ) -> int: """ >>> Santa().get_min_house_number_with_at_least_present_count(100) 6 """ max_present_count_seen = None debugger.reset() for house_number in debugger.stepping(count(1)): present_count = self.get_house_present_count(house_number) if present_count >= min_present_count: return house_number if max_present_count_seen is None \ or present_count > max_present_count_seen: max_present_count_seen = present_count if debugger.should_report(): debugger.default_report( f"max presents: {max_present_count_seen}" f"/{min_present_count}")
def get_all_possible_chains( self, start: str, prune: Optional[Callable[[str], bool]] = None, debugger: Debugger = Debugger(enabled=False), ) -> Iterable[Tuple[str, ...]]: """ >>> list(MachineExtended().get_all_possible_chains("")) [] >>> list(MachineExtended({'H': ['O']}).get_all_possible_chains("HH")) [('HH', 'OH'), ('HH', 'HO'), ('HH', 'OH', 'OO'), ('HH', 'HO', 'OO')] >>> list(MachineExtended({'H': ['O']}).get_all_possible_chains( ... "HH", lambda step: step != 'HO')) [('HH', 'OH'), ('HH', 'OH', 'OO')] >>> list(MachineExtended({'H': ['OH']}).get_all_possible_chains( ... "HH", lambda step: len(step) <= 4)) [('HH', 'OHH'), ('HH', 'HOH'), ('HH', 'OHH', 'OOHH'), ('HH', 'OHH', 'OHOH'), ('HH', 'HOH', 'OHOH'), ('HH', 'HOH', 'HOOH')] >>> list(MachineExtended({'H': ['O'], 'O': ['H']}) ... .get_all_possible_chains("HH")) [('HH', 'OH'), ('HH', 'HO'), ('HH', 'OH', 'OO'), ('HH', 'HO', 'OO'), ('HH', 'OH', 'OO', 'HO'), ('HH', 'HO', 'OO', 'OH')] """ stack = [(start, ())] debugger.reset() while stack: current, chain = stack.pop() next_chain = chain + (current, ) for next_step in self.get_all_possible_next_steps(current): if next_step in next_chain: continue if prune and not prune(next_step): continue yield next_chain + (next_step, ) stack.append((next_step, next_chain)) if debugger.should_report(): debugger.default_report(f"stack size: {len(stack)}, " f"end length: {len(next_chain[-1])}, " f"chain length: {len(next_chain)}")
def find_paths( self, start: Point2D = Point2D(0, 0), finish: Point2D = Point2D(3, 3), debugger: Debugger = Debugger(enabled=False), ) -> Iterable[str]: if start == finish: yield '' stack = [('', Point2D(0, 0))] debugger.reset() path_count = 0 largest_path = None while stack: path, position = stack.pop(0) path_door_states = self.get_path_door_states(path) for direction, door_is_open in path_door_states.items(): if not door_is_open: continue next_position = position.offset(direction.offset) if not self.is_position_valid(next_position): continue next_path = f"{path}{direction.value}" if next_position == finish: path_count += 1 largest_path = next_path yield next_path else: stack.append((next_path, next_position)) debugger.step() if debugger.should_report(): debugger.report( f"Step: {debugger.step_count}, time: " f"{debugger.pretty_duration_since_start}, stack: " f"{len(stack)}, paths: {path_count}, largest path: " f"{largest_path and len(largest_path)}, average speed: " f"{debugger.step_frequency}, recent speed: " f"{debugger.step_frequency_since_last_report}")