Example #1
0
    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,
        )
Example #4
0
    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
Example #5
0
    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}")