Exemple #1
0
        elif (turn := self._turn.get(action)) is not None:
            radians = math.radians(value * turn)
            self.direction *= complex(math.cos(radians), math.sin(radians))
        elif action == self._forward:
            self.forward(value)
        else:
            raise ValueError(f"unknown action '{action}'")


def parse_puzzle_input(
        puzzle_input: Sequence[str]) -> Sequence[Tuple[str, int]]:
    return tuple((s[0], int(s[1:])) for s in puzzle_input)


def solve_first_part(puzzle_input: Sequence[str]) -> int:
    intructions = parse_puzzle_input(puzzle_input)
    ship = Ship()
    for action, value in intructions:
        ship.execute(action, value)
    di, dj = math.fabs(ship.coordinates.real), math.fabs(ship.coordinates.imag)
    return round(di) + round(dj)


def solve_second_part(puzzle_input: Sequence[str]) -> int:
    return -1


if __name__ == "__main__":
    puzzle_input = get_puzzle_input("day12")
    print_puzzle(puzzle_input, solve_first_part, solve_second_part)
Exemple #2
0
def iter_triples_that_sum_to_target(
    integer_set: Set[int], target: int
) -> Iterable[Tuple[int, int]]:
    for i in integer_set:
        diff = target - i
        for pair in iter_pairs_that_sum_to_target(integer_set, diff):
            yield i, *pair


def solve_first_part(puzzle_input: Sequence[str]) -> int:
    integer_set = set(parse_puzzle_input(puzzle_input))
    try:
        a, b = next(iter_pairs_that_sum_to_target(integer_set, PUZZLE_TARGET))
    except StopIteration as e:
        raise ValueError(f"found no pair that sum to {PUZZLE_TARGET}") from e
    return a * b


def solve_second_part(puzzle_input: Sequence[str]) -> int:
    integer_set = set(parse_puzzle_input(puzzle_input))
    try:
        a, b, c = next(iter_triples_that_sum_to_target(integer_set, PUZZLE_TARGET))
    except StopIteration as e:
        raise ValueError(f"found no triple that sum to {PUZZLE_TARGET}") from e
    return a * b * c


if __name__ == "__main__":
    puzzle_input = get_puzzle_input("day01")
    print_puzzle(puzzle_input, solve_first_part, solve_second_part)
Exemple #3
0
        return False

    return outer_contains_inner


def make_count_func(rules: Dict[str, Rule]) -> Callable[[str], int]:
    @cache
    def count_contained_bags(outer: str) -> int:
        return sum(bag.quantity +
                   count_contained_bags(bag.color) * bag.quantity
                   for bag in rules[outer].content)

    return count_contained_bags


def solve_first_part(puzzle_input: Sequence[str]) -> int:
    rules = parse_puzzle_input(puzzle_input)
    outer_contains_inner = make_search_func(rules)
    return sum(outer_contains_inner(color, "shiny gold") for color in rules)


def solve_second_part(puzzle_input: Sequence[str]) -> int:
    rules = parse_puzzle_input(puzzle_input)
    count_contained_bags = make_count_func(rules)
    return count_contained_bags("shiny gold")


if __name__ == "__main__":
    puzzle_input = get_puzzle_input("day07")
    print_puzzle(puzzle_input, solve_first_part, solve_second_part)
Exemple #4
0
    def count_occupied_seats(self) -> int:
        return sum(s.occupied for s in self._sparse_grid.values())

    def stabilize(self) -> int:
        while True:
            if self.update_seats() == 0:
                return self.count_occupied_seats()

    def to_grid(self):
        range_i, range_j = self._dim
        grid = [["." for _ in range_i] for _ in range_j]
        for k, v in self._sparse_grid.items():
            grid[int(k.real)][int(k.imag)] = v
        return grid

    def __str__(self) -> str:
        return "\n".join("".join(r) for r in self.to_grid())


def solve_first_part(puzzle_input: Sequence[str]) -> int:
    return SeatGrid(puzzle_input, 4, False).stabilize()


def solve_second_part(puzzle_input: Sequence[str]) -> int:
    return SeatGrid(puzzle_input, 5, True).stabilize()


