Solve 2024 till day 18
This commit is contained in:
48
2024/d14.py
48
2024/d14.py
@@ -11,45 +11,19 @@ def score(robots):
|
|||||||
quadrants = defaultdict(int)
|
quadrants = defaultdict(int)
|
||||||
for _, r, c in robots:
|
for _, r, c in robots:
|
||||||
if r < rows // 2 and c < cols // 2:
|
if r < rows // 2 and c < cols // 2:
|
||||||
quadrant = 1 # Top-left
|
quadrants[1] += 1
|
||||||
quadrants[quadrant] += 1
|
|
||||||
elif r < rows // 2 and c > cols // 2:
|
elif r < rows // 2 and c > cols // 2:
|
||||||
quadrant = 2 # Top-right
|
quadrants[2] += 1
|
||||||
quadrants[quadrant] += 1
|
|
||||||
elif r > rows // 2 and c < cols // 2:
|
elif r > rows // 2 and c < cols // 2:
|
||||||
quadrant = 3 # Bottom-left
|
quadrants[3] += 1
|
||||||
quadrants[quadrant] += 1
|
|
||||||
elif r > rows // 2 and c > cols // 2:
|
elif r > rows // 2 and c > cols // 2:
|
||||||
quadrant = 4 # Bottom-right
|
quadrants[4] += 1
|
||||||
quadrants[quadrant] += 1
|
|
||||||
else:
|
|
||||||
pass
|
|
||||||
|
|
||||||
t = 1
|
t = 1
|
||||||
for q in quadrants.values():
|
for q in quadrants.values():
|
||||||
t *= q
|
t *= q
|
||||||
return t
|
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):
|
def print_from_xy(xs):
|
||||||
x_min = min(v[1] for v in xs)
|
x_min = min(v[1] for v in xs)
|
||||||
x_max = max(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_speed[i] = (vr, vc)
|
||||||
robots.append((i, r, c))
|
robots.append((i, r, c))
|
||||||
|
|
||||||
egg_coords = get_easter_egg_coords(rows, cols)
|
for j in range(rows * cols):
|
||||||
|
|
||||||
max_count = 0
|
|
||||||
|
|
||||||
for j in range(10_000_000_000):
|
|
||||||
nrobots = list()
|
nrobots = list()
|
||||||
count = 0
|
count = 0
|
||||||
for i, r, c in robots:
|
for i, r, c in robots:
|
||||||
vr, vc = robots_speed[i]
|
vr, vc = robots_speed[i]
|
||||||
nr = (r + vr) % rows
|
nr = (r + vr) % rows
|
||||||
nc = (c + vc) % cols
|
nc = (c + vc) % cols
|
||||||
if (nr, nc) in egg_coords:
|
|
||||||
count += 1
|
|
||||||
nrobots.append((i, nr, nc))
|
nrobots.append((i, nr, nc))
|
||||||
robots = nrobots
|
robots = nrobots
|
||||||
max_count = max(count, max_count)
|
|
||||||
if j == 99:
|
if j == 99:
|
||||||
print(score(robots))
|
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(j + 1)
|
||||||
# print_from_xy([(r, c) for _, r, c in robots])
|
# print_from_xy(robots_coords)
|
||||||
break
|
break
|
||||||
|
|||||||
92
2024/d15.py
Normal file
92
2024/d15.py
Normal 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
96
2024/d16.py
Normal 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
61
2024/d17.py
Normal 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
67
2024/d18.py
Normal 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
|
||||||
@@ -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 12: `00:30:30 3540 0 11:41:33 16212 0`
|
||||||
- Day 13: `00:05:35 225 0 00:55:48 2544 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 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:
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user