Skip to content

Commit 7efaca4

Browse files
committed
Add day 23
1 parent 64b2b78 commit 7efaca4

File tree

6 files changed

+110
-204
lines changed

6 files changed

+110
-204
lines changed

.aoc_tiles/tiles/2023/21.png

1.63 KB
Loading

.aoc_tiles/tiles/2023/22.png

5.41 KB
Loading

.aoc_tiles/tiles/2023/23.png

5.27 KB
Loading

2023/21/21.py

Lines changed: 13 additions & 204 deletions
Original file line numberDiff line numberDiff line change
@@ -1,223 +1,32 @@
1-
import re
2-
from collections import defaultdict, Counter, deque
3-
from itertools import permutations, combinations, product, combinations_with_replacement
4-
from queue import PriorityQueue
1+
from collections import deque
52

63
lines = open(0).read().splitlines()
74
Y, X = len(lines), len(lines[0])
8-
S = Y
9-
assert Y == X
105
dirs = [(0, 1), (1, 0), (0, -1), (-1, 0)]
11-
dirs_diag = [(1, 1), (1, -1), (-1, 1), (-1, -1)]
126

137
q = deque()
14-
158
dists = {}
9+
1610
for y, line in enumerate(lines):
1711
if 'S' in line:
1812
q.append((y, line.index('S')))
19-
dists[(y, line.index('S'))] = 0
2013