if __name__ == "__main__":
    puzzle_input = get_puzzle_input("day11")
    print_puzzle(puzzle_input, solve_first_part, solve_second_part)
Exemple #5
0
    counter = {1: 0, 2: 0, 3: 0}
    rating = 0
    for a in adapters:
        counter[a - rating] += 1
        rating = a
    return counter


def count_arrangements(adapters: Sequence[int]) -> int:
    diffs = [1, 2, 3]
    counter = {0: 1}
    for a in adapters:
        counter[a] = sum(map(lambda i: counter.get(a - i, 0), diffs))
    return counter[adapters[-1]]


def solve_first_part(puzzle_input: Sequence[str]) -> int:
    adapters = parse_puzzle_input(puzzle_input)
    counter = count_differences(adapters)
    return counter[1] * counter[3]


def solve_second_part(puzzle_input: Sequence[str]) -> int:
    adapters = parse_puzzle_input(puzzle_input)
    return count_arrangements(adapters)


if __name__ == "__main__":
    puzzle_input = get_puzzle_input("day10")
    print_puzzle(puzzle_input, solve_first_part, solve_second_part)
Exemple #6
0
def validate_first_policy(item: PuzzleItem) -> bool:
    letter_count = sum(char is item.letter for char in item.password)
    return item.x1 <= letter_count <= item.x2


def get_char(x: str, one_based_index: int) -> Optional[str]:
    zero_based_index = one_based_index - 1
    try:
        return x[zero_based_index]
    except IndexError:
        return


def validate_second_policy(item: PuzzleItem) -> bool:
    a, b = get_char(item.password, item.x1), get_char(item.password, item.x2)
    return (a == item.letter or b == item.letter) and a != b


def solve_first_part(puzzle_input: Sequence[str]) -> int:
    return count_valid_items(puzzle_input, validate_first_policy)


def solve_second_part(puzzle_input: Sequence[str]) -> int:
    return count_valid_items(puzzle_input, validate_second_policy)


if __name__ == "__main__":
    puzzle_input = get_puzzle_input("day02")
    print_puzzle(puzzle_input, solve_first_part, solve_second_part)
Exemple #7
0
    (7, 1),
    (1, 2),
)


def count_trees_in_path(puzzle_input: Sequence[str], right: int, down: int) -> int:
    count = 0
    i, j = 0, 0
    while i < len(puzzle_input) - down:
        i += down
        row = puzzle_input[i]
        j = (j + right) % len(row)
        count += row[j] == "#"
    return count


def solve_first_part(puzzle_input: Sequence[str]) -> int:
    return count_trees_in_path(puzzle_input, *PUZZLE_SLOPES[0])


def solve_second_part(puzzle_input: Sequence[str]) -> int:
    return math.prod(
        count_trees_in_path(puzzle_input, right, down)
        for right, down in PUZZLE_SLOPES[1:]
    )


if __name__ == "__main__":
    puzzle_input = get_puzzle_input("day03")
    print_puzzle(puzzle_input, solve_first_part, solve_second_part)
Exemple #8
0
from aoc2020.puzzle import print_puzzle


def parse_puzzle_input(puzzle_input: Sequence[str]) -> Sequence[Sequence[str]]:
    return tuple(tuple(v) for k, v in groupby(puzzle_input, lambda x: len(x) > 0) if k)


def count_any(answers: Sequence[str]) -> int:
    return len(set(chain.from_iterable(answers)))


def count_all(answers: Sequence[str]) -> int:
    group_size = len(answers)
    counter = Counter(chain.from_iterable(answers))
    return sum(c == group_size for c in counter.values())


def solve_first_part(puzzle_input: Sequence[str]) -> int:
    answers_list = parse_puzzle_input(puzzle_input)
    return sum(count_any(a) for a in answers_list)


def solve_second_part(puzzle_input: Sequence[str]) -> int:
    answers_list = parse_puzzle_input(puzzle_input)
    return sum(count_all(a) for a in answers_list)


if __name__ == "__main__":
    puzzle_input = get_puzzle_input("day06")
    print_puzzle(puzzle_input, solve_first_part, solve_second_part)
