Solve 2024 day 21 to finish the year
This commit is contained in:
parent
376a2eac09
commit
7013c5b0a0
178
2024/d21.py
178
2024/d21.py
@ -1,25 +1,29 @@
|
|||||||
import heapq
|
|
||||||
from lib import get_data
|
from lib import get_data
|
||||||
|
from collections import deque
|
||||||
|
from functools import cache
|
||||||
|
|
||||||
|
|
||||||
data = get_data(__file__)
|
data = get_data(__file__)
|
||||||
|
# data = """029A
|
||||||
|
# 980A
|
||||||
|
# 179A
|
||||||
|
# 456A
|
||||||
|
# 379A"""
|
||||||
|
|
||||||
|
|
||||||
def new_dir(current, move):
|
def new_dir(current, move):
|
||||||
return {"<":
|
return {
|
||||||
{">": "v"},
|
"<": {">": "v"},
|
||||||
"^":
|
"^": {">": "A", "v": "v"},
|
||||||
{">": "A", "v": "v"},
|
"v": {"<": "<", ">": ">", "^": "^"},
|
||||||
"v":
|
">": {"^": "A", "<": "v"},
|
||||||
{"<": "<", ">": ">", "^": "^"},
|
"A": {"<": "^", "v": ">"},
|
||||||
">":
|
|
||||||
{"^": "A", "<": "v"},
|
|
||||||
"A":
|
|
||||||
{"<": "^", "v": ">"}
|
|
||||||
}[current].get(move, None)
|
}[current].get(move, None)
|
||||||
|
|
||||||
|
|
||||||
def new_num(current, move):
|
def new_num(current, move):
|
||||||
return {"7": {">": "8", "v": "4",},
|
return {
|
||||||
|
"7": {">": "8", "v": "4", },
|
||||||
"8": {"<": "7", ">": "9", "v": "5"},
|
"8": {"<": "7", ">": "9", "v": "5"},
|
||||||
"9": {"<": "8", "v": "6"},
|
"9": {"<": "8", "v": "6"},
|
||||||
"4": {"^": "7", ">": "5", "v": "1"},
|
"4": {"^": "7", ">": "5", "v": "1"},
|
||||||
@ -33,111 +37,51 @@ def new_num(current, move):
|
|||||||
}[current].get(move, None)
|
}[current].get(move, None)
|
||||||
|
|
||||||
|
|
||||||
def new_state(press, node, has_numpad):
|
@cache
|
||||||
key_pads, num_pad, typed, pressed = node
|
def find(code, depth, lookup):
|
||||||
key_pads = list(key_pads)
|
if depth == 0:
|
||||||
pressed = pressed + press
|
return len(code)
|
||||||
|
code = list(code)
|
||||||
for i in range(len(key_pads)):
|
|
||||||
if press == "A":
|
|
||||||
press = key_pads[i]
|
|
||||||
else:
|
|
||||||
key_pads[i] = new_dir(key_pads[i], press)
|
|
||||||
if key_pads[i] is None:
|
|
||||||
return None
|
|
||||||
press = None
|
|
||||||
break
|
|
||||||
|
|
||||||
if press is not None:
|
|
||||||
if has_numpad:
|
|
||||||
if press == "A":
|
|
||||||
typed = typed + num_pad
|
|
||||||
else:
|
|
||||||
num_pad = new_num(num_pad, press)
|
|
||||||
if num_pad is None:
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
typed = typed + press
|
|
||||||
nnode = tuple(key_pads), num_pad, typed, pressed
|
|
||||||
return nnode
|
|
||||||
|
|
||||||
# if press == "A":
|
|
||||||
# if key_pads[0] == "A":
|
|
||||||
# if key_pads[1] == "A":
|
|
||||||
# entered += num_pad
|
|
||||||
# else:
|
|
||||||
# num_pad = new_num(num_pad, key_pads[1])
|
|
||||||
# else:
|
|
||||||
# key_pads[1] = new_dir(key_pads[1], key_pads[0])
|
|
||||||
# else:
|
|
||||||
# key_pads[0] = new_dir(key_pads[0], press)
|
|
||||||
#
|
|
||||||
# if key_pads[0] is None or key_pads[1] is None or num_pad is None:
|
|
||||||
# return None
|
|
||||||
# return tuple(key_pads), num_pad, typed
|
|
||||||
|
|
||||||
def find(code, key_pads=2, has_numpad=False):
|
|
||||||
_, _, TYPED, ENTERED = 0, 1, 2, 3
|
|
||||||
|
|
||||||
def dist(n1, n2):
|
|
||||||
if n1 == 0: return 0
|
|
||||||
return 1
|
|
||||||
|
|
||||||
def h(node):
|
|
||||||
return len(code) - len(node[TYPED])
|
|
||||||
|
|
||||||
def is_goal(node):
|
|
||||||
return node[TYPED] == code
|
|
||||||
|
|
||||||
def neighbors(node):
|
|
||||||
nbs = []
|
|
||||||
for move in '<^v>A':
|
|
||||||
nb = new_state(move, node, has_numpad)
|
|
||||||
if nb is None:
|
|
||||||
continue
|
|
||||||
if not code.startswith(nb[TYPED]):
|
|
||||||
continue
|
|
||||||
nbs.append(nb)
|
|
||||||
return nbs
|
|
||||||
|
|
||||||
def hash(node):
|
|
||||||
return node[:-1]
|
|
||||||
|
|
||||||
key_pads = tuple(['A' for _ in range(key_pads)])
|
|
||||||
start = (key_pads, 'A', '', '')
|
|
||||||
starts = [start]
|
|
||||||
open_set = []
|
|
||||||
g_score = {}
|
|
||||||
cost = None
|
|
||||||
|
|
||||||
for start in starts:
|
|
||||||
heapq.heappush(open_set, (h(start), start))
|
|
||||||
g_score[hash(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[hash(current)]
|
|
||||||
# print(current)
|
|
||||||
cost = g_score[hash(current)]
|
|
||||||
cost = current[ENTERED]
|
|
||||||
break
|
|
||||||
|
|
||||||
# print(current)
|
|
||||||
for neighbor in neighbors(current):
|
|
||||||
tentative_g_score = g_score[hash(current)] + dist(current, neighbor)
|
|
||||||
if tentative_g_score < g_score.get(hash(neighbor), 10**15):
|
|
||||||
# print(" ", neighbor, end="")
|
|
||||||
# input()
|
|
||||||
g_score[hash(neighbor)] = tentative_g_score
|
|
||||||
f_score = g_score[hash(neighbor)] + h(neighbor)
|
|
||||||
heapq.heappush(open_set, (f_score, neighbor))
|
|
||||||
return cost
|
|
||||||
|
|
||||||
t = 0
|
t = 0
|
||||||
|
current = "A"
|
||||||
|
while code:
|
||||||
|
solutions = []
|
||||||
|
target = code.pop(0)
|
||||||
|
start = (current, "")
|
||||||
|
seen = set()
|
||||||
|
queue = deque([start])
|
||||||
|
while queue:
|
||||||
|
node = queue.popleft()
|
||||||
|
if node in seen:
|
||||||
|
continue
|
||||||
|
seen.add(node)
|
||||||
|
if node[0] == target:
|
||||||
|
solution = node[1] + "A"
|
||||||
|
if len(solutions) == 0:
|
||||||
|
solutions.append(solution)
|
||||||
|
elif len(solutions[-1]) == len(solution):
|
||||||
|
solutions.append(solution)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
continue
|
||||||
|
|
||||||
|
for c in "<>v^":
|
||||||
|
next = lookup(node[0], c)
|
||||||
|
if next is not None:
|
||||||
|
queue.append((next, node[1] + c))
|
||||||
|
current = target
|
||||||
|
t += min(find(code, depth - 1, new_dir) for code in solutions)
|
||||||
|
return t
|
||||||
|
|
||||||
|
|
||||||
|
p1, p2 = 0, 0
|
||||||
for line in data.splitlines():
|
for line in data.splitlines():
|
||||||
s = find(line, 2, True)
|
|
||||||
i = int("".join([c for c in line if c.isdigit()]))
|
i = int("".join([c for c in line if c.isdigit()]))
|
||||||
s = len(s)
|
s1 = find(line, 3, new_num)
|
||||||
t += s * i
|
s2 = find(line, 26, new_num)
|
||||||
print(t)
|
p1 += s1 * i
|
||||||
|
p2 += s2 * i
|
||||||
|
|
||||||
|
|
||||||
|
print(p1)
|
||||||
|
print(p2)
|
||||||
|
@ -311,9 +311,9 @@ and focus. Of course, learning more algorithms and techniques helps.
|
|||||||
- Day 18: `14:35:01 20398 0 14:37:18 19550 0`
|
- Day 18: `14:35:01 20398 0 14:37:18 19550 0`
|
||||||
- Day 19: `00:14:37 2001 0 00:19:43 1584 0`
|
- Day 19: `00:14:37 2001 0 00:19:43 1584 0`
|
||||||
- Day 20: `01:08:53 3637 0 01:53:01 2837 0`
|
- Day 20: `01:08:53 3637 0 01:53:01 2837 0`
|
||||||
- Day 21: `00:48:40 215 0 - - -`
|
- Day 21: `00:48:40 215 0 >24h 16427 0`
|
||||||
- Day 22: `00:13:04 1930 0 00:28:29 739 0`
|
- Day 22: `00:13:04 1930 0 00:28:29 739 0`
|
||||||
- Day 23: ` >24h 20096 0 >24h 17620 0`
|
- Day 23: ` >24h 20096 0 >24h 17620 0`
|
||||||
- Day 24: `15:57:01 17307 0 >24h 11326 0`
|
- Day 24: `15:57:01 17307 0 >24h 11326 0`
|
||||||
- Day 25: `10:41:54 14140 0 - - -`
|
- Day 25: `10:41:54 14140 0 >24h 13631 0`
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user