Advent of Code 2022 Day 23 Solve

preview_player
Показать описание
Recording of me solving day 23 of Advent of Code 2022 in Python. Finished rank #71 and #57 for each part.

Finish times:
Part 1: 19:18
Part 2: 20:45 (+1:27)

BUGS. The first bug I had was not accounting for the fact that when there's no other elves in the 8-neighbors they just don't move at all, sure, I realized and fixed pretty quickly, leaderboard was still at ~10 for part 1 by the time my lockout ended. My other bug though... Spot what's wrong with the following:

dirs = [
[(-1,+0),(-1,-1),(-1,+1)],
[(+1,+0),(+1,-1),(+1,+1)],
[(+0,-1),(-1,-1),(+1,-1)],
[(+0,+1),(-1,+1),(+1,-1)]
]
(this is supposed to be a list of lists where the first direction in each sublist is the direction to move in, and the next two are the appropriate diagonals to check). The last one has an extra minus sign! Should be E, NE, SE, but I actually wrote E, NE, SW. I even tried to double check by running len(set(sum(dirs,start=[]))), but I forgot that corners needed to be counted twice, so I really should've looked at Counter(sum(dirs,start=[])).

I feel like in general I've gotten a lot faster this year but at the cost of making a lot more simple mistakes? To some extent those are correlated (read too fast, you miss things) but even for silly bugs where I'm not particularly rushing on things it happens.

0:00 - Part 1
19:25 - Part 2
20:52 - Commentary
Рекомендации по теме
Комментарии
Автор

def is_other_elf_around(r, c, G):
return any([(rr, cc) in G for (rr, cc) in neighbours8(r, c)])


def propose(r, c, G, p):
D = [-1, 0, 1]

for dp in range(4):
pp = (p + dp) % 4
if pp == 0:
# N, NE, NW
if all([not (r - 1, c + dc) in G for dc in D]):
return (r - 1, c)
elif pp == 1:
# S, SE, SW
if all([not (r + 1, c + dc) in G for dc in D]):
return (r + 1, c)
elif pp == 2:
# W, NW, SW
if all([not (r + dr, c - 1) in G for dr in D]):
return (r, c - 1)
elif pp == 3:
# E, NE, SE
if all([not (r + dr, c + 1) in G for dr in D]):
return (r, c + 1)
else:
assert p, f"Wrong propose index {p}"

return (r, c)


def solve(text, part):
res = None

G = {}
for r, line in enumerate(text.split("\n")):
for c, ch in enumerate(line):
if ch == "#":
G[(r, c)] = "#"

N = len(G.keys())

prop = 0
t = 0
while True:
PROPOSING = defaultdict(list)
for (r, c) in G.keys():
if is_other_elf_around(r, c, G):
(rr, cc) = propose(r, c, G, prop)
PROPOSING[(rr, cc)].append((r, c))

any_moved = False
for k, v in PROPOSING.items():
if len(v) == 1:
G.pop(v[0])
G[k] = "#"
any_moved = True

prop = (prop + 1) % 4

t += 1
if part == 1:
if t == 10:
elfs = list(G.keys())
min_r = min([r for (r, c) in elfs])
max_r = max([r for (r, c) in elfs])
min_c = min([c for (r, c) in elfs])
max_c = max([c for (r, c) in elfs])

area = (max_r - min_r + 1) * (max_c - min_c + 1)
elfs_cnt = len(elfs)
res = area - elfs_cnt
assert elfs_cnt == N
break
elif part == 2:
if not any_moved:
res = t
break
else:
break

return res

rastislavsvoboda