Exemple #9
0
    total = integers[lower] + integers[upper - 1]
    while upper <= len(integers):
        if total < target:
            total += integers[upper]
            upper += 1
        elif total > target:
            total -= integers[lower]
            lower += 1
        else:
            return tuple(integers[lower:upper])
    raise ValueError("did not find any continuous tuple")


def solve_first_part(puzzle_input: Sequence[str],
                     preamble: int = PUZZLE_PREAMBLE) -> int:
    integers = parse_puzzle_input(puzzle_input)
    return find_weakness(integers, preamble)


def solve_second_part(puzzle_input: Sequence[str],
                      preamble: int = PUZZLE_PREAMBLE) -> int:
    integers = parse_puzzle_input(puzzle_input)
    weakness = find_weakness(integers, preamble)
    contiguous_tuple = find_contiguous_tuple(integers, weakness)
    return min(contiguous_tuple) + max(contiguous_tuple)


if __name__ == "__main__":
    puzzle_input = get_puzzle_input("day09")
    print_puzzle(puzzle_input, solve_first_part, solve_second_part)
Exemple #10
0
        operation, argument = instructions[i]
        if operation is Operation.ACC:
            accumulator += argument
        i += argument if operation is Operation.JMP else 1
    return accumulator


def solve_first_part(puzzle_input: Sequence[str]) -> int:
    instructions = parse_puzzle_input(puzzle_input)
    return run_boot_code(instructions, True)


def solve_second_part(puzzle_input: Sequence[str]) -> int:
    instructions = parse_puzzle_input(puzzle_input)
    for i in range(len(instructions)):
        operation, argument = instructions[i]
        if operation is Operation.ACC:
            continue
        new_operation = Operation.JMP if operation is Operation.NOP else Operation.NOP
        instructions[i] = new_operation, argument
        try:
            return run_boot_code(instructions)
        except RuntimeError:
            instructions[i] = operation, argument
    raise ValueError("no permutation fixed the instructions")


if __name__ == "__main__":
    puzzle_input = get_puzzle_input("day08")
    print_puzzle(puzzle_input, solve_first_part, solve_second_part)
Exemple #11
0
        puzzle_input: Sequence[str]) -> Sequence[Dict[str, str]]:
    return tuple(
        dict(
            field.split(":") for field in chain.from_iterable(line.split()
                                                              for line in v))
        for k, v in groupby(puzzle_input, lambda x: len(x) > 0) if k)


def solve_first_part(puzzle_input: Sequence[str]) -> int:
    passeports = parse_puzzle_input(puzzle_input)
    expected_fields = set(f.name for f in fields(Passeport)) - {"cid"}
    return sum(expected_fields <= p.keys() for p in passeports)


def solve_second_part(puzzle_input: Sequence[str]) -> int:
    passeports = parse_puzzle_input(puzzle_input)
    valid_count = 0
    for kwargs in passeports:
        try:
            Passeport(**kwargs)
        except (TypeError, AssertionError):
            pass
        else:
            valid_count += 1
    return valid_count


if __name__ == "__main__":
    puzzle_input = get_puzzle_input("day04")
    print_puzzle(puzzle_input, solve_first_part, solve_second_part)
Exemple #12
0
from aoc2020.input import get_puzzle_input
from aoc2020.puzzle import print_puzzle

PUZZLE_MAPPING = {"F": "0", "B": "1", "L": "0", "R": "1"}


def parse_puzzle_input(puzzle_input: Sequence[str]) -> Sequence[int]:
    return tuple(int("".join(PUZZLE_MAPPING[c] for c in p), 2) for p in puzzle_input)


def solve_first_part(puzzle_input: Sequence[str]) -> int:
    return max(parse_puzzle_input(puzzle_input))


def solve_second_part(puzzle_input: Sequence[str]) -> int:
    seat_id_set = set(parse_puzzle_input(puzzle_input))
    for seat_id in range(min(seat_id_set) + 1, max(seat_id_set)):
        if (
            seat_id not in seat_id_set
            and seat_id + 1 in seat_id_set
            and seat_id - 1 in seat_id_set
        ):
            return seat_id
    raise ValueError("could not find the seat id")


if __name__ == "__main__":
    puzzle_input = get_puzzle_input("day05")
    print_puzzle(puzzle_input, solve_first_part, solve_second_part)