102 lines
2.5 KiB
Python
102 lines
2.5 KiB
Python
from typing import Callable, List
|
|
|
|
EXAMPLE = """
|
|
47|53
|
|
97|13
|
|
97|61
|
|
97|47
|
|
75|29
|
|
61|13
|
|
75|53
|
|
29|13
|
|
97|29
|
|
53|29
|
|
61|53
|
|
97|53
|
|
61|29
|
|
47|13
|
|
75|47
|
|
97|75
|
|
47|61
|
|
75|61
|
|
47|29
|
|
75|13
|
|
53|13
|
|
|
|
75,47,61,53,29
|
|
97,61,53,29,13
|
|
75,29,13
|
|
75,97,47,61,53
|
|
61,13,29
|
|
97,13,75,29,47
|
|
"""
|
|
|
|
|
|
class CheckManual:
|
|
def __init__(self, input: str) -> None:
|
|
self._input = input[1:]
|
|
sep = self._input.splitlines().index("")
|
|
self.rules = self.parse_rules(self._input.splitlines()[:sep])
|
|
self.pages = [val.split(",") for val in self._input.splitlines()[sep + 1 :]]
|
|
self.validity = self.check_page_order()
|
|
|
|
def __str__(self) -> str:
|
|
return f"Part1: {self._part1}\nPart2: {self._part2}"
|
|
|
|
@property
|
|
def _part1(self) -> int:
|
|
return sum(
|
|
[
|
|
int(val[len(val) // 2])
|
|
for val, check in zip(self.pages, self.validity)
|
|
if check
|
|
]
|
|
)
|
|
|
|
@property
|
|
def _part2(self) -> int:
|
|
return sum([int(val[len(val) // 2]) for val in self.fix_page_order()])
|
|
|
|
def parse_rules(
|
|
self, rules: List[str], sep: str = "|"
|
|
) -> List[Callable[[str], bool]]:
|
|
def make_rule(rule: str, sep: str = "|") -> Callable[[str], bool]:
|
|
left, right = rule.split(sep)
|
|
|
|
def check(pages: List[str]) -> bool:
|
|
try:
|
|
return pages.index(left) < pages.index(right)
|
|
except ValueError:
|
|
return True
|
|
|
|
return check
|
|
|
|
return [(rule, make_rule(rule)) for rule in rules]
|
|
|
|
def check_page_order(self) -> List[bool]:
|
|
return [all([rule[1](line) for rule in self.rules]) for line in self.pages]
|
|
|
|
def fix_page_order(self) -> List[str]:
|
|
to_fix = [page for page, check in zip(self.pages, self.validity) if not check]
|
|
fixed = []
|
|
for pages in to_fix:
|
|
while not all([rule[1](pages) for rule in self.rules]):
|
|
for rule in self.rules:
|
|
if not rule[1](pages):
|
|
break
|
|
r1, r2 = rule[0].split("|")
|
|
i1, i2 = pages.index(r1), pages.index(r2)
|
|
pages[i1], pages[i2] = pages[i2], pages[i1]
|
|
fixed.append(pages)
|
|
return fixed
|
|
|
|
|
|
if __name__ == "__main__":
|
|
example = CheckManual(EXAMPLE)
|
|
print(example)
|
|
assert example._part1 == 143
|
|
assert example._part2 == 123
|
|
with open("input.txt", "r") as f:
|
|
main = CheckManual(f.read())
|
|
print(main)
|