Solve 2024 till day 18

This commit is contained in:
2024-12-18 22:09:38 -05:00
parent 4ad7075785
commit 744dbb4ffc
6 changed files with 329 additions and 40 deletions

View File

@@ -11,45 +11,19 @@ def score(robots):
quadrants = defaultdict(int)
for _, r, c in robots:
if r < rows // 2 and c < cols // 2:
quadrant = 1 # Top-left
quadrants[quadrant] += 1
quadrants[1] += 1
elif r < rows // 2 and c > cols // 2:
quadrant = 2 # Top-right
quadrants[quadrant] += 1
quadrants[2] += 1
elif r > rows // 2 and c < cols // 2:
quadrant = 3 # Bottom-left
quadrants[quadrant] += 1
quadrants[3] += 1
elif r > rows // 2 and c > cols // 2:
quadrant = 4 # Bottom-right
quadrants[quadrant] += 1
else:
pass
quadrants[4] += 1
t = 1
for q in quadrants.values():
t *= q
return t
def get_easter_egg_coords(rows, cols):
coords = set()
center_y, center_x = rows // 2, cols // 2
height = rows * 0.8
width = cols * 0.6
for i in range(rows):
for j in range(cols):
squeeze = 1 - 0.3 * ((i - center_y + height / 4) / height)
egg_eq = (j - center_x) ** 2 / (width / 2) ** 2 + (i - center_y) ** 2 / (
(height / 2 * squeeze) ** 2
)
if egg_eq <= 1:
coords.add((i, j))
return coords
def print_from_xy(xs):
x_min = min(v[1] for v in xs)
x_max = max(v[1] for v in xs)
@@ -72,25 +46,19 @@ for i, line in enumerate(data.splitlines()):
robots_speed[i] = (vr, vc)
robots.append((i, r, c))
egg_coords = get_easter_egg_coords(rows, cols)
max_count = 0
for j in range(10_000_000_000):
for j in range(rows * cols):
nrobots = list()
count = 0
for i, r, c in robots:
vr, vc = robots_speed[i]
nr = (r + vr) % rows
nc = (c + vc) % cols
if (nr, nc) in egg_coords:
count += 1
nrobots.append((i, nr, nc))
robots = nrobots
max_count = max(count, max_count)
if j == 99:
print(score(robots))
if count > 380:
robots_coords = [(r, c) for _, r, c in robots]
if len(robots_coords) == len(set(robots_coords)):
print(j + 1)
# print_from_xy([(r, c) for _, r, c in robots])
# print_from_xy(robots_coords)
break

92
2024/d15.py Normal file
View File

@@ -0,0 +1,92 @@
from lib import get_data
from lib import Grid2D
DIRS = {
"^": (-1, 0),
">": (0, 1),
"v": (1, 0),
"<": (0, -1),
}
data = get_data(__file__)
data, moves = data.split("\n\n")
g = Grid2D(data)
def simulate(grid: Grid2D, moves: str):
(p,) = g.find("@")
for c in moves:
if c == "\n":
continue
d = DIRS[c]
to_move = set([p])
row = to_move
blocked = False
while True:
nrow = set()
for (
r,
c,
) in row:
np = r + d[0], c + d[1]
if g[np] == "#":
blocked = True
elif g[np] == "O":
nrow.add(np)
elif g[np] == "[":
nrow.add(np)
if d == (1, 0) or d == (-1, 0):
nrow.add((np[0], np[1] + 1))
elif g[np] == "]":
if d == (1, 0) or d == (-1, 0):
nrow.add((np[0], np[1] - 1))
nrow.add(np)
to_move |= row
row = nrow
if len(row) == 0 or blocked:
break
if not blocked:
to_place = {}
p = p[0] + d[0], p[1] + d[1]
for tm in to_move:
np = tm[0] + d[0], tm[1] + d[1]
to_place[np] = g[tm]
g[tm] = "."
for pos, c in to_place.items():
g[pos] = c
def score(g: Grid2D) -> int:
os = g.find("O")
if os:
return sum(r * 100 + c for r, c in os)
return sum(r * 100 + c for r, c in g.find("["))
simulate(g, moves)
print(score(g))
ndata = ""
for c in data:
if c == "#":
ndata += "##"
elif c == "O":
ndata += "[]"
elif c == ".":
ndata += ".."
elif c == "@":
ndata += "@."
else:
ndata += c
g = Grid2D(ndata)
(p,) = g.find("@")
simulate(g, moves)
print(score(g))
exit()

96
2024/d16.py Normal file
View File

