Skip to content

Commit 378078e

Browse files
committedDec 25, 2024
feat: 2024 day 16
1 parent 1d65cf3 commit 378078e

File tree

3 files changed

+185
-0
lines changed

3 files changed

+185
-0
lines changed
 

‎2024/16a.py

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
from aoc import *
2+
from collections import defaultdict
3+
from functools import reduce
4+
import pickle
5+
from pprint import pprint as pp
6+
import sys
7+
8+
9+
DIRS = ((-1, 0), (0, 1), (1, 0), (0, -1))
10+
11+
# 0 1 2 3
12+
# N E S W
13+
14+
15+
def search(m, i, j, face, score, scorem, prev, fro):
16+
if (i, j, face) not in scorem:
17+
scorem[i, j, face] = score
18+
prev[i, j, face] = {fro}
19+
if m[i, j] == 'E':
20+
return
21+
elif scorem[i, j, face] < score:
22+
return
23+
elif scorem[i, j, face] == score:
24+
prev[i, j, face].add(fro)
25+
return
26+
else:
27+
scorem[i, j, face] = score
28+
prev[i, j, face] = {fro}
29+
if m[i, j] == 'E':
30+
return
31+
for dir, diff in enumerate(DIRS):
32+
newpos = (i + diff[0], j + diff[1])
33+
if m.get(newpos, None) in '.E':
34+
facediff = abs(face - dir)
35+
if facediff == 3:
36+
facediff = 1
37+
search(
38+
m,
39+
*newpos,
40+
dir,
41+
score + 1 + facediff * 1000,
42+
scorem,
43+
prev,
44+
(i, j, face),
45+
)
46+
47+
48+
def dfs(prev, elem: set):
49+
if not elem:
50+
return elem
51+
return (
52+
reduce(
53+
lambda x, y: x | y, (dfs(prev, prev.get(e, set())) for e in elem)
54+
)
55+
| elem
56+
)
57+
58+
59+
def main(infi: str):
60+
sys.setrecursionlimit(100000)
61+
inp = load_map_dd(infi)
62+
pos = [(i, j) for (i, j), e in inp.items() if e == 'S'][0]
63+
face = 1
64+
score = {}
65+
# store the previous position for state i, j, face -> set(previous states)
66+
prev = defaultdict(set)
67+
end = [(i, j) for (i, j), e in inp.items() if e == 'E'][0]
68+
# print(list((*end, face, score[(*end, face)]) for face in range(4)))
69+
# try:
70+
# with open('16.pickle', 'rb') as f:
71+
# prev = pickle.load(f)
72+
# except OSError:
73+
search(inp, *pos, face, 0, score, prev, None)
74+
# with open('16.pickle', 'wb') as f:
75+
# pickle.dump(prev, f)
76+
best_paths = dfs(prev, {(1, 139, 1)})
77+
best_paths.remove(None)
78+
return len(set((i, j) for i, j, _ in best_paths))
79+
80+
81+
DAY = 16
82+
FILE_TEST = f"{DAY}_testa.txt"
83+
FILE_TEST = f"{DAY}_testb.txt"
84+
FILE_EXP = f"{DAY}_exp.txt"
85+
FILE = f"{DAY}.txt"
86+
# test_and_submit(main, FILE_TEST, FILE_EXP, FILE, DAY)
87+
# print(main(FILE_TEST))
88+
print(main(FILE))

‎2024/16b.py

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
from aoc import *
2+
from itertools import (
3+
pairwise,
4+
combinations,
5+
repeat,
6+
product,
7+
accumulate,
8+
permutations,
9+
cycle,
10+
combinations_with_replacement,
11+
)
12+
from more_itertools import (
13+
first_true,
14+
flatten,
15+
ncycles,
16+
first_true,
17+
zip_broadcast,
18+
windowed,
19+
chunked,
20+
take,
21+
peekable,
22+
)
23+
import re
24+
from blessed import BlessedList
25+
from collections import (
26+
namedtuple,
27+
defaultdict,
28+
OrderedDict,
29+
Counter,
30+
deque,
31+
UserList,
32+
)
33+
import operator
34+
from operator import itemgetter
35+
from bisect import *
36+
from functools import reduce, cache, cmp_to_key
37+
import math
38+
from copy import deepcopy
39+
from math import ceil
40+
from heapq import *
41+
import sys
42+
from pprint import pprint as pp
43+
from statistics import mode
44+
from string import ascii_uppercase
45+
46+
47+
DIRS = ((-1, 0), (0, 1), (1, 0), (0, -1))
48+
49+
# 0 1 2 3
50+
# N E S W
51+
52+
53+
# TODO: Very inefficient. I have to rewrite it using Dijkstra.
54+
def search(m, i, j, face, score, scorem):
55+
if (i, j, face) not in scorem:
56+
scorem[i, j, face] = score
57+
elif scorem[i, j, face] <= score:
58+
return
59+
else:
60+
scorem[i, j, face] = score
61+
if m[i, j] == 'E':
62+
return
63+
for dir, diff in enumerate(DIRS):
64+
newpos = (i + diff[0], j + diff[1])
65+
if m.get(newpos, None) in '.E':
66+
facediff = abs(face - dir)
67+
if facediff == 3:
68+
facediff = 1
69+
search(m, *newpos, dir, score + 1 + facediff * 1000, scorem)
70+
71+
72+
def main(infi: str):
73+
sys.setrecursionlimit(100000)
74+
inp = load_map_dd(infi)
75+
pos = [(i, j) for (i, j), e in inp.items() if e == 'S'][0]
76+
face = 1
77+
score = {}
78+
search(inp, *pos, face, 0, score)
79+
end = [(i, j) for (i, j), e in inp.items() if e == 'E'][0]
80+
return min(
81+
x[3]
82+
for x in list(
83+
(*end, face, score.get((*end, face), None)) for face in range(4)
84+
)
85+
if x[3] is not None
86+
)
87+
88+
89+
DAY = 16
90+
FILE_TEST = f"{DAY}_testa.txt"
91+
FILE_TEST = f"{DAY}_testb.txt"
92+
FILE_EXP = f"{DAY}_exp.txt"
93+
FILE = f"{DAY}.txt"
94+
# test_and_submit(main, FILE_TEST, FILE_EXP, FILE, DAY)
95+
# print(main(FILE_TEST))
96+
print(main(FILE))

‎README.org

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
| 19 | 01:44:22 | 6641 | 0 | 01:50:06 | 5444 | 0 |
1414
| 18 | 00:23:32 | 2771 | 0 | 00:29:19 | 2300 | 0 |
1515
| 17 | 00:27:08 | 1748 | 0 | 07:06:10 | 5688 | 0 |
16+
| 16 | >24h | 24642 | 0 | >24h | 20241 | 0 |
1617
| 15 | 00:32:17 | 2397 | 0 | 02:59:49 | 4379 | 0 |
1718
| 14 | 00:19:09 | 1902 | 0 | 01:13:46 | 3551 | 0 |
1819
| 13 | 00:39:23 | 4308 | 0 | 12:34:52 | 21706 | 0 |

0 commit comments

Comments
 (0)
Please sign in to comment.