2023.17
This commit is contained in:
parent
fbac277c8a
commit
8efe5a209f
5 changed files with 117 additions and 35 deletions
|
@ -1,6 +1,9 @@
|
|||
import sys
|
||||
import gridutil.grid as gu
|
||||
import gridutil.coord as cu
|
||||
from collections.abc import Callable, Iterator
|
||||
from collections import namedtuple
|
||||
from queue import PriorityQueue
|
||||
|
||||
|
||||
def parse(instr: str) -> gu.Grid:
|
||||
|
@ -8,63 +11,116 @@ def parse(instr: str) -> gu.Grid:
|
|||
return {k: int(g[k]) for k in g}
|
||||
|
||||
|
||||
def get_shortest_path(grid: gu.Grid, start: cu.Coordinate, end: cu.Coordinate) -> list[cu.Coordinate]:
|
||||
d = {start: (0, 0, cu.Direction.Right)}
|
||||
State = namedtuple("State", ["pos", "steps_taken", "direction"])
|
||||
|
||||
|
||||
def djikstra(
|
||||
start: State,
|
||||
end: Callable[[State], bool],
|
||||
neighbours: Callable[[State], Iterator[State, None, None]],
|
||||
cost: Callable[[State, State], int],
|
||||
) -> list[State]:
|
||||
dq = PriorityQueue()
|
||||
dq.put((0, start))
|
||||
d = {start: 0}
|
||||
p = {}
|
||||
f = {}
|
||||
|
||||
while end not in d:
|
||||
w = min(filter(lambda x: x[0] not in f, d.items()), key=lambda x: x[1][0])[0]
|
||||
f[w] = None
|
||||
endState = None
|
||||
while endState is None:
|
||||
w = dq.get()[1]
|
||||
|
||||
dist_w, prev_steps, prev_direction = d[w]
|
||||
|
||||
for direction in cu.Direction:
|
||||
if (direction == prev_direction and prev_steps == 3) or direction == prev_direction.opposite():
|
||||
continue
|
||||
u = cu.add(w, direction.delta())
|
||||
if u not in grid:
|
||||
continue
|
||||
|
||||
if u not in d or dist_w + grid[u] < d[u][0]:
|
||||
d[u] = (dist_w + grid[u], prev_steps + 1 if direction == prev_direction else 1, direction)
|
||||
for u in neighbours(w):
|
||||
c = d[w] + cost(w, u)
|
||||
if u not in d or c < d[u]:
|
||||
d[u] = c
|
||||
dq.put((c, u))
|
||||
p[u] = w
|
||||
|
||||
if u == end:
|
||||
if end(u):
|
||||
endState = u
|
||||
break
|
||||
|
||||
# raise SystemExit(14)
|
||||
|
||||
res = [end]
|
||||
cursor = p[end]
|
||||
while cursor != start:
|
||||
res = [endState]
|
||||
cursor = p[endState]
|
||||
while cursor is not None:
|
||||
res.append(cursor)
|
||||
cursor = p[cursor]
|
||||
cursor = p.get(cursor)
|
||||
return list(reversed(res))
|
||||
|
||||
|
||||
def one(instr: str):
|
||||
grid = parse(instr)
|
||||
end = (gu.get_max_x(grid), gu.get_max_y(grid))
|
||||
path = get_shortest_path(grid, (0, 0), end)
|
||||
|
||||
gu.print_grid(grid, file=sys.stderr)
|
||||
_debug()
|
||||
def neighbours(node: State) -> Iterator[State, None, None]:
|
||||
for direction in cu.Direction:
|
||||
if (
|
||||
direction == node.direction and node.steps_taken == 3
|
||||
) or node.direction == direction.opposite():
|
||||
continue
|
||||
|
||||
g = grid.copy()
|
||||
for p in path:
|
||||
g[p] = "█"
|
||||
nc = cu.add(node.pos, direction.delta())
|
||||
if nc not in grid:
|
||||
continue
|
||||
|
||||
gu.print_grid(g, file=sys.stderr)
|
||||
yield State(
|
||||
nc,
|
||||
(node.steps_taken + 1) if direction == node.direction else 1,
|
||||
direction,
|
||||
)
|
||||
|
||||
path = djikstra(
|
||||
State((0, 0), 0, cu.Direction.Right),
|
||||
lambda x: x.pos == end,
|
||||
neighbours,
|
||||
lambda _, x: grid[x.pos],
|
||||
)[1:]
|
||||
|
||||
acc = 0
|
||||
for node in path:
|
||||
acc += grid[node]
|
||||
acc += grid[node.pos]
|
||||
return acc
|
||||
|
||||
|
||||
def two(instr: str):
|
||||
return
|
||||
grid = parse(instr)
|
||||
end = (gu.get_max_x(grid), gu.get_max_y(grid))
|
||||
|
||||
for x in range(end[0] - 3, end[0]):
|
||||
for y in range(end[1] - 3, end[1]):
|
||||
del grid[(x, y)]
|
||||
|
||||
def neighbours(node: State) -> Iterator[State, None, None]:
|
||||
for direction in cu.Direction:
|
||||
if 0 < node.steps_taken < 4 and direction != node.direction:
|
||||
continue
|
||||
|
||||
if (
|
||||
direction == node.direction and node.steps_taken == 10
|
||||
) or node.direction == direction.opposite():
|
||||
continue
|
||||
|
||||
nc = cu.add(node.pos, direction.delta())
|
||||
if nc not in grid:
|
||||
continue
|
||||
|
||||
yield State(
|
||||
nc,
|
||||
(node.steps_taken + 1) if direction == node.direction else 1,
|
||||
direction,
|
||||
)
|
||||
|
||||
path = djikstra(
|
||||
State((0, 0), 0, cu.Direction.Right),
|
||||
lambda x: x.pos == end,
|
||||
neighbours,
|
||||
lambda _, x: grid[x.pos],
|
||||
)[1:]
|
||||
|
||||
acc = 0
|
||||
for node in path:
|
||||
acc += grid[node.pos]
|
||||
return acc
|
||||
|
||||
|
||||
def _debug(*args, **kwargs):
|
||||
|
@ -80,4 +136,4 @@ if __name__ == "__main__":
|
|||
if sys.argv[1] == "1":
|
||||
print(one(inp))
|
||||
else:
|
||||
print(two(inp))
|
||||
print(two(inp))
|
||||
|
|
|
@ -4,5 +4,15 @@
|
|||
"is": "102",
|
||||
"input": "2413432311323\n3215453535623\n3255245654254\n3446585845452\n4546657867536\n1438598798454\n4457876987766\n3637877979653\n4654967986887\n4564679986453\n1224686865563\n2546548887735\n4322674655533\n\n"
|
||||
}
|
||||
],
|
||||
"2": [
|
||||
{
|
||||
"is": "94",
|
||||
"input": "2413432311323\n3215453535623\n3255245654254\n3446585845452\n4546657867536\n1438598798454\n4457876987766\n3637877979653\n4654967986887\n4564679986453\n1224686865563\n2546548887735\n4322674655533\n\n"
|
||||
},
|
||||
{
|
||||
"is": "71",
|
||||
"input": "111111111111\n999999999991\n999999999991\n999999999991\n999999999991\n\n"
|
||||
}
|
||||
]
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 46 KiB |
|
@ -29,3 +29,5 @@
|
|||
{"day": 15, "part": 2, "runner": "go", "min": 0.0012998580932617188, "max": 0.0028612613677978516, "avg": 0.0014359498023986817, "n": 100}
|
||||
{"day": 16, "part": 1, "runner": "py", "min": 0.030805587768554688, "max": 0.03831839561462402, "avg": 0.03250444730122884, "n": 15}
|
||||
{"day": 16, "part": 2, "runner": "py", "min": 2.7863943576812744, "max": 4.14529013633728, "avg": 3.1346225261688234, "n": 15}
|
||||
{"day": 17, "part": 1, "runner": "py", "min": 5.36311674118042, "max": 5.36311674118042, "avg": 5.36311674118042, "n": 1}
|
||||
{"day": 17, "part": 2, "runner": "py", "min": 26.201914072036743, "max": 26.201914072036743, "avg": 26.201914072036743, "n": 1}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue