Пример #1
0
                return SolverDay22._count_score(d2), False
            if not d2:
                return SolverDay22._count_score(d1), True

            as_tuple = (tuple(d1), tuple(d2))
            if as_tuple in seen:
                return SolverDay22._count_score(d1), True
            seen.add(as_tuple)

            c1, c2 = d1.popleft(), d2.popleft()
            if len(d1) < c1 or len(d2) < c2:
                p1_winner = c1 > c2
            else:
                _, p1_winner = SolverDay22._recursive_combat(
                    deque(islice(d1, 0, c1)), deque(islice(d2, 0, c2)))

            if p1_winner:
                d1.extend([c1, c2])
            else:
                d2.extend([c2, c1])

    def part2(self) -> int:
        d1, d2 = self.puzzle.data
        return SolverDay22._recursive_combat(d1, d2)[0]


if __name__ == '__main__':
    SolverDay22(
        PuzzleDownloader(day=22,
                         parser=SolverDay22.parser).get_puzzle()).run()
Пример #2
0
        dimensions = (len(cells[0]) // 2, len(cells) // 2, 0, 0)
        active = set()
        for y in range(len(cells)):
            for x in range(len(cells[0])):
                if cells[y][x] == "#":
                    active.add(
                        (x - len(cells[0]) // 2, y - len(cells) // 2, 0, 0))

        return SmarterMultiverse(active_cells=active, dimensions=dimensions)

    def part1(self) -> int:
        u = BoringVerse(active_cells=self.puzzle.data.active_cells,
                        dimensions=self.puzzle.data.dimensions)
        for _ in range(6):
            # should fix it so that .run_cycle return self.type, but...
            u = u.run_cycle()  # type: ignore
        return len(u.active_cells)

    def part2(self) -> int:
        mu = self.puzzle.data
        for _ in range(6):
            mu = mu.run_cycle()
        return len(mu.active_cells)


if __name__ == '__main__':
    SolverDay17(
        PuzzleDownloader(day=17,
                         parser=SolverDay17.parser).get_puzzle()).run()
Пример #3
0
from aoc2020.shared.models import NoResultFoundException
from aoc2020.shared.puzzle import Puzzle, PuzzleDownloader
from aoc2020.shared.solver import Solver


@dataclass
class SolverDay1(Solver):
    puzzle: Puzzle[List[int]]
    TARGET: ClassVar[int] = 2020

    def _solve_for(self, n: int) -> int:
        for x in combinations(self.puzzle.data, n):
            if sum(x) == self.TARGET:
                return prod(x)
        else:
            raise NoResultFoundException

    def part1(self) -> int:
        return self._solve_for(2)

    def part2(self) -> int:
        return self._solve_for(3)


def parser(string: str) -> List[int]:
    return list(map(int, string.splitlines()))


if __name__ == '__main__':
    SolverDay1(PuzzleDownloader(day=1, parser=parser).get_puzzle()).run()
Пример #4
0
    @groupwise_parser
    def parser(group: Iterable[str]) -> Union[ValidationError, Passport]:
        single_line = " ".join(group)
        fields_as_str = single_line.split(" ")
        as_dict = {tuple(s.split(":")) for s in fields_as_str}
        try:
            return Passport.parse_obj(as_dict)
        except ValidationError as v:
            return v

    def part1(self) -> int:
        count = 0
        for maybe_passport in self.puzzle.data:
            if isinstance(maybe_passport, Passport):
                count += 1
            # part 1 doesn't care about anything but the correct fields being there (ie the MissingError)
            elif all([not isinstance(err.exc, MissingError) for err in maybe_passport.raw_errors]):  # type: ignore
                count += 1
        return count

    def part2(self) -> int:
        count = 0
        for maybe_passport in self.puzzle.data:
            if isinstance(maybe_passport, Passport):
                count += 1
        return count


if __name__ == '__main__':
    SolverDay4(PuzzleDownloader(day=4, parser=SolverDay4.parser).get_puzzle()).run()
Пример #5
0
        parser = Lark("\n".join(named_rules), start="r0")
        ok_count = 0
        for line in self.puzzle.data[1].splitlines():
            try:
                parser.parse(line)
                ok_count += 1
            except LarkError:
                pass
        return ok_count

    def part1(self) -> int:
        return self._count_ok(self.puzzle.data[0].splitlines())

    def part2(self) -> int:
        input_rules = []
        for rule in self.puzzle.data[0].splitlines():
            if not (rule.startswith("8:") or rule.startswith("11:")):
                input_rules.append(rule)

        new_rules_str = """\
            8: 42 | 42 8
            11: 42 31 | 42 11 31"""
        new_rules = dedent(new_rules_str).splitlines()
        rules = input_rules + new_rules

        return self._count_ok(rules)


if __name__ == '__main__':
    SolverDay19(PuzzleDownloader(day=19, parser=SolverDay19.parser).get_puzzle()).run()
Пример #6
0
    puzzle: Puzzle
    _divider = 20201227

    def _transformations(self, subject_number: int) -> Iterator[Tuple[int, int]]:
        """Yields the loop number and the its associated value"""
        value = 1
        loop = 0
        while True:
            value *= subject_number
            value %= self._divider
            yield loop, value
            loop += 1

    @staticmethod
    def parser(input_: str) -> Tuple[CardPK, DoorPK]:
        card, door = input_.splitlines()
        return int(card), int(door)

    def part1(self) -> int:
        card_pk, door_pk = self.puzzle.data
        for loop, value in self._transformations(7):
            if value == card_pk:
                return next(islice(self._transformations(door_pk), loop, loop + 1))[1]
            if value == door_pk:
                return next(islice(self._transformations(card_pk), loop, loop + 1))[1]
        raise ValueError  # should be unreachable


if __name__ == '__main__':
    SolverDay25(PuzzleDownloader(day=25, parser=SolverDay25.parser).get_puzzle()).run()
Пример #7
0
            **self.puzzle.data[index].dict(by_alias=True), "code":
            new_instruction_cls.__name__.lower()
        }
        new_instruction_set[index] = new_instruction_cls.parse_obj(
            new_instruction)
        return new_instruction_set

    def part2(self) -> int:
        for index, instruction in enumerate(self.puzzle.data):
            if instruction.code == "acc":
                continue
            elif instruction.code == "jmp":
                new_instruction_set = self._mutate_instruction(index, Nop)
            elif instruction.code == "nop":
                new_instruction_set = self._mutate_instruction(index, Jmp)
            else:
                assert_never(instruction.code)

            interpreter = Interpreter(new_instruction_set)

            try:
                return interpreter.run()
            except LoopDetected:
                pass
        raise NoResultFoundException


if __name__ == '__main__':
    SolverDay8(PuzzleDownloader(day=8,
                                parser=SolverDay8.parser).get_puzzle()).run()
Пример #8
0
        return sum(map(lambda l: l.count("#"), s)) - len(monster_zones)

    @staticmethod
    def _monster_shape() -> List[Tuple[int, int]]:
        s = """\
                  # 
#    ##    ##    ###
 #  #  #  #  #  #   """
        res = []
        for y, row in enumerate(s.splitlines()):
            for x, cell in enumerate(row):
                if cell == "#":
                    res.append((x, y))
        return res

    @staticmethod
    def _detect_monster(image: List[str], xx: int, yy: int) -> Optional[Set[Tuple[int, int]]]:
        adjusted = set(map(lambda t: (t[0] + xx, t[1] + yy), SolverDay20._monster_shape()))
        try:
            for x, y in adjusted:
                if not image[y][x] == "#":
                    return None
            return adjusted
        except IndexError:
            return None


if __name__ == '__main__':
    SolverDay20(PuzzleDownloader(day=20, parser=SolverDay20.parser).get_puzzle()).run()
Пример #9
0
    @staticmethod
    @groupwise_parser
    def parser(group: Iterable[str]) -> List[str]:
        answers = []
        for answer_per_person in group:
            no_blanks = answer_per_person.replace(" ", "")
            answers.append(no_blanks)
        return answers

    def part1(self) -> int:
        count = 0
        for answers_per_group in self.puzzle.data:
            answers_in_group = set()
            for answers_per_person in answers_per_group:
                answers_in_group.update(list(answers_per_person))
            count += len(answers_in_group)
        return count

    def part2(self) -> int:
        count = 0
        for answers_per_group in self.puzzle.data:
            as_sets = map(set, answers_per_group)  # type: ignore
            common_answers = reduce(set.intersection, as_sets)
            count += len(common_answers)
        return count


if __name__ == '__main__':
    SolverDay6(PuzzleDownloader(day=6, parser=SolverDay6.parser).get_puzzle()).run()