def get_checksum(self, data: str, debugger: Debugger) -> str: """ >>> DataGenerator().get_checksum("110010110100") '100' >>> DataGenerator().get_checksum("110101") '100' >>> DataGenerator().get_checksum("100") '100' >>> DataGenerator().get_checksum("10000011110010000111") '01100' """ reduced = data while True: new_reduced = self.reduce_data(reduced) if new_reduced == reduced: break reduced = new_reduced if debugger.should_report(): debugger.report( f"Check summing, step: {debugger.step_count}, time: " f"{debugger.pretty_duration_since_start}, size: " f"{len(reduced)}/{len(data)}") return reduced
def solve(self, _input, debugger: Debugger): """ >>> Challenge().default_solve() 22887907 """ firewall = Firewall.from_ranges_text(_input) if debugger.should_report(): debugger.report(f"Total range: {firewall.total_range}") for _range in firewall.blocked_ranges: debugger.report(f" {_range}") return firewall.get_lowest_non_blocked_value()
def __add__( self, other: "ModuloShuffle", debugger: Debugger = Debugger(enabled=False), ) -> "ModuloShuffle": """ >>> ShufflesExtended.parse(''' ... deal with increment 7 ... deal into new stack ... deal into new stack ... ''').to_modulo_shuffle_for_size(10).shuffle_deck(tuple(range(10))) (0, 3, 6, 9, 2, 5, 8, 1, 4, 7) >>> ShufflesExtended.parse(''' ... cut 6 ... deal with increment 7 ... deal into new stack ... ''').to_modulo_shuffle_for_size(10).shuffle_deck(tuple(range(10))) (3, 0, 7, 4, 1, 8, 5, 2, 9, 6) >>> ShufflesExtended.parse(''' ... deal with increment 7 ... deal with increment 9 ... cut -2 ... ''').to_modulo_shuffle_for_size(10).shuffle_deck(tuple(range(10))) (6, 3, 0, 7, 4, 1, 8, 5, 2, 9) >>> 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" ... ).to_modulo_shuffle_for_size(10).shuffle_deck(tuple(range(10))) (9, 2, 5, 8, 1, 4, 7, 0, 3, 6) """ if self.size != other.size: raise Exception(f"Cannot combine shuffles with different sizes") debugger.report(f"Add {self} + {other}") cls = type(self) # noinspection PyArgumentList return cls( factor=(other.factor * self.factor) % self.size, offset=(other.offset * self.factor + self.offset) % self.size, size=self.size, )
def fill_disk(self, size: int, initial: str, debugger: Debugger) -> str: """ >>> DataGenerator().fill_disk(20, "10000") '10000011110010000111' """ disk = initial while len(disk) < size: disk = self.increase_data(disk) if debugger.should_report(): debugger.report( f"Filling, step: {debugger.step_count}, time: " f"{debugger.pretty_duration_since_start}, size: " f"{len(disk)}/{size}") disk = disk[:size] return disk
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 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}")