2023.03
This commit is contained in:
parent
514cbc2dfd
commit
366efe0b0d
3 changed files with 144 additions and 0 deletions
1
challenges/2023/03-gearRatios/README.md
Normal file
1
challenges/2023/03-gearRatios/README.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
# [Day 3: Gear Ratios](https://adventofcode.com/2023/day/3)
|
135
challenges/2023/03-gearRatios/main.py
Normal file
135
challenges/2023/03-gearRatios/main.py
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def _debug(*args, **kwargs):
|
||||||
|
kwargs["file"] = sys.stderr
|
||||||
|
print(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
Coordinate = tuple[int, int]
|
||||||
|
Schematic = dict[Coordinate, str]
|
||||||
|
|
||||||
|
|
||||||
|
def parse(instr: str) -> Schematic:
|
||||||
|
res = {}
|
||||||
|
|
||||||
|
lines = instr.splitlines()
|
||||||
|
max_x = len(lines[0])
|
||||||
|
|
||||||
|
for row_n, row in enumerate(lines):
|
||||||
|
assert len(row) == max_x
|
||||||
|
for col_n, char in enumerate(row):
|
||||||
|
res[(col_n, row_n)] = char
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
DIRECTIONS = [(-1, -1), (0, -1), (1, -1), (-1, 0), (1, 0), (-1, 1), (0, 1), (1, 1)]
|
||||||
|
|
||||||
|
|
||||||
|
def apply_coord_delta(c: Coordinate, d: Coordinate) -> Coordinate:
|
||||||
|
a, b = c
|
||||||
|
e, f = d
|
||||||
|
return a + e, b + f
|
||||||
|
|
||||||
|
|
||||||
|
def seek_digits(
|
||||||
|
sc: Schematic, start: Coordinate, delta: Coordinate
|
||||||
|
) -> tuple[str, set[Coordinate]]:
|
||||||
|
digits = ""
|
||||||
|
coords = set()
|
||||||
|
|
||||||
|
cursor = start
|
||||||
|
while True:
|
||||||
|
cursor = apply_coord_delta(cursor, delta)
|
||||||
|
val = sc.get(cursor, ".")
|
||||||
|
if not val.isdigit():
|
||||||
|
break
|
||||||
|
coords.add(cursor)
|
||||||
|
digits += val
|
||||||
|
|
||||||
|
return digits, coords
|
||||||
|
|
||||||
|
|
||||||
|
def collect_digits_around(
|
||||||
|
sc: Schematic, start: Coordinate
|
||||||
|
) -> tuple[int, set[Coordinate]]:
|
||||||
|
backward_digits, backward_coords = seek_digits(sc, start, (-1, 0))
|
||||||
|
forward_digits, forward_coords = seek_digits(sc, start, (1, 0))
|
||||||
|
|
||||||
|
return (
|
||||||
|
int("".join(reversed(backward_digits)) + sc[start] + forward_digits),
|
||||||
|
backward_coords | forward_coords | set((start,)),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def one(inp: str):
|
||||||
|
schematic = parse(inp)
|
||||||
|
|
||||||
|
consumed_numbers = set()
|
||||||
|
acc = 0
|
||||||
|
|
||||||
|
for coord in schematic:
|
||||||
|
if coord in consumed_numbers:
|
||||||
|
continue
|
||||||
|
|
||||||
|
char = schematic[coord]
|
||||||
|
|
||||||
|
if not char.isdigit():
|
||||||
|
continue
|
||||||
|
|
||||||
|
is_part_number = False
|
||||||
|
for delta in DIRECTIONS:
|
||||||
|
target = schematic.get(apply_coord_delta(coord, delta), ".")
|
||||||
|
if not (target.isdigit() or target == "."):
|
||||||
|
is_part_number = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if is_part_number:
|
||||||
|
n, used_coords = collect_digits_around(schematic, coord)
|
||||||
|
consumed_numbers = consumed_numbers | used_coords
|
||||||
|
acc += int(n)
|
||||||
|
|
||||||
|
return acc
|
||||||
|
|
||||||
|
|
||||||
|
def two(inp: str):
|
||||||
|
schematic = parse(inp)
|
||||||
|
acc = 0
|
||||||
|
|
||||||
|
for coord in schematic:
|
||||||
|
char = schematic[coord]
|
||||||
|
|
||||||
|
if char != "*":
|
||||||
|
continue
|
||||||
|
|
||||||
|
consumed_numbers = set()
|
||||||
|
numbers = []
|
||||||
|
|
||||||
|
for delta in DIRECTIONS:
|
||||||
|
test_coord = apply_coord_delta(coord, delta)
|
||||||
|
if test_coord in consumed_numbers:
|
||||||
|
continue
|
||||||
|
if schematic.get(test_coord, ".").isdigit():
|
||||||
|
n, c = collect_digits_around(schematic, test_coord)
|
||||||
|
consumed_numbers = consumed_numbers | c
|
||||||
|
numbers.append(n)
|
||||||
|
|
||||||
|
if len(numbers) == 2:
|
||||||
|
# is gear!
|
||||||
|
x, y = numbers
|
||||||
|
acc += x * y
|
||||||
|
|
||||||
|
return acc
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) < 2 or sys.argv[1] not in ["1", "2"]:
|
||||||
|
print("Missing day argument", file=sys.stderr)
|
||||||
|
os.exit(1)
|
||||||
|
inp = sys.stdin.read().strip()
|
||||||
|
if sys.argv[1] == "1":
|
||||||
|
print(one(inp))
|
||||||
|
else:
|
||||||
|
print(two(inp))
|
8
challenges/2023/03-gearRatios/tests.json
Normal file
8
challenges/2023/03-gearRatios/tests.json
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"1": [
|
||||||
|
{"res": "4361", "in": "467..114..\n...*......\n..35..633.\n......#...\n617*......\n.....+.58.\n..592.....\n......755.\n...$.*....\n.664.598.."}
|
||||||
|
],
|
||||||
|
"2": [
|
||||||
|
{"res": "467835", "in": "467..114..\n...*......\n..35..633.\n......#...\n617*......\n.....+.58.\n..592.....\n......755.\n...$.*....\n.664.598.."}
|
||||||
|
]
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue