71 lines
1.4 KiB
Python
71 lines
1.4 KiB
Python
import os
|
|
from collections import defaultdict
|
|
from dataclasses import dataclass
|
|
from functools import cmp_to_key
|
|
|
|
|
|
def relpath(path: str) -> str:
|
|
return os.path.join(os.path.dirname(__file__), path)
|
|
|
|
|
|
with open(relpath("../input/day05.txt")) as f:
|
|
text = f.read()
|
|
sections = text.split("\n\n")
|
|
|
|
rules = [
|
|
tuple(map(int, line.split("|")))
|
|
for line in sections[0].splitlines()
|
|
]
|
|
|
|
updates = [
|
|
tuple(map(int, line.split(",")))
|
|
for line in sections[1].splitlines()
|
|
]
|
|
|
|
|
|
@dataclass
|
|
class Constraint:
|
|
before: set[int]
|
|
after: set[int]
|
|
|
|
|
|
constraints = defaultdict(lambda: Constraint(before=set(), after=set()))
|
|
|
|
for (x, y) in rules:
|
|
constraints[x].after.add(y)
|
|
constraints[y].before.add(x)
|
|
|
|
|
|
def is_valid(update):
|
|
for (x, y) in zip(update[:-1], update[1:]):
|
|
if x not in constraints or y in constraints[x].after:
|
|
continue
|
|
return False
|
|
return True
|
|
|
|
|
|
def part1():
|
|
return sum(
|
|
update[int(len(update)) // 2]
|
|
for update in updates
|
|
if is_valid(update)
|
|
)
|
|
|
|
|
|
def part2():
|
|
def compare(x, y):
|
|
if y in constraints[x].after:
|
|
return +1
|
|
if y in constraints[x].before:
|
|
return -1
|
|
return 0
|
|
|
|
return sum(
|
|
sorted(update, key=cmp_to_key(compare))[int(len(update)) // 2]
|
|
for update in updates
|
|
if not is_valid(update)
|
|
)
|
|
|
|
|
|
print(part1())
|
|
print(part2())
|