Python: Day 3

This commit is contained in:
Adrian Rumpold
2022-12-15 08:00:17 +01:00
parent 7237b2c770
commit aeebed7ec9
4 changed files with 492 additions and 0 deletions

65
03/py/solution.py Normal file
View File

@@ -0,0 +1,65 @@
from pathlib import Path
from typing import Generator, TypeVar
from collections.abc import Iterable
T = TypeVar("T")
def threes(i: Iterable[T]) -> Generator[tuple[T, T, T], None, None]:
if len(i) % 3 != 0:
raise ValueError()
for idx in range(0, len(i), 3):
yield i[idx], i[idx + 1], i[idx + 2]
def priority(s: str) -> int:
assert len(s) == 1
if "a" <= s <= "z":
return ord(s) - ord("a") + 1
elif "A" <= s <= "Z":
return ord(s) - ord("A") + 27
raise RuntimeError(f"Invalid char: {s}")
def split(s: str) -> tuple[str, str]:
mid = len(s) // 2
return s[:mid], s[mid:]
def part1(data: str) -> int:
result = 0
for line in data.splitlines():
left, right = split(line)
both = {ch for ch in right}.intersection({ch for ch in left})
value = 0
for ch in both:
value += priority(ch)
print(f"{line}: {both}")
result += value
return result
def part2(data: str) -> int:
result = 0
lines = data.splitlines()
for a, b, c in threes(lines):
badge = set(a).intersection(set(b)).intersection(set(c))
value = 0
for ch in badge:
value += priority(ch)
result += value
return result
# Setup
data = (Path(__file__).parents[1] / "input").read_text()
# Problem solving - part 1
result = part1(data)
print(f"Part 1 solution: {result}")
# Problem solving - part 2
result = part2(data)
print(f"Part 2 solution: {result}")

57
03/py/test.py Normal file
View File

@@ -0,0 +1,57 @@
from typing import ContextManager, Optional
from solution import part1, part2, priority, threes
from contextlib import nullcontext as no_raise
import pytest
@pytest.fixture
def example_data() -> str:
return """vJrwpWtwJgWrhcsFMMfFFhFp
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
PmmdzqPrVvPwwTWBwg
wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
ttgJtRGJQctTZtZT
CrZsJsPPZsGzwwsLwLmpwMDw"""
def test_part1(example_data: str) -> None:
assert part1(example_data) == 157
@pytest.mark.parametrize(
"s,expected",
[
("a", 1),
("b", 2),
("z", 26),
("A", 27),
("C", 29),
("Z", 52),
],
)
def test_priority(s: str, expected: int) -> None:
assert priority(s) == expected
@pytest.mark.parametrize(
"line,expected,raises",
[
("a\nb\nc", [("a", "b", "c")], no_raise()),
("a\nb\nc\nd", None, pytest.raises(ValueError)),
],
)
def test_threes(
line: str,
expected: Optional[list[tuple[str, str, str]]],
raises: ContextManager,
):
with raises:
actual = list(threes(line.splitlines()))
if expected:
assert actual == expected
def test_part2(example_data: str) -> None:
assert part2(example_data) == 70