2024 d21 wip that is not going anywhere
This commit is contained in:
parent
acdf82d768
commit
3979a60fa4
200
2024/d21.py
200
2024/d21.py
@ -1,9 +1,12 @@
|
||||
import heapq
|
||||
from lib import get_data
|
||||
from functools import cache
|
||||
|
||||
|
||||
data = get_data(__file__)
|
||||
data = """029A
|
||||
980A
|
||||
179A
|
||||
456A
|
||||
379A"""
|
||||
|
||||
|
||||
def new_dir(current, move):
|
||||
@ -87,79 +90,43 @@ def new_num(current, move):
|
||||
assert False
|
||||
|
||||
|
||||
@cache
|
||||
def new_state(press, node):
|
||||
cost, r, n, path = node
|
||||
r = list(r)
|
||||
def find_numpad(target: str) -> str:
|
||||
COUNT, CURRENT, RESULT, PATH = 0, 1, 2, 3
|
||||
|
||||
for i in range(len(r)):
|
||||
if press == "A":
|
||||
press = r[i]
|
||||
else:
|
||||
r[i] = new_dir(r[i], press)
|
||||
if r[i] is None:
|
||||
return None
|
||||
press = None
|
||||
break
|
||||
|
||||
npath = str(path)
|
||||
if press is not None:
|
||||
if press == "A":
|
||||
npath += n
|
||||
else:
|
||||
n = new_num(n, press)
|
||||
if n is None:
|
||||
return None
|
||||
|
||||
nnode = cost + 1, tuple(r), n, npath
|
||||
return nnode
|
||||
|
||||
if press == "A":
|
||||
if r[0] == "A":
|
||||
if r[1] == "A":
|
||||
path += n
|
||||
else:
|
||||
n = new_num(n, r[1])
|
||||
else:
|
||||
r[1] = new_dir(r[1], r[0])
|
||||
else:
|
||||
r[0] = new_dir(r[0], press)
|
||||
|
||||
if r[0] is None or r[1] is None or n is None:
|
||||
return None
|
||||
|
||||
npath = str(path)
|
||||
return cost + 1, tuple(r), n, npath
|
||||
|
||||
def sequence(line):
|
||||
def dist(n1, n2):
|
||||
"""cost from node to node"""
|
||||
if n1 == 0:
|
||||
return 0
|
||||
return 1
|
||||
|
||||
def h(node):
|
||||
"""heuristic function (never overestimate)"""
|
||||
return len(line) - len(node[3])
|
||||
return len(target) - len(node[RESULT])
|
||||
|
||||
def is_goal(node):
|
||||
return node[3] == line
|
||||
return node[RESULT] == target
|
||||
|
||||
def neighbors(node):
|
||||
nbs = []
|
||||
for move in '<^v>A':
|
||||
nb = new_state(move, node)
|
||||
if nb is None:
|
||||
for press in 'A^>v<':
|
||||
nnode = list(node)
|
||||
nnode[PATH] = node[PATH] + press
|
||||
if press == "A":
|
||||
nnode[RESULT] = node[RESULT] + node[CURRENT]
|
||||
else:
|
||||
nnode[CURRENT] = new_num(node[CURRENT], press)
|
||||
if nnode[CURRENT] is None:
|
||||
continue
|
||||
if not target.startswith(nnode[RESULT]):
|
||||
continue
|
||||
if not line.startswith(node[3]):
|
||||
continue
|
||||
nbs.append(nb)
|
||||
nnode[COUNT] += 1
|
||||
nbs.append(tuple(nnode))
|
||||
return nbs
|
||||
|
||||
key_pads = tuple(['A' for _ in range(5)])
|
||||
start = (0, key_pads, 'A', '')
|
||||
start = (0, 'A', '', '')
|
||||
starts = [start]
|
||||
open_set = []
|
||||
g_score = {}
|
||||
cost = None
|
||||
solutions = []
|
||||
|
||||
for start in starts:
|
||||
heapq.heappush(open_set, (h(start), start))
|
||||
@ -170,7 +137,90 @@ def sequence(line):
|
||||
if is_goal(current):
|
||||
assert current_f_score == g_score[current]
|
||||
cost = g_score[current]
|
||||
break
|
||||
cost = current[PATH]
|
||||
if solutions != [] and len(cost) > len(solutions[-1]):
|
||||
break
|
||||
solutions.append(current[PATH])
|
||||
|
||||
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))
|
||||
return solutions
|
||||
|
||||
def find_dirpad(target: str) -> str:
|
||||
COUNT, CURRENT, RESULT, PATH = 0, 1, 2, 3
|
||||
|
||||
def dist(n1, n2):
|
||||
if n1 == 0:
|
||||
return 0
|
||||
return 1
|
||||
|
||||
def h(node):
|
||||
hdist = {
|
||||
"A": {"^": 2, ">": 2, "<": 4, "v": 3, "A": 1},
|
||||
">": {"^": 3, ">": 1, "<": 3, "v": 2, "A": 2},
|
||||
"v": {"^": 2, ">": 2, "<": 2, "v": 1, "A": 3},
|
||||
"<": {"^": 3, ">": 3, "<": 1, "v": 2, "A": 4},
|
||||
"^": {"^": 1, ">": 3, "<": 3, "v": 2, "A": 2},
|
||||
}
|
||||
d = 0
|
||||
cur_key = node[CURRENT]
|
||||
nxt_key_idx = len(node[RESULT])
|
||||
while nxt_key_idx < len(target):
|
||||
nxt_key = target[nxt_key_idx]
|
||||
d += hdist[cur_key][nxt_key]
|
||||
cur_key = nxt_key
|
||||
nxt_key_idx += 1
|
||||
return d
|
||||
|
||||
def is_goal(node):
|
||||
return node[RESULT] == target
|
||||
|
||||
def neighbors(node):
|
||||
nbs = []
|
||||
to_press = list('A^>v<')
|
||||
if node[PATH]:
|
||||
to_press.remove(node[PATH][-1])
|
||||
to_press = [node[PATH][-1]] + to_press
|
||||
|
||||
for press in to_press:
|
||||
if press == "A":
|
||||
new_result = node[RESULT] + node[CURRENT]
|
||||
new_current = node[CURRENT]
|
||||
if not target.startswith(new_result):
|
||||
continue
|
||||
else:
|
||||
new_result = node[RESULT]
|
||||
new_current = new_dir(node[CURRENT], press)
|
||||
if new_current is None:
|
||||
continue
|
||||
nnode = (node[COUNT] + 1, new_current, new_result, node[PATH] + press)
|
||||
nbs.append(nnode)
|
||||
return nbs
|
||||
|
||||
start = (0, 'A', '', '')
|
||||
starts = [start]
|
||||
open_set = []
|
||||
g_score = {}
|
||||
cost = None
|
||||
solutions = []
|
||||
|
||||
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]
|
||||
cost = current[PATH]
|
||||
if solutions and len(cost) > len(solutions[-1]):
|
||||
break
|
||||
solutions.append(cost)
|
||||
|
||||
for neighbor in neighbors(current):
|
||||
tentative_g_score = g_score[current] + dist(current, neighbor)
|
||||
@ -178,12 +228,36 @@ def sequence(line):
|
||||
g_score[neighbor] = tentative_g_score
|
||||
f_score = g_score[neighbor] + h(neighbor)
|
||||
heapq.heappush(open_set, (f_score, neighbor))
|
||||
return cost
|
||||
return solutions
|
||||
|
||||
|
||||
def find(a):
|
||||
print(a)
|
||||
a = find_numpad(a)[0]
|
||||
print(len(a), a)
|
||||
a = find_dirpad(a)[0]
|
||||
print(len(a), a)
|
||||
a = find_dirpad(a)[0]
|
||||
print(len(a), a)
|
||||
return a
|
||||
|
||||
print(a)
|
||||
for a in find_numpad(a):
|
||||
print(len(a), a)
|
||||
for a in find_dirpad(a):
|
||||
print(len(a), a)
|
||||
a = find_dirpad(a)
|
||||
# print(len(a))
|
||||
# print()
|
||||
exit()
|
||||
# a = find_keypad(a)
|
||||
return a
|
||||
|
||||
t = 0
|
||||
for line in data.splitlines():
|
||||
s = sequence(line)
|
||||
s = find(line)
|
||||
i = int("".join([c for c in line if ord('0') <= ord(c) <= ord('9')]))
|
||||
print(s, i)
|
||||
t += (s - 1) * i
|
||||
print(len(s), i, s)
|
||||
# t += s * i
|
||||
|
||||
print(t)
|
||||
|
Loading…
Reference in New Issue
Block a user