Part 1 solution for Day 5.

This commit is contained in:
2024-12-05 21:29:45 +10:00
parent ed88e9b868
commit 029a76b088
2 changed files with 121 additions and 0 deletions

75
day5/solver.py Normal file
View File

@@ -0,0 +1,75 @@
from collections.abc import Iterable
import operator as op
import itertools as it
from collections import defaultdict
from typing import Iterator, TypeAlias
import logging
import sys
logger = logging.getLogger()
logger.addHandler(logging.StreamHandler())
RuleSet: TypeAlias = dict[str, set[str]]
def parse_rules(rule_lines: Iterable[str]) -> RuleSet:
"""
Parse a sequence of poset rules into a rulset
mapping id -> list of descendents.
"""
descendents = defaultdict(set)
for line in rule_lines:
if '|' not in line:
raise ValueError(f"Provided line '{line}' is not a rule.")
a, b = line.split('|')
descendents[a].add(b)
return descendents
def check_line(line: list[str], ruleset: RuleSet) -> bool:
"""
Check whether the provided line satisfies the given rules.
"""
for i, char in enumerate(line):
rules = ruleset[char]
if any(prevchar in rules for prevchar in line[:i]):
return False
return True
def get_middle(line: list[str]) -> str:
"""
Get the middle of the line, if it exists.
"""
if not len(line) % 2:
raise ValueError("Even length line has no middle.")
return line[len(line) // 2]
def process_data(lines: Iterator[str]):
lines = map(op.methodcaller('strip'), lines)
lines = it.dropwhile(op.not_, lines)
ruleset = parse_rules(it.takewhile(bool, lines))
if logger.isEnabledFor(logging.DEBUG):
logger.debug(f"Ruleset: {ruleset}")
total = 0
for line in lines:
if line:
parts = line.split(',')
if check_line(parts, ruleset):
total += int(get_middle(parts))
logger.debug(f"Valid line: {line}")
else:
logger.debug(f"Invalid line: {line}")
return total
def main():
with open(sys.argv[1]) as f:
total = process_data(f)
print(f"Total middle-sum is {total}")
if __name__ == '__main__':
main()

46
day5/test.py Normal file
View File

@@ -0,0 +1,46 @@
import logging
from solver import process_data
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
test_data = r"""
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
"""
def test_main():
print("Beginning basic test")
result = process_data(iter(test_data.splitlines()))
assert result == 143
print("Basic test passed")
if __name__ == '__main__':
test_main()