Files
Jens Kadenbach 0a6181ccc0 Day 13
2023-01-27 13:50:12 +01:00

97 lines
2.9 KiB
Python

import json
import pathlib
import sys
def parse(puzzle_input: str) -> list[list[int, ...]]:
"""Convert str representations of lists into real int lists"""
str_pkts: list[list[str, str]] = [
packet.splitlines() for packet in puzzle_input.split("\n\n")
]
int_pkts: list[list[int, ...]] = []
for pkt in str_pkts:
int_pk: list[int, ...] = []
for pk in pkt:
# Here's the magick - I'm highly averse to eval()
int_pk.append(json.loads(pk))
int_pkts.append(int_pk)
return int_pkts
def compare(l: int, r: int) -> int:
"""Compare 2 ints, return 1, 0, -1 depending on values"""
if l < r:
return 1
elif l > r:
return -1
else:
return 0
def compare_packets(left: list[int, ...], right: list[int, ...]) -> int:
"""Compare 2 lists to establish correct order"""
match left, right:
case int(), int():
return compare(left, right)
case int(), list():
return compare_packets([left], right)
case list(), int():
return compare_packets(left, [right])
case list(), list():
for l, r in zip(left, right):
res = compare_packets(l, r)
if res != 0:
return res
return compare_packets(len(left), len(right))
def part1(pairs: list[list[int, ...]]) -> int:
"""Solve part 1"""
sum_of_indices: int = 0
for idx, pair in enumerate(pairs):
if compare_packets(*pair) == 1:
sum_of_indices += idx + 1
return sum_of_indices
def flatten(l: list[list[int]]) -> list[int]:
"""Flatten a nested list one level"""
return [item for sublist in l for item in sublist]
def find_index(l: list[list[int]], item: list[int]) -> int:
"""Return index of where item falls in list"""
item_idx: int = 0
for pkt in flatten(l):
if compare_packets(pkt, item) == 1:
item_idx += 1
return item_idx
def part2(pairs: list[list[int, ...]]) -> int:
"""Solve part 2"""
# Remove one layer of list to match flattened list above
first_divider: list[int] = [2]
second_divider: list[int] = [6]
first_pos: int = find_index(pairs, first_divider) + 1
second_pos: int = find_index(pairs, second_divider) + 2
return first_pos * second_pos
def solve(puzzle_input: str) -> tuple[int, int]:
"""Solve the puzzle for the given input"""
data: list[list[int, ...]] = parse(puzzle_input)
solution1: int = part1(data) # Correct answer was 4734 (with my data)
solution2: int = part2(data) # Correct answer was 21836 (with my data)
return solution1, solution2
if __name__ == "__main__":
for path in sys.argv[1:]:
print(f"{path}:")
puzzle_input = pathlib.Path(path).read_text().strip()
solutions = solve(puzzle_input)
print("\n".join(str(solution) for solution in solutions))