Initial commit
This commit is contained in:
commit
97a4330bc0
110 changed files with 7006 additions and 0 deletions
4
2024/16/:w
Normal file
4
2024/16/:w
Normal file
|
@ -0,0 +1,4 @@
|
|||
####
|
||||
#.E#
|
||||
#S##
|
||||
####
|
23
2024/16/README.md
Normal file
23
2024/16/README.md
Normal file
|
@ -0,0 +1,23 @@
|
|||
Oh boy. My first time in a while doing something with mazes.
|
||||
I decided to go with a filling thing.
|
||||
I realized I need to put the direction as a dimension in the table of visited scores.
|
||||
So basically it would go up to the very last tile, and then be like "op, what if I went back to the start?", although I did not know that at the time.
|
||||
I did exhaust Python call stack, so I increased it, again and again.
|
||||
But I thought that surely, even with this dumb of an algorithm it should be able to do, so I decided to look for a bug.
|
||||
I used the depth variable (initally only used to indent print statements) as my own call stack limit that would still print the maze.
|
||||
I realized that even at 1000 depth, the maze was already filled, which puzzled me.
|
||||
I submitted the answer... and it was correct x)
|
||||
|
||||
For part 2 I first implemented something that would print only one best path.
|
||||
Then I realized my mistake, and then did something that would work if not for the fact that I optimized out
|
||||
2 paths arriving with the same score. A <= changed to < later and it was fixed.
|
||||
The optimisation didn't cost much, the "allocating a list every recursion", very much so.
|
||||
|
||||
Since it was taking a long time to compute I realized maybe I could do something clever with only considering crossways,
|
||||
since there's quite a lot of corridors.
|
||||
But I decided to instead firsrt code two2.py, which would add the position to the set of best places only when the recursion hit the best score,
|
||||
which was hardcoded from part 1 (it took 48s to run alone, sooo).
|
||||
I tried it on demo, got None as answer to part 1 and 0 as answer to part 2, completly overlooked that, and let it cook on the real input.
|
||||
In the end, the first iteration of two.py ended up being cooked first, 11 minutes after, with the right answer.
|
||||
|
||||
...a win is a win I guess
|
15
2024/16/demog
Normal file
15
2024/16/demog
Normal file
|
@ -0,0 +1,15 @@
|
|||
################
|
||||
############..E#
|
||||
###########..#.#
|
||||
##########..##.#
|
||||
#########..###.#
|
||||
########..##...#
|
||||
#######..###.###
|
||||
######..####...#
|
||||
#####..#######.#
|
||||
####..##.......#
|
||||
###..###.#######
|
||||
##..####.......#
|
||||
#..###########.#
|
||||
#S.............#
|
||||
################
|
4
2024/16/demog0
Normal file
4
2024/16/demog0
Normal file
|
@ -0,0 +1,4 @@
|
|||
####
|
||||
#.E#
|
||||
#S.#
|
||||
####
|
86
2024/16/networkx_test.py
Normal file
86
2024/16/networkx_test.py
Normal file
|
@ -0,0 +1,86 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import typing
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import networkx as nx
|
||||
|
||||
input_file = sys.argv[1]
|
||||
|
||||
with open(input_file) as fd:
|
||||
lines = [line.rstrip() for line in fd.readlines()]
|
||||
|
||||
height = len(lines)
|
||||
width = len(lines[0])
|
||||
|
||||
directions = [
|
||||
(-1, 0), # ^ North
|
||||
(0, 1), # > East
|
||||
(1, 0), # v South
|
||||
(0, -1), # < West
|
||||
]
|
||||
|
||||
# Parse input
|
||||
g = nx.DiGraph()
|
||||
for i in range(height):
|
||||
for j in range(width):
|
||||
char = lines[i][j]
|
||||
if char == "#":
|
||||
continue
|
||||
for d, direction in enumerate(directions):
|
||||
cur = (i, j, d)
|
||||
# Start/end
|
||||
if char == "E":
|
||||
g.add_edge(cur, "end", weight=0)
|
||||
elif char == "S" and d == 1:
|
||||
g.add_edge("start", cur, weight=0)
|
||||
# Rotate
|
||||
g.add_edge(cur, (i, j, (d + 1) % len(directions)), weight=1000)
|
||||
g.add_edge(cur, (i, j, (d - 1) % len(directions)), weight=1000)
|
||||
# Advance
|
||||
ii, jj = i + direction[0], j + direction[1]
|
||||
if lines[ii][jj] == "#":
|
||||
continue
|
||||
g.add_edge(cur, (ii, jj, d), weight=1)
|
||||
|
||||
# Part 1
|
||||
score = nx.shortest_path_length(g, "start", "end", weight="weight")
|
||||
print(f"{score=}")
|
||||
|
||||
# Part 2
|
||||
paths = nx.all_shortest_paths(g, "start", "end", weight="weight")
|
||||
best_orientations = set()
|
||||
for path in paths:
|
||||
best_orientations |= set(path)
|
||||
path_edges = list(zip(path, path[1:])) # Will be one random best path
|
||||
best_places = set(bo[:2] for bo in best_orientations - {"start", "end"})
|
||||
print(f"{len(best_places)=}")
|
||||
|
||||
# Draw graph
|
||||
if len(g.nodes) > 1000:
|
||||
sys.exit(0)
|
||||
|
||||
node_colors = ["blue" if node in best_orientations else "cyan" for node in g.nodes()]
|
||||
edge_colors = ["red" if edge in path_edges else "black" for edge in g.edges()]
|
||||
node_pos: dict[typing.Any, tuple[float, float]] = dict()
|
||||
for node in g.nodes():
|
||||
pos: tuple[float, float]
|
||||
if node == "start":
|
||||
pos = height - 1, 0
|
||||
elif node == "end":
|
||||
pos = 0, width - 1
|
||||
else:
|
||||
i, j, d = node
|
||||
direction = directions[d]
|
||||
pos = i + direction[0] / 3, j + direction[1] / 3
|
||||
node_pos[node] = pos[1], pos[0] * -1
|
||||
|
||||
nx.draw_networkx_nodes(g, node_pos, node_color=node_colors)
|
||||
nx.draw_networkx_edges(g, node_pos, edge_color=edge_colors)
|
||||
# nx.draw_networkx_labels(g, node_pos)
|
||||
# nx.draw_networkx_edge_labels(
|
||||
# g, node_pos, edge_labels={(u, v): d["weight"] for u, v, d in g.edges(data=True)}
|
||||
# )
|
||||
|
||||
plt.show()
|
135
2024/16/numpy_test.py
Normal file
135
2024/16/numpy_test.py
Normal file
|
@ -0,0 +1,135 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
|
||||
import numpy as np
|
||||
import scipy as sp
|
||||
|
||||
dtype = np.int32
|
||||
|
||||
input_file = sys.argv[1]
|
||||
|
||||
with open(input_file) as fd:
|
||||
lines = [line.rstrip() for line in fd.readlines()]
|
||||
|
||||
height = len(lines)
|
||||
width = len(lines[0])
|
||||
start = height - 2, 1
|
||||
stop = 1, width - 2
|
||||
|
||||
directions = [
|
||||
(-1, 0), # ^ North
|
||||
(0, 1), # > East
|
||||
(1, 0), # v South
|
||||
(0, -1), # < West
|
||||
]
|
||||
directions_keys = ("^", ">", "v", "<")
|
||||
|
||||
walls = np.zeros((height, width), dtype)
|
||||
for i in range(height):
|
||||
for j in range(width):
|
||||
if lines[i][j] == "#":
|
||||
walls[i, j] = 1
|
||||
invwalls = 1 - walls
|
||||
|
||||
# print("Walls")
|
||||
# print(walls)
|
||||
|
||||
# TEST 4
|
||||
|
||||
scores = np.zeros((height, width, len(directions)), dtype)
|
||||
scores[start[0], start[1], 1] = 1
|
||||
|
||||
for i in range(1000):
|
||||
print("Step", i)
|
||||
oldscores = scores.copy()
|
||||
for od, odir in enumerate(directions):
|
||||
for nd, ndir in enumerate(directions):
|
||||
score = scores[:, :, nd]
|
||||
moved = sp.ndimage.shift(oldscores[:, :, od], ndir)
|
||||
increment = 1 if nd == od else 1001
|
||||
moved = (moved + increment) * (moved > 0)
|
||||
moved = moved * invwalls
|
||||
mask = (moved > 0) & ((score == 0) | (score > moved))
|
||||
scores[:, :, nd] = (score * ~mask) + (moved * mask)
|
||||
|
||||
# for d, dir in enumerate(directions):
|
||||
# print("Direction", directions_keys[d])
|
||||
# print(scores[:, :, d])
|
||||
|
||||
if (scores == oldscores).all():
|
||||
break
|
||||
else:
|
||||
print("Limit!")
|
||||
|
||||
end_score = min(filter(lambda d: d > 0, scores[stop])) - 1
|
||||
print(f"{end_score=}")
|
||||
|
||||
# TEST 3
|
||||
|
||||
# scores = [np.zeros((height, width), dtype) for _ in directions]
|
||||
# scores[1][start] = 1
|
||||
#
|
||||
# for i in range(100):
|
||||
# print("Step", i)
|
||||
# for od, odir in enumerate(directions):
|
||||
# oldscore = scores[od].copy()
|
||||
# for nd, ndir in enumerate(directions):
|
||||
# score = scores[nd]
|
||||
# moved = sp.ndimage.shift(oldscore, ndir)
|
||||
# increment = 1 if nd == od else 1001
|
||||
# moved = (moved + increment) * (moved > 0)
|
||||
# moved = moved * invwalls
|
||||
# mask = (moved > 0) & ((score == 0) | (score > moved))
|
||||
# scores[nd] = (score * ~mask) + (moved * mask)
|
||||
#
|
||||
# final_score = None
|
||||
# for d, dir in enumerate(directions):
|
||||
# print("Direction", directions_keys[d])
|
||||
# print(scores[d])
|
||||
# end_score = scores[d][stop]
|
||||
# if end_score > 0:
|
||||
# if final_score is None or end_score < final_score:
|
||||
# final_score = end_score
|
||||
#
|
||||
# if final_score:
|
||||
# final_score -= 1
|
||||
# print(f"{final_score=}")
|
||||
# break
|
||||
# else:
|
||||
# print("Limit!")
|
||||
|
||||
|
||||
# TEST 2
|
||||
|
||||
# score = np.zeros((height, width), dtype)
|
||||
# score[start] = 1
|
||||
#
|
||||
# for i in range(10):
|
||||
# print("Step", i)
|
||||
# oldscore = score.copy()
|
||||
# for nd, ndir in enumerate(directions):
|
||||
# moved = sp.ndimage.shift(oldscore, ndir)
|
||||
# moved = (moved + 1) * (moved > 0)
|
||||
# moved = moved * invwalls
|
||||
# mask = (moved > 0) & ((score == 0) | (score > moved))
|
||||
# score = (score * ~mask) + (moved * mask)
|
||||
# print(score)
|
||||
|
||||
# TEST 1
|
||||
|
||||
# directions = np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]], dtype)
|
||||
#
|
||||
# visited = np.zeros((height, width), dtype)
|
||||
# visited[start] = 1
|
||||
#
|
||||
# for i in range(1000):
|
||||
# print("Step", i)
|
||||
# new = sp.signal.convolve2d(visited, directions, mode="same")
|
||||
# visited = (((new > 0) - walls) > 0)
|
||||
# print(visited * 1)
|
||||
# if visited[stop]:
|
||||
# break
|
||||
# else:
|
||||
# print("Limit!")
|
||||
# print(i)
|
86
2024/16/one.py
Normal file
86
2024/16/one.py
Normal file
|
@ -0,0 +1,86 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import pprint
|
||||
import sys
|
||||
|
||||
input_file = sys.argv[1]
|
||||
|
||||
with open(input_file) as fd:
|
||||
lines = [line.rstrip() for line in fd.readlines()]
|
||||
|
||||
height = len(lines)
|
||||
width = len(lines[0])
|
||||
|
||||
vec = tuple[int, int]
|
||||
|
||||
directions = [
|
||||
(-1, 0), # ^ North
|
||||
(0, 1), # > East
|
||||
(1, 0), # v South
|
||||
(0, -1), # < West
|
||||
]
|
||||
|
||||
directions_keys = ("^", ">", "v", "<")
|
||||
|
||||
min_scores: list[list[list[None | int]]] = list()
|
||||
for _ in range(height):
|
||||
line: list[list[None | int]] = list()
|
||||
for _ in range(width):
|
||||
cell: list[None | int] = [None] * len(directions)
|
||||
line.append(cell)
|
||||
min_scores.append(line)
|
||||
|
||||
start = height - 2, 1
|
||||
|
||||
|
||||
def walk(pos: vec, dir: int, score: int, depth: int = 0) -> int | None:
|
||||
i, j = pos
|
||||
char = lines[i][j]
|
||||
|
||||
if depth > 1000:
|
||||
return None
|
||||
|
||||
# print("-" * depth, 28, pos, char, directions_keys[dir], score)
|
||||
if char == "E":
|
||||
return score
|
||||
elif char == "#":
|
||||
return None
|
||||
|
||||
min_score = min_scores[i][j][dir]
|
||||
if min_score is not None and score >= min_score:
|
||||
# print("-" * depth, f" 32 already taken {score} >= {min_score}")
|
||||
return None
|
||||
min_scores[i][j][dir] = score
|
||||
|
||||
mscore = None
|
||||
for ndir, direction in enumerate(directions):
|
||||
ii, jj = i + direction[0], j + direction[1]
|
||||
price = 1 if dir == ndir else 1001
|
||||
nscore = walk((ii, jj), ndir, score + price, depth+1)
|
||||
if nscore is None:
|
||||
continue
|
||||
if mscore is None or nscore < mscore:
|
||||
mscore = nscore
|
||||
return mscore
|
||||
|
||||
sys.setrecursionlimit(9000)
|
||||
tot_score = walk(start, 1, 0)
|
||||
|
||||
# Viz
|
||||
for i in range(height):
|
||||
cline = ""
|
||||
for j in range(width):
|
||||
char = lines[i][j]
|
||||
min_score = None
|
||||
for d in range(len(directions)):
|
||||
score = min_scores[i][j][d]
|
||||
if score is None:
|
||||
continue
|
||||
if min_score is None or score < min_score:
|
||||
char = directions_keys[d]
|
||||
min_score = score
|
||||
cline += char
|
||||
print(cline)
|
||||
print()
|
||||
|
||||
print(tot_score)
|
93
2024/16/one_opti.py
Normal file
93
2024/16/one_opti.py
Normal file
|
@ -0,0 +1,93 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import pprint
|
||||
import sys
|
||||
|
||||
input_file = sys.argv[1]
|
||||
|
||||
with open(input_file) as fd:
|
||||
lines = [line.rstrip() for line in fd.readlines()]
|
||||
|
||||
height = len(lines)
|
||||
width = len(lines[0])
|
||||
|
||||
vec = tuple[int, int]
|
||||
|
||||
directions = [
|
||||
(-1, 0), # ^ North
|
||||
(0, 1), # > East
|
||||
(1, 0), # v South
|
||||
(0, -1), # < West
|
||||
]
|
||||
|
||||
directions_keys = ("^", ">", "v", "<")
|
||||
|
||||
min_scores: list[list[list[None | int]]] = list()
|
||||
for _ in range(height):
|
||||
line: list[list[None | int]] = list()
|
||||
for _ in range(width):
|
||||
cell: list[None | int] = [None] * len(directions)
|
||||
line.append(cell)
|
||||
min_scores.append(line)
|
||||
|
||||
start = height - 2, 1
|
||||
|
||||
|
||||
def walk(pos: vec, dir: int, score: int, depth: int = 0) -> int | None:
|
||||
i, j = pos
|
||||
char = lines[i][j]
|
||||
|
||||
if depth > 1000:
|
||||
return None
|
||||
|
||||
# print("-" * depth, 28, pos, char, directions_keys[dir], score)
|
||||
if char == "E":
|
||||
return score
|
||||
elif char == "#":
|
||||
return None
|
||||
|
||||
min_score = min_scores[i][j][dir]
|
||||
for d, min_score in enumerate(min_scores[i][j]):
|
||||
if min_score is None:
|
||||
continue
|
||||
if d == dir:
|
||||
if score >= min_score:
|
||||
return None
|
||||
else:
|
||||
if score >= min_score + 1000:
|
||||
return None
|
||||
min_scores[i][j][dir] = score
|
||||
|
||||
mscore = None
|
||||
for ndir, direction in enumerate(directions):
|
||||
ii, jj = i + direction[0], j + direction[1]
|
||||
price = 1 if dir == ndir else 1001
|
||||
nscore = walk((ii, jj), ndir, score + price, depth + 1)
|
||||
if nscore is None:
|
||||
continue
|
||||
if mscore is None or nscore < mscore:
|
||||
mscore = nscore
|
||||
return mscore
|
||||
|
||||
|
||||
sys.setrecursionlimit(3000)
|
||||
tot_score = walk(start, 1, 0)
|
||||
|
||||
# Viz
|
||||
for i in range(height):
|
||||
cline = ""
|
||||
for j in range(width):
|
||||
char = lines[i][j]
|
||||
min_score = None
|
||||
for d in range(len(directions)):
|
||||
score = min_scores[i][j][d]
|
||||
if score is None:
|
||||
continue
|
||||
if min_score is None or score < min_score:
|
||||
char = directions_keys[d]
|
||||
min_score = score
|
||||
cline += char
|
||||
print(cline)
|
||||
print()
|
||||
|
||||
print(tot_score)
|
27
2024/16/reddit_edge_case
Normal file
27
2024/16/reddit_edge_case
Normal file
|
@ -0,0 +1,27 @@
|
|||
###########################
|
||||
#######################..E#
|
||||
######################..#.#
|
||||
#####################..##.#
|
||||
####################..###.#
|
||||
###################..##...#
|
||||
##################..###.###
|
||||
#################..####...#
|
||||
################..#######.#
|
||||
###############..##.......#
|
||||
##############..###.#######
|
||||
#############..####.......#
|
||||
############..###########.#
|
||||
###########..##...........#
|
||||
##########..###.###########
|
||||
#########..####...........#
|
||||
########..###############.#
|
||||
#######..##...............#
|
||||
######..###.###############
|
||||
#####..####...............#
|
||||
####..###################.#
|
||||
###..##...................#
|
||||
##..###.###################
|
||||
#..####...................#
|
||||
#.#######################.#
|
||||
#S........................#
|
||||
###########################
|
14
2024/16/reddit_open_maze
Normal file
14
2024/16/reddit_open_maze
Normal file
|
@ -0,0 +1,14 @@
|
|||
####################################################
|
||||
#......................................#..........E#
|
||||
#......................................#...........#
|
||||
#....................#.................#...........#
|
||||
#....................#.................#...........#
|
||||
#....................#.................#...........#
|
||||
#....................#.................#...........#
|
||||
#....................#.................#...........#
|
||||
#....................#.................#...........#
|
||||
#....................#.................#...........#
|
||||
#....................#.................#...........#
|
||||
#....................#.............................#
|
||||
#S...................#.............................#
|
||||
####################################################
|
105
2024/16/two.py
Normal file
105
2024/16/two.py
Normal file
|
@ -0,0 +1,105 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import pprint
|
||||
import sys
|
||||
|
||||
input_file = sys.argv[1]
|
||||
|
||||
with open(input_file) as fd:
|
||||
lines = [line.rstrip() for line in fd.readlines()]
|
||||
|
||||
height = len(lines)
|
||||
width = len(lines[0])
|
||||
|
||||
vec = tuple[int, int]
|
||||
|
||||
directions = [
|
||||
(-1, 0), # ^ North
|
||||
(0, 1), # > East
|
||||
(1, 0), # v South
|
||||
(0, -1), # < West
|
||||
]
|
||||
|
||||
directions_keys = ("^", ">", "v", "<")
|
||||
|
||||
min_scores: list[list[list[None | int]]] = list()
|
||||
for _ in range(height):
|
||||
line: list[list[None | int]] = list()
|
||||
for _ in range(width):
|
||||
cell: list[None | int] = [None] * len(directions)
|
||||
line.append(cell)
|
||||
min_scores.append(line)
|
||||
|
||||
start = height - 2, 1
|
||||
|
||||
valid_paths: list[tuple[int, set[vec]]] = list()
|
||||
|
||||
|
||||
def walk(pos: vec, dir: int, score: int, path: list[vec]) -> int | None:
|
||||
i, j = pos
|
||||
char = lines[i][j]
|
||||
|
||||
depth = len(path)
|
||||
path = path + [pos]
|
||||
|
||||
if depth > 1000:
|
||||
return None
|
||||
|
||||
# print("-" * depth, 28, pos, char, directions_keys[dir], score)
|
||||
if char == "E":
|
||||
valid_paths.append((score, set(path)))
|
||||
return score
|
||||
elif char == "#":
|
||||
return None
|
||||
|
||||
min_score = min_scores[i][j][dir]
|
||||
if min_score is not None and score > min_score:
|
||||
# print("-" * depth, f" 32 already taken {score} >= {min_score}")
|
||||
return None
|
||||
min_scores[i][j][dir] = score
|
||||
|
||||
mscore = None
|
||||
for ndir, direction in enumerate(directions):
|
||||
ii, jj = i + direction[0], j + direction[1]
|
||||
price = 1 if dir == ndir else 1001
|
||||
nscore = walk((ii, jj), ndir, score + price, path)
|
||||
if nscore is None:
|
||||
continue
|
||||
if mscore is None or nscore < mscore:
|
||||
mscore = nscore
|
||||
return mscore
|
||||
|
||||
|
||||
sys.setrecursionlimit(9000)
|
||||
tot_score = walk(start, 1, 0, [])
|
||||
|
||||
print(76, len(valid_paths))
|
||||
all_best: set[vec] = set()
|
||||
for s, path in valid_paths:
|
||||
if s != tot_score:
|
||||
continue
|
||||
print(81, "BEST")
|
||||
all_best |= path
|
||||
|
||||
# Viz
|
||||
for i in range(height):
|
||||
cline = ""
|
||||
for j in range(width):
|
||||
char = lines[i][j]
|
||||
pos = i, j
|
||||
if pos in all_best:
|
||||
min_score = None
|
||||
for d in range(len(directions)):
|
||||
score = min_scores[i][j][d]
|
||||
if score is None:
|
||||
continue
|
||||
if min_score is None or score < min_score:
|
||||
char = directions_keys[d]
|
||||
min_score = score
|
||||
cline += char
|
||||
print(cline)
|
||||
print()
|
||||
|
||||
|
||||
print(tot_score)
|
||||
print(len(all_best))
|
95
2024/16/two2.py
Normal file
95
2024/16/two2.py
Normal file
|
@ -0,0 +1,95 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import pprint
|
||||
import sys
|
||||
|
||||
input_file = sys.argv[1]
|
||||
|
||||
with open(input_file) as fd:
|
||||
lines = [line.rstrip() for line in fd.readlines()]
|
||||
|
||||
height = len(lines)
|
||||
width = len(lines[0])
|
||||
|
||||
vec = tuple[int, int]
|
||||
|
||||
directions = [
|
||||
(-1, 0), # ^ North
|
||||
(0, 1), # > East
|
||||
(1, 0), # v South
|
||||
(0, -1), # < West
|
||||
]
|
||||
|
||||
directions_keys = ("^", ">", "v", "<")
|
||||
|
||||
min_scores: list[list[list[None | int]]] = list()
|
||||
for _ in range(height):
|
||||
line: list[list[None | int]] = list()
|
||||
for _ in range(width):
|
||||
cell: list[None | int] = [None] * len(directions)
|
||||
line.append(cell)
|
||||
min_scores.append(line)
|
||||
|
||||
start = height - 2, 1
|
||||
|
||||
best: set[vec] = set()
|
||||
|
||||
def walk(pos: vec, dir: int, score: int, depth: int) -> int | None:
|
||||
i, j = pos
|
||||
char = lines[i][j]
|
||||
|
||||
if depth > 1000:
|
||||
return None
|
||||
|
||||
# print("-" * depth, 28, pos, char, directions_keys[dir], score)
|
||||
if char == "E":
|
||||
if score == 90440:
|
||||
return score
|
||||
else:
|
||||
return None
|
||||
elif char == "#":
|
||||
return None
|
||||
|
||||
min_score = min_scores[i][j][dir]
|
||||
if min_score is not None and score > min_score:
|
||||
# print("-" * depth, f" 32 already taken {score} >= {min_score}")
|
||||
return None
|
||||
min_scores[i][j][dir] = score
|
||||
|
||||
mscore = None
|
||||
for ndir, direction in enumerate(directions):
|
||||
ii, jj = i + direction[0], j + direction[1]
|
||||
price = 1 if dir == ndir else 1001
|
||||
nscore = walk((ii, jj), ndir, score + price, depth + 1)
|
||||
if nscore is None:
|
||||
continue
|
||||
best.add((ii, jj))
|
||||
# if mscore is None or nscore < mscore:
|
||||
# mscore = nscore
|
||||
return mscore
|
||||
|
||||
|
||||
sys.setrecursionlimit(9000)
|
||||
tot_score = walk(start, 1, 0, 0)
|
||||
|
||||
# Viz
|
||||
for i in range(height):
|
||||
cline = ""
|
||||
for j in range(width):
|
||||
char = lines[i][j]
|
||||
pos = i, j
|
||||
min_score = None
|
||||
for d in range(len(directions)):
|
||||
score = min_scores[i][j][d]
|
||||
if score is None:
|
||||
continue
|
||||
if min_score is None or score < min_score:
|
||||
char = directions_keys[d]
|
||||
min_score = score
|
||||
cline += char
|
||||
print(cline)
|
||||
print()
|
||||
|
||||
|
||||
print(tot_score)
|
||||
print(len(best))
|
111
2024/16/two_opti.py
Normal file
111
2024/16/two_opti.py
Normal file
|
@ -0,0 +1,111 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import pprint
|
||||
import sys
|
||||
|
||||
input_file = sys.argv[1]
|
||||
|
||||
with open(input_file) as fd:
|
||||
lines = [line.rstrip() for line in fd.readlines()]
|
||||
|
||||
height = len(lines)
|
||||
width = len(lines[0])
|
||||
|
||||
vec = tuple[int, int]
|
||||
|
||||
directions = [
|
||||
(-1, 0), # ^ North
|
||||
(0, 1), # > East
|
||||
(1, 0), # v South
|
||||
(0, -1), # < West
|
||||
]
|
||||
|
||||
directions_keys = ("^", ">", "v", "<")
|
||||
|
||||
min_scores: list[list[list[None | int]]] = list()
|
||||
for _ in range(height):
|
||||
line: list[list[None | int]] = list()
|
||||
for _ in range(width):
|
||||
cell: list[None | int] = [None] * len(directions)
|
||||
line.append(cell)
|
||||
min_scores.append(line)
|
||||
|
||||
start = height - 2, 1
|
||||
|
||||
valid_paths: list[tuple[int, set[vec]]] = list()
|
||||
|
||||
|
||||
def walk(pos: vec, dir: int, score: int, path: list[vec]) -> int | None:
|
||||
i, j = pos
|
||||
char = lines[i][j]
|
||||
|
||||
depth = len(path)
|
||||
path = path + [pos]
|
||||
|
||||
if depth > 1000:
|
||||
return None
|
||||
|
||||
# print("-" * depth, 28, pos, char, directions_keys[dir], score)
|
||||
if char == "E":
|
||||
valid_paths.append((score, set(path)))
|
||||
return score
|
||||
elif char == "#":
|
||||
return None
|
||||
|
||||
min_score = min_scores[i][j][dir]
|
||||
for d, min_score in enumerate(min_scores[i][j]):
|
||||
if min_score is None:
|
||||
continue
|
||||
if d == dir:
|
||||
if score > min_score:
|
||||
return None
|
||||
else:
|
||||
if score > min_score + 1000:
|
||||
return None
|
||||
min_scores[i][j][dir] = score
|
||||
|
||||
mscore = None
|
||||
for ndir, direction in enumerate(directions):
|
||||
ii, jj = i + direction[0], j + direction[1]
|
||||
price = 1 if dir == ndir else 1001
|
||||
nscore = walk((ii, jj), ndir, score + price, path)
|
||||
if nscore is None:
|
||||
continue
|
||||
if mscore is None or nscore < mscore:
|
||||
mscore = nscore
|
||||
return mscore
|
||||
|
||||
|
||||
sys.setrecursionlimit(9000)
|
||||
tot_score = walk(start, 1, 0, [])
|
||||
|
||||
print(76, len(valid_paths))
|
||||
all_best: set[vec] = set()
|
||||
for s, path in valid_paths:
|
||||
if s != tot_score:
|
||||
continue
|
||||
print(81, "BEST")
|
||||
all_best |= path
|
||||
|
||||
# Viz
|
||||
for i in range(height):
|
||||
cline = ""
|
||||
for j in range(width):
|
||||
char = lines[i][j]
|
||||
pos = i, j
|
||||
if pos in all_best:
|
||||
min_score = None
|
||||
for d in range(len(directions)):
|
||||
score = min_scores[i][j][d]
|
||||
if score is None:
|
||||
continue
|
||||
if min_score is None or score < min_score:
|
||||
char = directions_keys[d]
|
||||
min_score = score
|
||||
cline += char
|
||||
print(cline)
|
||||
print()
|
||||
|
||||
|
||||
print(tot_score)
|
||||
print(len(all_best))
|
Loading…
Add table
Add a link
Reference in a new issue