def find(self, debugger: Debugger = Debugger(enabled=False)) -> Paths: def reporting_format(_: Debugger, message: str) -> str: return ( f"{message} ({len(paths)} found, {len(seen)} seen, " f"{len(stack)} in stack)" ) paths = [] stack: List[CaveFinderStateT] = [self.get_state_class().make_initial()] seen = {stack[0]} with debugger.adding_extra_report_format(reporting_format): debugger.default_report("Looking...") while debugger.step_if(stack): debugger.default_report_if("Looking...") state = stack.pop(0) for next_state in state.get_next_states(self.system.graph): if next_state in seen: continue seen.add(next_state) if next_state.is_terminal: paths.append(next_state.path) continue stack.append(next_state) debugger.default_report("Finished looking") return paths
def __mul__( self, count: int, debugger: Debugger = Debugger(enabled=False), ) -> "ModuloShuffle": cls = type(self) if count < 0: raise Exception(f"Cannot calculate negative count shuffle") # noinspection PyArgumentList total = cls( factor=1, offset=0, size=self.size, ) power_shuffle = self power = 1 remaining_count = count debugger.default_report( f"Remaining {math.ceil(math.log2(remaining_count))} rounds " f"({remaining_count}, {bin(remaining_count)})") while debugger.step_if(remaining_count): debugger.default_report_if( f"Remaining {math.ceil(math.log2(remaining_count))} rounds " f"({remaining_count}, {bin(remaining_count)})") if remaining_count % 2: total = total + power_shuffle remaining_count //= 2 power *= 2 power_shuffle = power_shuffle + power_shuffle return total
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 get_nth_phase_message( initial: Union[str, Iterable[int]], length: Optional[int] = None, count: int = 100, message_offset: int = 0, debugger: Debugger = Debugger(enabled=False), ) -> str: """ >>> get_nth_phase_message('12345678', count=4) '01029498' >>> get_nth_phase_message('80871224585914546619083218645595') '24176176' >>> get_nth_phase_message('19617804207202209144916044189917') '73745418' >>> get_nth_phase_message('69317163492948606335995924319873') '52432133' """ if length is None: if not hasattr(initial, '__str__'): raise Exception( f"Initial has no length capability, and no length was passed") length = len(initial) if isinstance(initial, str): initial = list(map(int, initial)) result = np.array(initial) # phase_patterns = list(map(list, get_phase_patterns(length))) debugger.default_report(f"Doing {count} iterations") for iteration in debugger.stepping(range(1, count + 1)): result = get_next_phase(result, length, debugger=debugger) debugger.default_report_if(f"Done {iteration}/{count}") return "".join(map(str, result[message_offset:message_offset + 8]))
def move_until_stop( self, debugger: Debugger = Debugger(enabled=False), ) -> Tuple[int, "Herd"]: """ >>> _step_count, final = Herd.from_herd_text(''' ... v...>>.vv> ... .vv>>.vv.. ... >>.>v>...v ... >>v>>.>.v. ... v>v.vv.v.. ... >.>>..v... ... .vv..>.>v. ... v.v..>>v.v ... ....v..v.> ... ''').move_until_stop() >>> _step_count 58 >>> print(final) :.>>v>vv.. ..v.>>vv.. ..>>v>>vv. ..>>>>>vv. v......>vv v>v....>>v vvv.....>> >vv......> .>v.vv.v.. """ moved = self for step_count in debugger.stepping(count(1)): previous = moved moved = moved.move() debugger.default_report_if("Searching...") if moved == previous: return step_count, previous
def get_index_at_position_after_shuffle_many( self, index, size, count, debugger: Debugger = Debugger(enabled=False), ): total_index = index shuffles = [ shuffle.make_get_index_at_position_after_shuffle(size) for shuffle in reversed(self.shuffles) ] for step in debugger.stepping(range(count)): for shuffle in shuffles: total_index = shuffle(total_index) if total_index == index: break debugger.default_report_if( f"Looking {int(step / count * 10000) / 100}% " f"(current is {total_index})...") else: return total_index cycle_length = step + 1 debugger.default_report(f"Found cycle of length {cycle_length}") for _ in debugger.stepping(range(count % cycle_length)): for shuffle in shuffles: total_index = shuffle(total_index) debugger.default_report_if( f"Finishing after cycle (current is {total_index})...") return total_index
def get_index_cycle( self, index, size, max_count=None, debugger: Debugger = Debugger(enabled=False), ): """ >>> list(ShufflesExtended.parse( ... "deal into new stack\\n" ... "cut -2\\n" ... "deal with increment 7\\n" ... "cut 8\\n" ... "cut -4\\n" ... "deal with increment 7\\n" ... "cut 3\\n" ... "deal with increment 9\\n" ... "deal with increment 3\\n" ... "cut -1\\n" ... ).get_index_cycle(0, 10)) [9, 6, 7, 0] >>> list(ShufflesExtended.parse( ... "deal into new stack\\n" ... "cut -2\\n" ... "deal with increment 7\\n" ... "cut 8\\n" ... "cut -4\\n" ... "deal with increment 7\\n" ... "cut 3\\n" ... "deal with increment 9\\n" ... "deal with increment 3\\n" ... "cut -1\\n" ... ).get_index_cycle(1, 10)) [2, 5, 4, 1] >>> list(ShufflesExtended.parse( ... "deal into new stack\\n" ... "cut -2\\n" ... "deal with increment 7\\n" ... "cut 8\\n" ... "cut -4\\n" ... "deal with increment 7\\n" ... "cut 3\\n" ... "deal with increment 9\\n" ... "deal with increment 3\\n" ... "cut -1\\n" ... ).get_index_cycle(3, 10)) [8, 3] """ if max_count is None: max_count = size search_index = index for step in range(max_count): search_index = self.get_index_at_position_after_shuffle( search_index, size) yield search_index if search_index == index: break debugger.default_report_if("Looking...")
def step_many( self, algorithm: IEAlgorithm, count: int, debugger: Debugger = Debugger(enabled=False), ) -> "Image": """ >>> _algorithm = IEAlgorithm.from_mapping_text( ... "..#.#..#####.#.#.#.###.##.....###.##.#..###.####..#####..#...." ... "#..#..##..###..######.###...####..#..#####..##..#.#####...##.#" ... ".#..#.##..#.#......#.###.######.###.####...#.##.##..#..#..####" ... "#.....#.#....###..#.##......#.....#..#..#..##..#...##.######.#" ... "###.####.#.#...#.......#..#.#.#...####.##.#......#..#...##.#.#" ... "#..#...##.#.##..###.#......#.#.......#.#.#.####.###.##...#...." ... ".####.#..#..#.##.#....##..#.####....##...##..#...#......#.#..." ... "....#.......##..####..#...#.#.#...##..#.#..###..#####........#" ... "..####......#..#" ... ) >>> image = Image.from_image_text(''' ... #..#. ... #.... ... ##..# ... ..#.. ... ..### ... ''') >>> print(":", image.step_many(_algorithm, 1)) : ......... ..##.##.. .#..#.#.. .##.#..#. .####..#. ..#..##.. ...##..#. ....#.#.. ......... >>> print(":", image.step_many(_algorithm, 2)) : ........... ........#.. ..#..#.#... .#.#...###. .#...##.#.. .#.....#.#. ..#.#####.. ...#.#####. ....##.##.. .....###... ........... """ result = self debugger.default_report(f"Stepping {count} times") for step in debugger.stepping(range(count)): result = result.step(algorithm) debugger.default_report_if( f"Stepped {step}/{count} times, {result.light_pixel_count} " f"lights in result, size of {tuple(result.boundary.size)}" ) return result
def apply( self, reactor: Reactor, debugger: Debugger = Debugger(enabled=False), ) -> Reactor: for step_index, step in debugger.stepping(enumerate(self.steps, 1)): step.apply(reactor) debugger.default_report_if( f"After {step_index} steps: {reactor.cube_count} cubes are on") return reactor
def solve( self, debugger: Debugger = Debugger(enabled=False), ) -> "QuantumGameSearch": while not debugger.step_if(self.finished): self.advance_once() debugger.default_report_if( f"Done {self.move_count} moves, with " f"{len(self.residual_state_counts)} remaining states, " f"currently {self.player_1_wins} vs {self.player_2_wins}") return self
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 apply( self, step_set: RebootStepSet, debugger: Debugger = Debugger(enabled=False), ) -> "RegionSet": region_class = self.get_region_class() for index, step in debugger.stepping(enumerate(step_set.steps, 1)): step_region = region_class.from_step(step) if step.set_to_on: self.add(step_region) else: self.remove(step_region) debugger.default_report_if( f"Done {index}/{len(step_set.steps)}, " f"{len(self.regions)} regions, {len(self)} total cubes") 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 get_code( self, index: int, debugger: Debugger = Debugger(enabled=False), ) -> int: """ >>> list(map(Grid().get_code, range(1, 5))) [20151125, 31916031, 18749137, 16080970] """ max_precomputed_index = self.get_max_precomputed_index(index) code = self.pre_computed_codes[max_precomputed_index] for computing_index \ in debugger.stepping(range(index - max_precomputed_index)): debugger.default_report_if(computing_index) code *= self.multiplier code %= self.modulo return code
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 find_min_mana_necessary( self, debugger: Debugger = Debugger(enabled=False), ) -> int: def reporting_format(_: Debugger, message: str) -> str: if min_mana_spent is None: min_mana_spent_str = "no winner yet" else: min_mana_spent_str = f"best is {min_mana_spent}" return f"{message} ({min_mana_spent_str}, {len(stack)} in stack)" with debugger.adding_extra_report_format(reporting_format): stack = [deepcopy(self)] min_mana_spent = None min_mana_game = None debugger.default_report_if("Searching for a winning game...") while debugger.step_if(stack): debugger.default_report_if("Searching for a winning game...") game = stack.pop(0) if min_mana_spent is not None \ and game.player.mana_spent >= min_mana_spent: continue next_games = game.get_next_games(debugger) for next_game in next_games: if (min_mana_spent is not None and next_game.player.mana_spent >= min_mana_spent): continue if next_game.winner == CharacterEnum.Player: min_mana_spent = next_game.player.mana_spent min_mana_game = next_game debugger.report(f"Better game found: {min_mana_spent}") stack.append(next_game) debugger.default_report(f"Finished searching") if min_mana_spent is None: raise Exception(f"Could not find a winning game") options_played_str = ', '.join( option.name for option in min_mana_game.options_played if isinstance(option, SpellEnum)) debugger.report(f"Min mana game moves: {options_played_str}") return min_mana_spent
def measure_distances( self, debugger: Debugger = Debugger(enabled=False), ) -> None: while debugger.step_if(self.stack): should_report = debugger.should_report() debugger.default_report_if( f"Seen {len(self.distances)}, {len(self.stack)} in stack, " f"target risk is {self.distances.get(self.target)}") if should_report: debugger.report(str(self)) state = self.stack.pop(0) if state.distance > self.distances[state.position]: continue for next_state in state.get_next_states(self): self.visit_state(next_state) if debugger.enabled: debugger.report(str(self))
def get_message_after_index( initial: str, debugger: Debugger = Debugger(enabled=False), ) -> str: """ >>> get_message_after_index("03036732577212944063491565474664") 84462026 """ start_index = int(initial[:7]) original_length = len(initial) length = original_length * 10000 skip_lengths_count = math.floor(start_index / original_length) lengths_count = int(length / original_length - skip_lengths_count) skipped_phase = list(map(int, initial)) * lengths_count skipped_offset = start_index - skip_lengths_count * original_length skipped_phase = skipped_phase[skipped_offset:] result = skipped_phase debugger.default_report(f"Looking for message skipping {start_index}") for _ in debugger.stepping(range(100)): result = get_next_phase_after_index(result, start_index) debugger.default_report_if(f"So far: {''.join(map(str, result[:8]))}") return "".join(map(str, result[:8]))
def get_next_phase( phase: np.ndarray, length: int, phase_patterns: Optional[List[np.ndarray]] = None, debugger: Debugger = Debugger(enabled=False), ) -> List[int]: """ >>> "".join(map(str, get_next_phase(np.array(list(map(int, '12345678'))), 8))) '48226158' >>> "".join(map(str, get_next_phase(np.array(list(map(int, '48226158'))), 8))) '34040438' >>> "".join(map(str, get_next_phase(np.array(list(map(int, '34040438'))), 8))) '03415518' >>> "".join(map(str, get_next_phase(np.array(list(map(int, '03415518'))), 8))) '01029498' """ # if phase_patterns is None: # phase_patterns = get_phase_patterns(length) if phase_patterns is None: indexes_and_phase_patterns = zip_longest( range(length), [], fillvalue=None, ) else: indexes_and_phase_patterns = enumerate(phase_patterns) next_phase = [] for index, phase_pattern in debugger.stepping(indexes_and_phase_patterns): next_phase.append( get_element_for_next_phase(phase, length, index, phase_pattern=phase_pattern)) debugger.default_report_if( f"{index}/{length} ({index * 100 // length}%)") return next_phase
def find_scanners_positions( self, debugger: Debugger = Debugger(enabled=False), ) -> List[Tuple[BeaconT, ScannerT]]: """ >>> # noinspection PyUnresolvedReferences >>> [_position for _position, _ in Scanner2DSet.from_scanners_text(''' ... --- scanner 0 --- ... 0,2 ... 4,1 ... 3,3 ... ... --- scanner 1 --- ... -1,-1 ... -5,0 ... -2,1 ... ''').find_scanners_positions()] [Beacon2D(x=0, y=0), Beacon2D(x=5, y=2)] """ if not self.scanners: return [] beacon_class = self.get_beacon_class() first_scanner = self.scanners[0] positions_and_scanners_by_scanner: Dict[int, Tuple[BeaconT, ScannerT]] \ = { id(first_scanner): (beacon_class.get_zero_point(), first_scanner) } found_scanners = [first_scanner] remaining_scanners = self.scanners[1:] debugger.default_report( f"Looking for {len(self.scanners) - 1} positions, found " f"{len(found_scanners) - 1}") while remaining_scanners: for other_index, other in enumerate(remaining_scanners): for found_index, found_scanner \ in debugger.step_if(enumerate(found_scanners)): debugger.default_report_if( f"Looking for {len(self.scanners) - 1} positions, " f"found {len(found_scanners) - 1}") found_position, found_reoriented = \ positions_and_scanners_by_scanner[id(found_scanner)] position_and_scanner = \ found_reoriented.find_other_scanner_position( other, self.min_overlap, ) if not position_and_scanner: continue position, reoriented = position_and_scanner position = position.offset(found_position) found_scanners.append(other) positions_and_scanners_by_scanner[id(other)] = \ position, reoriented remaining_scanners.remove(other) break else: continue break else: raise Exception(f"Could not find any remaining scanner " f"({len(remaining_scanners)} remaining out of " f"{len(self.scanners)})") return [ positions_and_scanners_by_scanner[id(scanner)] for scanner in self.scanners ]