21-
s = 0
22-
# for i in range(64):
23-
# nextq = deque()
24-
visited = set()
25-
nextq = deque()
2614
while q:
2715
y, x = q.popleft()
2816
for dy, dx in dirs:
2917
ya, xa = y + dy, x + dx
30-
in_inner = 0 <= ya < Y and 0 <= xa < X
31-
in_outer = -Y*2 <= ya < Y*3 and -X*2 <= xa < X*3
32-
if in_outer and lines[ya%Y][xa%X] != '#': # and (ya, xa) not in visited:
33-
# ok = True
34-
# if (ya, xa) in dists:
35-
# di, do = dists[(ya, xa)]
36-
# ok = dist_outer+(not in_inner) < do
37-
# if ok:
38-
if (ya, xa) not in visited:
39-
# dists[(ya, xa)] = (dist_inner + in_inner, dist_outer + (not in_inner))
40-
dists[(ya, xa)] = dists[(y, x)]+1
41-
if in_inner:
42-
q.append((ya, xa))
43-
else:
44-
nextq.append((ya, xa))
45-
visited.add((ya, xa))
46-
if not q:
47-
q = nextq
48-
49-
# q = nextq
50-
51-
# print(dists)
52-
# print(len(dists))
53-
54-
for y in range(-Y*2, Y*3):
55-
if y % Y == 0:
56-
print('-' * (15*S))
57-
# for x in range(-X*2, X*3):
58-
for x in range(0, X):
59-
v = '#'
60-
if (y, x) in dists:
61-
dist = dists[(y, x)]
62-
# yadd = 0 if (y == y%Y) else (Y if (y > y%Y) else -Y)
63-
# xadd = 0 if (x == x%X) else (X if (x > x%X) else -X)
64-
# veryouter_dist = dists[(y+yadd, x+xadd)]
65-
# repeat = veryouter_dist - dist
66-
# repeat = do
67-
# v = str('Y' if dist % 2== 1 else ' ')
68-
v = str(dist)
69-
v = v.replace("(", "").replace(",", "").replace(")", "").replace(" ", "-")
70-
print(end=f"{v:3}" + ('| ' if x in (-X-1, -1, X-1, 2*X-1) else ''))
71-
print()
72-
73-
74-
# for direction in dirs:
75-
# for y in range(-Y, Y*2):
76-
# for x in range(-X, X*2):
77-
# if (y, x) in dists:
78-
# in_inner = 0 <= y < Y and 0 <= x < X
79-
# dist = dists[(y, x)]
80-
# # inner_di, _ = dists[(y%Y, x%X)]
81-
# if in_inner:
82-
# if dist % 2 == mod and dist <= target:
83-
# s += 1
84-
# else:
85-
# new = max(-1, (target - dist))
86-
# if new >= 0:
87-
# print(y, x, new, target, dist)
88-
# if new % 2 == mod:
89-
# if not (0 <= y < Y or 0 <= x < X):
90-
# div = S*2
91-
# s += new // (S*2) + 1
92-
# else:
93-
# div = S
94-
# s += new // S + 1
95-
# if not (0 <= y < Y or 0 <= x < X):
96-
# for side in [-1, 1]:
97-
# for i, rem in enumerate(range(target - S * 1, -S*2, -S*2)):
98-
# new = max(-1, (rem - dist))
99-
# if new >= 0:
100-
# if new % 2 == mod:
101-
# # print(f"add {new=} {S=} {dist=} {new // S=}")
102-
# s += (new) // S // 2 + 1
103-
# if new % 2 == (not mod):
104-
# # print(f"add {new=} {S=} {dist=} {new // S=}")
105-
# s += (new) // S // 2
106-
107-
# In exactly 6 steps, he can still reach 16 garden plots.
108-
# In exactly 10 steps, he can reach any of 50 garden plots.
109-
# In exactly 50 steps, he can reach 1594 garden plots.
110-
# In exactly 100 steps, he can reach 6536 garden plots.
111-
# In exactly 500 steps, he can reach 167004 garden plots.
112-
# In exactly 1000 steps, he can reach 668697 garden plots.
113-
# In exactly 5000 steps, he can reach 16733044 garden plots.
114-
115-
target = 26501365
116-
# target = 100
117-
mod = target % 2
118-
119-
curr_sum = 0
120-
next_sum = 0
121-
for y in range(0, Y):
122-
for x in range(0, X):
123-
if (y, x) in dists:
124-
curr_sum += dists[(y, x)] % 2 == mod
125-
next_sum += dists[(y, x)] % 2 == (not mod)
126-
127-
print(curr_sum, next_sum)
128-
# s = next_sum * sum(range(1, target // S, 2)) * 4 + curr_sum * ((sum(range(0, target // S, 2))) * 4 + 1)
129-
# s = curr_sum * sum(range(1, target // S, 2)) * 4 + next_sum * ((sum(range(0, target // S, 2))) * 4 + 1)
130-
131-
s += next_sum * 4
132-
s += curr_sum * 4
133-
s += next_sum * 8
134-
135-
# Visited is a HashMap<Coord, usize> which maps tiles in the input-square to their distance from the starting tile
136-
# So read this as "even_corners is the number of tiles which have a distance that is even and greater than 65"
137-
let even_corners = visited.values().filter(|v| **v % 2 == 0 && **v > 65).count();
138-
let odd_corners = visited.values().filter(|v| **v % 2 == 1 && **v > 65).count();
139-
140-
let even_full = visited.values().filter(|v| **v % 2 == 0).count();
141-
let odd_full = visited.values().filter(|v| **v % 2 == 1).count();
142-
143-
// This is 202300 but im writing it out here to show the process
144-
let n = ((26501365 - (env.dim.0 / 2)) / env.dim.0) as usize;
145-
assert_eq!(n, 202300);
146-
147-
let p2 = ((n+1)*(n*1)) * odd_full + (n*n) * even_full - (n+1) * odd_corners + n * even_corners;
148-
149-
150-
for x1, x2, y1, y2 in [(0, X, -Y*2, -Y), (0, X, Y*2, Y*3), (-X*2, -X, 0, Y), (X*2, X*3, 0, Y)]:
151-
for y in range(y1, y2):
152-
for x in range(x1, x2):
153-
if (y, x) in dists:
154-
d = dists[(y, x)]
155-
for times in range(target // S+10):
156-
num = d + S * times
157-
if num <= target:
158-
s += num % 2 == mod
159-
160-
for xlims, ylims in [((-X*2, -X), (-Y*2, -Y)), ((X*2, X*3), (-Y*2, -Y)), ((X*2, X*3), (Y*2, Y*3)), ((-X*2, -X), (Y*2, Y*3))]:
161-
for y in range(*ylims):
162-
for x in range(*xlims):
163-
if (y, x) in dists:
164-
d = dists[(y, x)]
165-
for times in range(target // S+10):
166-
num = d + S * times
167-
if num <= target:
168-
s += (num % 2 == mod) * (times+3)
169-
170-
# num = (dists[(y, x)] - S * 2) + (target // S) * S
171-
# if num <= target:
172-
# s += (num % 2 == (not mod)) * (target // S - 2)
173-
174-
# num = (dists[(y, x)] - S * 3) + (target // S) * S
175-
# if num <= target:
176-
# s += (num % 2 == mod) * (target // S - 3)
177-
178-
# num = (dists[(y, x)]) + (target // S) * S
179-
# if num <= target:
180-
# s += (num % 2 == (not mod)) * (target // S)
181-
print()
182-
183-
print(s+curr_sum)
184-
exit()
185-
186-
for y in range(0, Y):
187-
for x in range(0, X):
188-
if (y, x) in dists:
189-
dist = dists[(y, x)]
190-
if dist % 2 == mod and dist <= target:
191-
s += 1
192-
for dy, dx in dirs + dirs_diag:
193-
dist = dists[(y+Y*2*dy, x+X*2*dx)] - S
194-
new = max(-1, (target - dist))
195-
if new >= 0:
196-
# print(y, x, new, target, dist)
197-
if new % 2 == mod:
198-
div = S if dy == 0 or dx == 0 else S * 2
199-
s += new // div + 1
200-
for dy, dx in dirs:
201-
dist = dists[(y+Y*2*dy, x+X*2*dx)] - S
202-
# print(dist)
203-
for side in [-1, 1]:
204-
for i, rem in enumerate(range(target, -S*2, -S*2)):
205-
new = max(-1, (rem - dist))
206-
if new >= 0:
207-
if new % 2 == mod:
208-
s += (new) // S + 1
18+
if 0 <= ya < Y and 0 <= xa < X and lines[ya][xa] != '#' and (ya, xa) not in dists:
19+
dists[(ya, xa)] = dists.get((y, x), 0)+1
20+
q.append((ya, xa))
20921

210-
#
211-
# #---#
212-
# |###|
213-
# |###|
214-
# |###|
215-
# #---#
22+
n = 26501365 // X
21623

217-
print(s)
24+
even_full = sum(d % 2 == 0 for d in dists.values())
25+
odd_full = sum(d % 2 == 1 for d in dists.values())
26+
even_edges = sum(d % 2 == 0 and d > 65 for d in dists.values())
27+
odd_edges = sum(d % 2 == 1 and d > 65 for d in dists.values())
21828

29+
print(even_full - even_edges)
21930

220-
# Too low:
221-
# 618261433216623
222-
# 618249208752749 wrong
223-
# 618261433216623 same
31+
p2 = (n+1)**2 * odd_full + n**2 * even_full - (n+1) * odd_edges + n * even_edges
32+
print(p2)

2023/22/22.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
from copy import deepcopy
2+
from itertools import product
3+
4+
s1 = s2 = 0
5+
X, Y, Z = 10, 10, 400
6+
stack = [[[-1] * Z for _ in range(Y)] for _ in range(X)]
7+
bricks = []
8+
9+
for i, line in enumerate(open(0)):
10+
x1, y1, z1, x2, y2, z2 = map(int, line.replace("~", ",").split(","))
11+
bricks.append([])
12+
for x, y, z in product(range(x1, x2+1), range(y1, y2+1), range(z1, z2+1)):
13+
stack[x][y][z] = i
14+
bricks[-1].append((x, y, z))
15+
16+
def z_lower(coords):
17+
return [(x, y, z-1) for x,y,z in coords]
18+
19+
def at_z_lower(coords, stack):
20+
return {stack[x][y][z-1] for x,y,z in coords}
21+
22+
def at_z_upper(coords, stack):
23+
return {stack[x][y][z+1] for x,y,z in coords}
24+
25+
def drop_all(stack, bricks):
26+
changed = True
27+
dropped = set()
28+
while changed:
29+
changed = False
30+
for z, y, x in product(range(2, Z), range(Y), range(X)):
31+
if (brick_id := stack[x][y][z]) != -1:
32+
brick = bricks[brick_id]
33+
if all(z > 1 for _, _, z in brick):
34+
if len(at_z_lower(brick, stack) - {-1, brick_id}) == 0:
35+
for x,y,z in brick:
36+
stack[x][y][z] = -1
37+
brick = bricks[brick_id] = z_lower(brick)
38+
for x,y,z in brick:
39+
stack[x][y][z] = brick_id
40+
dropped.add(brick_id)
41+
changed = True
42+
return dropped
43+
44+
drop_all(stack, bricks)
45+
46+
for i, brick in enumerate(bricks):
47+
ids_above = at_z_upper(brick, stack) - {-1, i}
48+
can_remove = True
49+
for id_above in ids_above:
50+
supporting_ids = at_z_lower(bricks[id_above], stack) - {-1, id_above}
51+
if len(supporting_ids) == 1:
52+
can_remove = False
53+
stack2 = deepcopy(stack)
54+
bricks2 = deepcopy(bricks)
55+
for x,y,z in bricks2[i]:
56+
stack2[x][y][z] = -1
57+
bricks2[i] = []
58+
s2 += len(drop_all(stack2, bricks2) - {i})
59+
break
60+
61+
s1 += can_remove
62+
63+
print(s1, s2, sep='\n')

2023/23/23.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import sys
2+
sys.setrecursionlimit(1000000000)
3+
from collections import deque
4+
5+
lines = open(0).read().splitlines()
6+
Y, X = len(lines), len(lines[0])
7+
dirs = [(0, 1), (1, 0), (0, -1), (-1, 0)]
8+
9+
max_dist = 0
10+
def dfs(y, x, dist, visited, part2=False):
11+
global max_dist
12+
if (y, x) == (Y-1, X-2):
13+
if dist > max_dist:
14+
# Prints all current largest paths. After a couple minutes it finds the correct answer
15+
# However it does not finish within half an hour.
16+
print(dist)
17+
max_dist = dist
18+
19+
adj = []
20+
for i, (dy, dx) in enumerate(dirs):
21+
ya, xa = y+dy, x+dx
22+
if 0 <= ya < Y and 0 <= xa < X and lines[ya][xa] != '#' and (ya, xa) not in visited:
23+
adj.append((ya, xa))
24+
if not part2 and lines[ya][xa] in '>v<^' and '>v<^'.index(lines[ya][xa]) == i:
25+
continue
26+
if len(adj) == 1:
27+
visited.add(adj[0])
28+
dfs(adj[0][0], adj[0][1], dist+1, visited)
29+
elif len(adj) > 1:
30+
for a in adj:
31+
dfs(a[0], a[1], dist+1, visited | {a})
32+
33+
dfs(0, 1, 0, {(0, 1)})
34+
dfs(0, 1, 0, {(0, 1)}, part2=True)

0 commit comments

Comments
 (0)