@@ -0,0 +1,96 @@
import heapq
from collections import defaultdict
from lib import get_data
from lib import Grid2D
data = get_data(__file__)
g = Grid2D(data)
def search(start, end, dir):
paths = set()
def reconstruct(parents, current):
seen = set()
to_visit = [current]
while to_visit:
current = to_visit.pop()
if current in seen:
continue
seen.add(current)
paths.add(current[0])
for p in parents[current]:
to_visit.append(p)
def dist(n1, n2):
"""cost from node to node"""
if n1 == 0 or n1 == n2:
return 0
p1, d1 = n1
p2, d2 = n2
if p1 != p2:
return 1
if d1 != d2:
return 1000
assert False
def h(node):
"""heuristic function (never overestimate)"""
pos = node[0]
return abs(pos[0] - end[0]) + abs(pos[1] - end[1])
def is_goal(node):
return node[0] == end
def neighbors(node):
pos, dir = node
npos = pos[0] + dir[0], pos[1] + dir[1]
nbs = []
if g.contains(npos) and g[npos] != "#":
nbs.append((npos, dir))
ndir = dir[1], -dir[0]
nbs.append((pos, ndir))
ndir = -dir[1], dir[0]
nbs.append((pos, ndir))
return nbs
starts = [(start, dir)]
open_set = []
g_score = {}
cost = None
for start in starts:
heapq.heappush(open_set, (h(start), start))
g_score[start] = dist(0, start)
parents = defaultdict(list)
while open_set:
current_f_score, current = heapq.heappop(open_set)
if is_goal(current):
# assert current_f_score == g_score[current]
gs = g_score[current]
if cost is None or gs <= cost:
cost = gs
reconstruct(parents, current)
else:
break
for neighbor in neighbors(current):
tentative_g_score = g_score[current] + dist(current, neighbor)
if tentative_g_score <= g_score.get(neighbor, 10**12):
parents[neighbor].append(current)
g_score[neighbor] = tentative_g_score
f_score = g_score[neighbor] + h(neighbor)
heapq.heappush(open_set, (f_score, neighbor))
return cost, paths
(start,) = g.find("S")
(end,) = g.find("E")
dir = (0, 1)
cost, paths = search(start, end, dir)
print(cost)
print(len(paths))

61
2024/d17.py Normal file
View File

@@ -0,0 +1,61 @@
from lib import get_data
from lib import ints
data = get_data(__file__)
nums, prog = data.split("\n\n")
regs = ints(nums)
prog = ints(prog)
i = 0
out = []
while i < len(prog) - 1:
inst, op = prog[i], prog[i + 1]
assert op != 7
combo = op if op not in [4, 5, 6] else regs[op - 4]
literal = op
match inst:
case 0:
regs[0] = regs[0] >> combo
case 1:
regs[1] = regs[1] ^ literal
case 2:
regs[1] = combo % 8
case 3:
if regs[0] != 0:
i = literal - 2
case 4:
regs[1] = regs[1] ^ regs[2]
case 5:
out.append(combo % 8)
case 6:
regs[1] = regs[0] // (2**combo)
case 7:
regs[2] = regs[0] // (2**combo)
case _:
assert False
i += 2
print(",".join(map(str, out)))
def get_a(a_current, xs):
if len(xs) == 0:
return [a_current // 8]
x = xs[0]
aan = []
for a_new in range(8):
a = a_current + a_new
b = a % 8
assert b == a_new
b = b ^ 1
c = a >> b
b = b ^ c
b = b ^ 5
if (b % 8) == x:
aan += get_a(a << 3, xs[1:])
return aan
aa = get_a(0, list(reversed(prog)))
print(min(aa))

67
2024/d18.py Normal file
View File

@@ -0,0 +1,67 @@
import heapq
from lib import get_data
from lib import ints
from lib import Grid2D
data = get_data(__file__)
size = 71
grid = "\n".join(["." * size for _ in range(size)])
g = Grid2D(grid)
for i, line in enumerate(data.splitlines()):
x, y = ints(line)
g[(y, x)] = "x"
start = (0, 0)
end = (size - 1, size - 1)
def dist(n1, n2):
"""cost from node to node"""
if n1 == 0 or n1 == n2:
return 0
return 1
def h(node):
"""heuristic function (never overestimate)"""
return abs(node[0] - end[0]) + abs(node[1] - end[1])
def is_goal(node):
return node == end
def neighbors(node):
nbs = []
for nb in g.neighbors_ort(node):
if g[nb] != "x":
nbs.append(nb)
return nbs
starts = [start]
open_set = []
g_score = {}
cost = None
for start in starts:
heapq.heappush(open_set, (h(start), start))
g_score[start] = dist(0, start)
while open_set:
current_f_score, current = heapq.heappop(open_set)
if is_goal(current):
assert current_f_score == g_score[current]
cost = g_score[current]
break
for neighbor in neighbors(current):
tentative_g_score = g_score[current] + dist(current, neighbor)
if neighbor not in g_score or tentative_g_score < g_score[neighbor]:
g_score[neighbor] = tentative_g_score
f_score = g_score[neighbor] + h(neighbor)
heapq.heappush(open_set, (f_score, neighbor))
if i == 1023:
print(cost)
if cost is None:
print(line)
break

View File

@@ -305,4 +305,9 @@ and focus. Of course, learning more algorithms and techniques helps.
- Day 12: `00:30:30 3540 0 11:41:33 16212 0`
- Day 13: `00:05:35 225 0 00:55:48 2544 0`
- Day 14: `00:20:41 2136 0 00:35:14 1048 0`
- Day 15: ` >24h 32248 0 >24h 23671 0`
- Day 16: ` >24h 24941 0 >24h 20575 0`
- Day 17: `17:34:16 23722 0 >24h 17778 0`
- Day 18: `14:35:01 20398 0 14:37:18 19550 0`
- Day 19: