2023/day03: Complete!
parent
c31f4fd964
commit
9304a38628
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue