Advertisement

# Untitled

a guest
Dec 6th, 2021
832
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
1. # aoc202104.py
2.
3. import pathlib
4. import sys
5. from typing import Any, TypeVar
6.
7. # Type annotation alias
8. T = TypeVar('tuple[list[int], list[list[list[int]]]]')
9.
10.
11. def intify(list_of_strings: list[str]) -> list[int]:
12.     """ Convert a list of strings into one of ints """
13.     return [int(c) for c in list_of_strings]
14.
15.
16. def format_board(board: list[str]) -> list[int]:
17.     """ Format each board from the input into int equivalents """
18.     formatted_board = []
19.     for row in board.splitlines():
20.         row = row.replace('  ', ' ')
21.         formatted_board.append(row.split())
22.     return [intify(board) for board in formatted_board]
23.
24.
25. def parse(puzzle_input: str) -> T:
26.     """ Parse input """
27.     data = puzzle_input.split('\n\n')
28.     nums, boards = data[0].split(','), data[1:]
29.     return (intify(nums), [format_board(board) for board in boards])
30.
31.
32. def invert_board(board: list[list[int]]) -> list[list[int]]:
33.     """ Switch rows and columns of board """
34.     return [list(tupp) for tupp in list(zip(*board))]
35.
36.
37. def winning_turns(nums: list[int], seq: list) -> int:
38.     """ Return num of times it takes to match all nums in a sequence """
39.     counter, turns = 0, 0
40.     for num in nums:
41.         turns += 1
42.         if num in seq:
43.             counter += 1
44.             if counter == 5:
45.                 return turns
46.
47.
48. def get_scores(board: list[list[int]], nums: list[int]) -> list[int]:
49.     """ Return a list of winning turns for a board """
50.     return [winning_turns(nums, seq) for seq in board]
51.
52.
53. def scores(board: list[list[int]], nums: list[int]) -> list[int]:
54.     """ Calculate scores for board and return all values as a list """
55.     results = []
56.     by_row = get_scores(board, nums)
57.     by_col = get_scores(invert_board(board), nums)
58.     for row, col in zip(by_row, by_col):
59.         results.append(min(row, col))
60.     return results
61.
62.
63. def board_scores(boards: T, nums: list[int]) -> dict[int, list[int]]:
64.     """ Get all the quickest scores for each board """
65.     return {
66.         board_no: min(scores(board, nums))
67.         for board_no, board in enumerate(boards)
68.     }
69.
70.
71. def flatten(t: list[list[Any]]) -> list[Any]:
72.     """ Flatten a nested list """
73.     return [item for sublist in t for item in sublist]
74.
75.
76. def final_score(board: list[list[int]], played_nums: list[int]) -> int:
77.     """ Work out final score using sets """
78.     last_num = played_nums[-1]
79.     board_nums = set(flatten(board))
80.     remaining_numbers = board_nums - set(played_nums)
81.     return sum(remaining_numbers) * last_num
82.
83.
84. def part1(data: T) -> int:
85.     """ Solve part 1 """
86.     nums, boards = data[0], data[1]
87.     board_info = board_scores(boards, nums)
88.     # Get quickest board
89.     quickest = min(board_info, key=board_info.get)
90.     num_turns = board_info[quickest]
91.     return final_score(boards[quickest], nums[:num_turns])
92.
93.
94. def part2(data: T) -> int:
95.     """ Solve part 2 """
96.     nums, boards = data[0], data[1]
97.     board_info = board_scores(boards, nums)
98.     # Get slowest board
99.     slowest = max(board_info, key=board_info.get)
100.     num_turns = board_info[slowest]
101.     return final_score(boards[slowest], nums[:num_turns])
102.
103.
104. def solve(puzzle_input: T) -> tuple[int, int]:
105.     """ Solve the puzzle for the given input """
106.     data = parse(puzzle_input)
107.     solution1 = part1(data)  # Correct answer was 58412 (with my data)
108.     solution2 = part2(data)  # Correct answer was 10030 (with my data)
109.
110.     return solution1, solution2
111.
112.
113. if __name__ == "__main__":
114.     for path in sys.argv[1:]:
115.         print(f"{path}:")
116.         puzzle_input = pathlib.Path(path).read_text().strip()
117.         solutions = solve(puzzle_input)
118.         print('\n'.join(str(solution) for solution in solutions))
Advertisement
Advertisement
Advertisement
RAW Paste Data Copied
Advertisement