2023/day03: Complete!

main
earnest ma 2023-12-04 20:58:31 -05:00
parent c31f4fd964
commit 9304a38628
Signed by: earnest ma
GPG Key ID: A343F43342EB6E2A
2 changed files with 200 additions and 0 deletions

190
2023/day03.py Normal file
View File

@ -0,0 +1,190 @@
#!/usr/bin/env python3
from typing import TextIO
import re
schematic: list[str] = []
# line {int: {(a,b): num}, ...}
gears: dict[int, dict[tuple[int, int], int]] = {}
def get_adjacent(l: int, co: tuple[int, int]) -> bool:
for i in range(co[0], co[1]):
# check below
if (
l + 1 < len(schematic)
and not schematic[l + 1][i].isdigit()
and schematic[l + 1][i] != "."
):
return True
# check above
if l != 0 and not schematic[l - 1][i].isdigit() and schematic[l - 1][i] != ".":
return True
# if first num check left
if (
i != 0
and i == co[0]
and not schematic[l][i - 1].isdigit()
and schematic[l][i - 1] != "."
):
return True
# if last num check right
if (
i + 1 < len(schematic[l])
and i == co[1] - 1
and not schematic[l][i + 1].isdigit()
and schematic[l][i + 1] != "."
):
return True
# all check diag
# U L
if (
l != 0
and i != 0
and not schematic[l - 1][i - 1].isdigit()
and schematic[l - 1][i - 1] != "."
):
return True
# U R
if (
l != 0
and i + 1 < len(schematic[l])
and not schematic[l - 1][i + 1].isdigit()
and schematic[l - 1][i + 1] != "."
):
return True
# D L
if (
l + 1 < len(schematic)
and i != 0
and not schematic[l + 1][i - 1].isdigit()
and schematic[l + 1][i - 1] != "."
):
return True
# D R
if (
l + 1 < len(schematic)
and i + 1 < len(schematic[l])
and not schematic[l + 1][i + 1].isdigit()
and schematic[l + 1][i + 1] != "."
):
return True
return False
def part1(file: TextIO) -> int:
sum_: int = 0
for line in file:
schematic.append(line.strip())
for l in range(len(schematic)):
nums = re.finditer(r"\d+", schematic[l])
for n in nums:
if l in gears:
gears[l][n.span()] = int(n.group(0))
else:
gears[l] = {n.span(): int(n.group(0))}
if get_adjacent(l, n.span()):
sum_ += int(n.group(0))
return sum_
def find_num(l, c) -> tuple[int, tuple[int, int, int]]:
for coord in gears[l]:
if c in range(coord[0], coord[1] + 1):
return (
gears[l][coord],
(l, coord[0], coord[1]),
) # line pos (same coordinates on 2 diff lines)
raise ValueError
def part2() -> int:
ratios: int = 0
for l in range(len(schematic)):
for c in range(len(schematic[l])):
if schematic[l][c] == "*":
nums: list[int] = []
used_c: list[tuple[int, int, int]] = []
# start parsing for digits
# check below
if l + 1 < len(schematic) and schematic[l + 1][c].isdigit():
a = find_num(l + 1, c)
if a[1] not in used_c:
nums.append(a[0])
used_c.append(a[1])
# check above
if l != 0 and schematic[l - 1][c].isdigit():
a = find_num(l - 1, c)
if a[1] not in used_c:
nums.append(a[0])
used_c.append(a[1])
# check left
if c != 0 and schematic[l][c - 1].isdigit():
a = find_num(l, c - 1)
if a[1] not in used_c:
nums.append(a[0])
used_c.append(a[1])
# check right
if c + 1 < len(schematic[l]) and schematic[l][c + 1].isdigit():
a = find_num(l, c + 1)
if a[1] not in used_c:
nums.append(a[0])
used_c.append(a[1])
# all check diag
# U L
if l != 0 and c != 0 and schematic[l - 1][c - 1].isdigit():
a = find_num(l - 1, c - 1)
if a[1] not in used_c:
nums.append(a[0])
used_c.append(a[1])
# U R
if (
l != 0
and c + 1 < len(schematic[l])
and schematic[l - 1][c + 1].isdigit()
):
a = find_num(l - 1, c + 1)
if a[1] not in used_c:
nums.append(a[0])
used_c.append(a[1])
# D L
if (
l + 1 < len(schematic)
and c != 0
and schematic[l + 1][c - 1].isdigit()
):
a = find_num(l + 1, c - 1)
if a[1] not in used_c:
nums.append(a[0])
used_c.append(a[1])
# D R
if (
l + 1 < len(schematic)
and c + 1 < len(schematic[l])
and schematic[l + 1][c + 1].isdigit()
):
a = find_num(l + 1, c + 1)
if a[1] not in used_c:
nums.append(a[0])
used_c.append(a[1])
if len(nums) == 2:
ratios += nums[0] * nums[1]
if len(nums) > 2:
raise ValueError
return ratios
if __name__ == "__main__":
with open("day03.txt") as f:
print(part1(f))
print(part2()) # not 75089990 too low

10
2023/day03_test.py Normal file
View File

@ -0,0 +1,10 @@
from day03 import *
def test_part1() -> None:
with open("day03.txt") as f:
assert part1(f) == 546312
def test_part2() -> None:
assert part2() == 87449461