Initial commit
This commit is contained in:
commit
97a4330bc0
110 changed files with 7006 additions and 0 deletions
2
2024/20/README.md
Normal file
2
2024/20/README.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
Reading comprehension got me on the second part,
|
||||
a one byte change helped 🙃
|
4
2024/20/demog
Normal file
4
2024/20/demog
Normal file
|
@ -0,0 +1,4 @@
|
|||
#####
|
||||
#S#E#
|
||||
#...#
|
||||
#####
|
32
2024/20/demog2
Normal file
32
2024/20/demog2
Normal file
|
@ -0,0 +1,32 @@
|
|||
#############################################################################################
|
||||
#S#........................................................................................E#
|
||||
#.#########################################################################################.#
|
||||
#.#########################################################################################.#
|
||||
#.#########################################################################################.#
|
||||
#.#########################################################################################.#
|
||||
#.#########################################################################################.#
|
||||
#.#########################################################################################.#
|
||||
#.#########################################################################################.#
|
||||
#.#########################################################################################.#
|
||||
#.#########################################################################################.#
|
||||
#.#########################################################################################.#
|
||||
#.#########################################################################################.#
|
||||
#.#########################################################################################.#
|
||||
#.#########################################################################################.#
|
||||
#.#########################################################################################.#
|
||||
#.#########################################################################################.#
|
||||
#.#########################################################################################.#
|
||||
#.#########################################################################################.#
|
||||
#.#########################################################################################.#
|
||||
#.#########################################################################################.#
|
||||
#.#########################################################################################.#
|
||||
#.#########################################################################################.#
|
||||
#.#########################################################################################.#
|
||||
#.#########################################################################################.#
|
||||
#.#########################################################################################.#
|
||||
#.#########################################################################################.#
|
||||
#.#########################################################################################.#
|
||||
#.#########################################################################################.#
|
||||
#.#########################################################################################.#
|
||||
#...........................................................................................#
|
||||
#############################################################################################
|
5
2024/20/demog3
Normal file
5
2024/20/demog3
Normal file
|
@ -0,0 +1,5 @@
|
|||
######
|
||||
#...E#
|
||||
#S####
|
||||
#....#
|
||||
######
|
129
2024/20/one.py
Normal file
129
2024/20/one.py
Normal file
|
@ -0,0 +1,129 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import collections
|
||||
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
|
||||
]
|
||||
|
||||
Cheat = tuple[vec, int]
|
||||
|
||||
cheats: set[Cheat] = set()
|
||||
for i, line in enumerate(lines):
|
||||
if "S" in line:
|
||||
j = line.index("S")
|
||||
start = i, j
|
||||
if i in range(1, height - 1):
|
||||
for j in range(1, width - 1):
|
||||
char = lines[i][j]
|
||||
if char != "#":
|
||||
continue
|
||||
for d, direction in enumerate(directions):
|
||||
ii, jj = i + direction[0], j + direction[1]
|
||||
if ii not in range(1, height - 1) or jj not in range(1, width - 1):
|
||||
continue
|
||||
cchar = lines[ii][jj]
|
||||
if cchar == "#":
|
||||
continue
|
||||
cheats.add(((i, j), d))
|
||||
|
||||
|
||||
def print_grid(visited: list[list[int | None]], cheat: Cheat) -> None:
|
||||
for i in range(height):
|
||||
line = ""
|
||||
for j in range(width):
|
||||
char = lines[i][j]
|
||||
if visited[i][j] is not None:
|
||||
char = "O"
|
||||
if cheat[0] == (i, j):
|
||||
char = "X"
|
||||
line += char
|
||||
print(line)
|
||||
print()
|
||||
|
||||
|
||||
def time(cheat: Cheat) -> int | None:
|
||||
visited: list[list[int | None]] = list()
|
||||
for _ in range(height):
|
||||
visited.append([None] * width)
|
||||
stack: set[vec] = {start}
|
||||
for s in range(1, 10000):
|
||||
nstack: set[vec] = set()
|
||||
for pos in stack:
|
||||
i, j = pos
|
||||
for d, direction in enumerate(directions):
|
||||
if (i, j) == cheat[0]:
|
||||
if d != cheat[1]:
|
||||
continue
|
||||
ii, jj = i + direction[0], j + direction[1]
|
||||
cchar = lines[ii][jj]
|
||||
if cchar == "#" and cheat != ((ii, jj), d):
|
||||
continue
|
||||
elif cchar == "E":
|
||||
# if s == 84 - 8:
|
||||
# print_grid(visited, cheat)
|
||||
return s
|
||||
previs = visited[ii][jj]
|
||||
if previs is not None and previs < s:
|
||||
continue
|
||||
visited[ii][jj] = s
|
||||
nstack.add((ii, jj))
|
||||
stack = nstack
|
||||
|
||||
# print("Second", s)
|
||||
# print_grid(visited)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
canon_saves: collections.Counter[int] = collections.Counter()
|
||||
for k, v in (
|
||||
{
|
||||
2: 14,
|
||||
4: 14,
|
||||
6: 2,
|
||||
8: 4,
|
||||
10: 2,
|
||||
12: 3,
|
||||
20: 1,
|
||||
36: 1,
|
||||
38: 1,
|
||||
40: 1,
|
||||
64: 1,
|
||||
}
|
||||
).items():
|
||||
canon_saves[k] = v
|
||||
|
||||
normal = time(((0, 0), 0))
|
||||
assert normal
|
||||
saves: collections.Counter[int] = collections.Counter()
|
||||
saves_mo100 = 0
|
||||
print(f"{normal=}")
|
||||
print(f"{len(cheats)=}")
|
||||
for c, cheat in enumerate(cheats):
|
||||
print("Cheat", c, "/", len(cheats))
|
||||
ntime = time(cheat)
|
||||
assert ntime
|
||||
diff = normal - ntime
|
||||
saves[diff] += 1
|
||||
if diff >= 100:
|
||||
saves_mo100 += 1
|
||||
del saves[0]
|
||||
print(f"{saves=}")
|
||||
print(f"{canon_saves=}")
|
||||
print(f"{(saves == canon_saves)=}")
|
||||
print(saves_mo100)
|
||||
# 1282: too low
|
41
2024/20/reddit_part3
Normal file
41
2024/20/reddit_part3
Normal file
|
@ -0,0 +1,41 @@
|
|||
#########################################
|
||||
#...#.............#.....#.....#.....#...#
|
||||
###.#.###.#########.###.###.#####.###.#.#
|
||||
#...#...#.#.#.....#...#...#.#.........#.#
|
||||
#..##.###.#.#####.#####.#.#.#.#####.#.#.#
|
||||
#.......#.....#.#.....#.#...#...#...#.#.#
|
||||
#.###########.#.#.####.####.#.###########
|
||||
#.#.#...#...#.....#.................#...#
|
||||
#.#.#.#.#.#.###.#.#.###.#########.#####.#
|
||||
#.....#...#.....#...#.........#...#.#.#.#
|
||||
#####.#####.#####.#.#.#.#.#######.#.#.#.#
|
||||
#.....#.........#.#.#...#...#...#.#...#.#
|
||||
#.#########.#######.#####.#.##..###.###.#
|
||||
#...#.......#.....#.#...#.#...#.....#...#
|
||||
#.###.###########.#.###.#.#.###.#######.#
|
||||
#.#.#.............#.....#.#...#...#.....#
|
||||
###.#.#####.#####.#.###.#.#####.#####.###
|
||||
#...#.#.........#.#...#...#...#.#.....#.#
|
||||
###.###.#.#########.#####.###.#.#.#.#.#.#
|
||||
#S#.#...#.#.....#.....#.........#.#.#..E#
|
||||
#.#.#.#########.#.#########.#.###.#####.#
|
||||
#.....#.........#...#.#...#.#.....#...#.#
|
||||
###.#####..##.#.#####.#.###.#####.###.###
|
||||
#.#.#...#.#.#.#.#...#...#...#.........#.#
|
||||
#.#.###.###.#.#.#.#####.####.##.#.#####.#
|
||||
#.#.#.#.#.#...#.........#.#...#.#.#...#.#
|
||||
#.#.#.#.#.#####.###.#.#.#.###.#.###.###.#
|
||||
#...#.......#...#...#.#.#.........#.#...#
|
||||
#######.#####.#####.###.#.#.#####.#.###.#
|
||||
#.............#.....#.#.#.#.....#.......#
|
||||
###############.#####.#.#########.#.#.###
|
||||
#.....#...#.#.........#.#...#...#.#.#.#.#
|
||||
#.#.#.#.#.#.###.#########.###.###.#####.#
|
||||
#.#.#.#.#...........#.#.............#...#
|
||||
###.#.#.###.#######.#.#.#.###.###.#.#.###
|
||||
#...#...#...#.#...#.#...#...#.#.#.#.#...#
|
||||
###.#.#######.#.#.#.###.#####.#..##.#.###
|
||||
#.#.#...#.....#.#.#.......#.#.#...#.....#
|
||||
#.#.#####.###.#.#.#.#.#####.#####.###.#.#
|
||||
#.....#.....#.......#.............#...#.#
|
||||
#########################################
|
41
2024/20/reddit_part3g
Normal file
41
2024/20/reddit_part3g
Normal file
|
@ -0,0 +1,41 @@
|
|||
#########################################
|
||||
#...#.............#.....#.....#.....#...#
|
||||
###.#.###.#########.###.###.#####.###.#.#
|
||||
#...#...#.#.#.....#...#...#.#.........#.#
|
||||
#..##.###.#.#####.#####.#.#.#.#####.#.#.#
|
||||
#.......#.....#.#.....#.#...#...#...#.#.#
|
||||
#.###########.#.#.####.####.#.###########
|
||||
#.#.#...#...#.....#.................#...#
|
||||
#.#.#.#.#.#.###.#.#.###.#########.#####.#
|
||||
#.....#...#.....#...#.........#...#.#.#.#
|
||||
#####.#####.#####.#.#.#.#.#######.#.#.#.#
|
||||
#.....#.........#.#.#...#...#...#.#...#.#
|
||||
#.#########.#######.#####.#.##..###.###.#
|
||||
#...#.......#.....#.#...#.#...#.....#...#
|
||||
#.###.###########.#.###.#.#.###.#######.#
|
||||
#.#.#.............#.....#.#...#...#.....#
|
||||
###.#.#####.#####.#.###.#.#####.#####.###
|
||||
#...#.#.........#.#...#...#...#.#.....#.#
|
||||
###.###.#.#########.#####.###.#.#.#.#.#.#
|
||||
#S#.#...#.#.....#.....#.........#.#.#..E#
|
||||
#.#.#.#########.#.#########.#.###.#####.#
|
||||
#.....#.........#...#.#...#.#.....#...#.#
|
||||
###.#####..##.#.#####.#.###.#####.###.###
|
||||
#.#.#...#.#.#.#.#...#...#...#.........#.#
|
||||
#.#.###.###.#.#.#.#####.####.##.#.#####.#
|
||||
#.#.#.#.#.#...#.........#.#...#.#.#...#.#
|
||||
#.#.#.#.#.#####.###.#.#.#.###.#.###.###.#
|
||||
#...#.......#...#...#.#.#.........#.#...#
|
||||
#######.#####.#####.###.#.#.#####.#.###.#
|
||||
#.............#.....#.#.#.#.....#.......#
|
||||
#####################.#.#########.#.#.###
|
||||
#.....#...#.#.........#.#...#...#.#.#.#.#
|
||||
#.#.#.#.#.#.###.#########.###.###.#####.#
|
||||
#.#.#.#.#...........#.#.............#...#
|
||||
###.#.#.###.#######.#.#.#.###.###.#.#.###
|
||||
#...#...#...#.#...#.#...#...#.#.#.#.#...#
|
||||
###.#.#######.#.#.#.###.#####.#..##.#.###
|
||||
#.#.#...#.....#.#.#.......#.#.#...#.....#
|
||||
#.#.#####.###.#.#.#.#.#####.#####.###.#.#
|
||||
#.....#.....#.......#.............#...#.#
|
||||
#########################################
|
153
2024/20/two.py
Normal file
153
2024/20/two.py
Normal file
|
@ -0,0 +1,153 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import collections
|
||||
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])
|
||||
|
||||
# Adjust parameters for part/file
|
||||
part = int(sys.argv[2])
|
||||
assert part in (1, 2)
|
||||
|
||||
if input_file.startswith("input"):
|
||||
minic = 100
|
||||
else:
|
||||
if part == 1:
|
||||
minic = 1
|
||||
else:
|
||||
minic = 50
|
||||
skips = 1 if part == 1 else 20
|
||||
canon: collections.Counter[int] = collections.Counter()
|
||||
demo = {}
|
||||
if input_file == "demo":
|
||||
if skips == 1:
|
||||
demo = {2: 14, 4: 14, 6: 2, 8: 4, 10: 2} | (
|
||||
{12: 3, 20: 1, 36: 1, 38: 1, 40: 1, 64: 1}
|
||||
)
|
||||
elif skips == 20:
|
||||
demo = {50: 32, 52: 31, 54: 29, 56: 39, 58: 25, 60: 23} | (
|
||||
{62: 20, 64: 19, 66: 12, 68: 14, 70: 12, 72: 22, 74: 4, 76: 3}
|
||||
)
|
||||
for k, v in demo.items():
|
||||
canon[k] = v
|
||||
|
||||
vec = tuple[int, int]
|
||||
directions = [
|
||||
(-1, 0), # ^ North
|
||||
(0, 1), # > East
|
||||
(1, 0), # v South
|
||||
(0, -1), # < West
|
||||
]
|
||||
|
||||
# Find start position
|
||||
for i, line in enumerate(lines):
|
||||
if "S" in line:
|
||||
j = line.index("S")
|
||||
start = i, j
|
||||
|
||||
|
||||
# Visit normally
|
||||
normal = None
|
||||
visited: list[list[int | None]] = list()
|
||||
for _ in range(height):
|
||||
visited.append([None] * width)
|
||||
visited[start[0]][start[1]] = 0
|
||||
stack: set[vec] = {start}
|
||||
s = 0
|
||||
while stack:
|
||||
s += 1
|
||||
nstack: set[vec] = set()
|
||||
for pos in stack:
|
||||
i, j = pos
|
||||
for d, direction in enumerate(directions):
|
||||
ii, jj = i + direction[0], j + direction[1]
|
||||
|
||||
previs = visited[ii][jj]
|
||||
if previs is not None and previs < s:
|
||||
continue
|
||||
visited[ii][jj] = s
|
||||
|
||||
cchar = lines[ii][jj]
|
||||
if cchar == "#":
|
||||
continue
|
||||
elif cchar == "E":
|
||||
if normal is None:
|
||||
normal = s
|
||||
nstack.add((ii, jj))
|
||||
stack = nstack
|
||||
assert normal
|
||||
|
||||
# Print
|
||||
for i in range(height):
|
||||
line = ""
|
||||
for j in range(width):
|
||||
char = lines[i][j]
|
||||
if visited[i][j] is not None:
|
||||
if char == "#":
|
||||
char = "@"
|
||||
else:
|
||||
char = "O"
|
||||
line += char
|
||||
print(line)
|
||||
print()
|
||||
|
||||
|
||||
# Find cheats
|
||||
saves: collections.Counter[int] = collections.Counter()
|
||||
for i in range(1, height - 1):
|
||||
if height > 100:
|
||||
print(103, i, "/", height)
|
||||
for j in range(1, width - 1):
|
||||
char = lines[i][j]
|
||||
if char == "#":
|
||||
continue
|
||||
ovis = visited[i][j]
|
||||
if ovis is None:
|
||||
continue
|
||||
if ovis >= normal:
|
||||
continue
|
||||
# for di in range(-skips, skips):
|
||||
# ii = i + di
|
||||
# G
|
||||
for ii in range(1, height - 1):
|
||||
for jj in range(1, width - 1):
|
||||
manh = abs(i - ii) + abs(j - jj)
|
||||
if manh > skips:
|
||||
continue
|
||||
cchar = lines[ii][jj]
|
||||
if cchar == "#":
|
||||
continue
|
||||
nvis = visited[ii][jj]
|
||||
if nvis is None:
|
||||
continue
|
||||
orem = normal - ovis
|
||||
nrem = abs(normal - nvis) + manh
|
||||
save = orem - nrem
|
||||
if save < minic:
|
||||
continue
|
||||
saves[save] += 1
|
||||
|
||||
|
||||
print(f"{normal=}")
|
||||
print(f"{dict(sorted(saves.items()))=}")
|
||||
if demo:
|
||||
print(f"{dict(sorted(canon.items()))=}")
|
||||
diff = canon.copy()
|
||||
diff.subtract(saves)
|
||||
print(f"{dict(sorted(diff.items()))=}")
|
||||
print(f"{(saves == canon)=}")
|
||||
print(f"{saves.total()=}")
|
||||
print(f"{canon.total()=}")
|
||||
difft = 0
|
||||
for v in diff.values():
|
||||
difft += abs(v)
|
||||
print(f"{difft=}")
|
||||
print(saves.total())
|
||||
# 1119834 too high
|
||||
# 982425 correct!
|
212
2024/20/two_correct.py
Normal file
212
2024/20/two_correct.py
Normal file
|
@ -0,0 +1,212 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import collections
|
||||
import colorsys
|
||||
import sys
|
||||
|
||||
import rich.console
|
||||
|
||||
import rich.text
|
||||
import rich.progress
|
||||
|
||||
console = rich.console.Console()
|
||||
|
||||
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])
|
||||
|
||||
# Adjust parameters for part/file
|
||||
part = int(sys.argv[2])
|
||||
assert part in (1, 2)
|
||||
|
||||
if input_file.startswith("input"):
|
||||
minic = 100
|
||||
elif input_file.startswith("reddit_part3"):
|
||||
minic = 30
|
||||
else:
|
||||
if part == 1:
|
||||
minic = 1
|
||||
else:
|
||||
minic = 50
|
||||
skips = 2 if part == 1 else 20
|
||||
canon: collections.Counter[int] = collections.Counter()
|
||||
demo = {}
|
||||
if input_file == "demo":
|
||||
if part == 1:
|
||||
demo = {2: 14, 4: 14, 6: 2, 8: 4, 10: 2} | (
|
||||
{12: 3, 20: 1, 36: 1, 38: 1, 40: 1, 64: 1}
|
||||
)
|
||||
elif part == 2:
|
||||
demo = {50: 32, 52: 31, 54: 29, 56: 39, 58: 25, 60: 23} | (
|
||||
{62: 20, 64: 19, 66: 12, 68: 14, 70: 12, 72: 22, 74: 4, 76: 3}
|
||||
)
|
||||
for k, v in demo.items():
|
||||
canon[k] = v
|
||||
|
||||
vec = tuple[int, int]
|
||||
directions = [
|
||||
(-1, 0), # ^ North
|
||||
(0, 1), # > East
|
||||
(1, 0), # v South
|
||||
(0, -1), # < West
|
||||
]
|
||||
|
||||
# Find start position
|
||||
for i, line in enumerate(lines):
|
||||
if "S" in line:
|
||||
j = line.index("S")
|
||||
start = i, j
|
||||
if "E" in line:
|
||||
j = line.index("E")
|
||||
stop = i, j
|
||||
|
||||
|
||||
# Visit forward
|
||||
normal = None
|
||||
forward: list[list[int | None]] = list()
|
||||
for _ in range(height):
|
||||
forward.append([None] * width)
|
||||
forward[start[0]][start[1]] = 0
|
||||
stack: set[vec] = {start}
|
||||
s = 0
|
||||
while stack:
|
||||
s += 1
|
||||
nstack: set[vec] = set()
|
||||
for pos in stack:
|
||||
i, j = pos
|
||||
for d, direction in enumerate(directions):
|
||||
ii, jj = i + direction[0], j + direction[1]
|
||||
|
||||
cchar = lines[ii][jj]
|
||||
if cchar == "#":
|
||||
continue
|
||||
|
||||
previs = forward[ii][jj]
|
||||
if previs is not None and previs < s:
|
||||
continue
|
||||
forward[ii][jj] = s
|
||||
|
||||
if cchar == "E":
|
||||
if normal is None:
|
||||
normal = s
|
||||
nstack.add((ii, jj))
|
||||
stack = nstack
|
||||
assert normal
|
||||
|
||||
# Visit backwards
|
||||
backward: list[list[int | None]] = list()
|
||||
for _ in range(height):
|
||||
backward.append([None] * width)
|
||||
backward[stop[0]][stop[1]] = 0
|
||||
stack = {stop}
|
||||
s = 0
|
||||
while stack:
|
||||
s += 1
|
||||
nstack = set()
|
||||
for pos in stack:
|
||||
i, j = pos
|
||||
for d, direction in enumerate(directions):
|
||||
ii, jj = i + direction[0], j + direction[1]
|
||||
|
||||
cchar = lines[ii][jj]
|
||||
if cchar == "#":
|
||||
continue
|
||||
|
||||
previs = backward[ii][jj]
|
||||
if previs is not None and previs < s:
|
||||
continue
|
||||
backward[ii][jj] = s
|
||||
|
||||
if cchar == "E":
|
||||
assert s == normal
|
||||
nstack.add((ii, jj))
|
||||
stack = nstack
|
||||
|
||||
# Print
|
||||
|
||||
|
||||
def perc2color(perc: float) -> str:
|
||||
rgb = colorsys.hsv_to_rgb(perc, 1.0, 1.0)
|
||||
r, g, b = tuple(round(c * 255) for c in rgb)
|
||||
return f"rgb({r},{g},{b})"
|
||||
|
||||
|
||||
text = rich.text.Text()
|
||||
for i in range(height):
|
||||
for j in range(width):
|
||||
fg = "white"
|
||||
bg = "black"
|
||||
char = lines[i][j]
|
||||
forw = forward[i][j]
|
||||
if char == ".":
|
||||
if forw is not None:
|
||||
fg = perc2color(forw / normal)
|
||||
char = str(forw % 10)
|
||||
bckw = backward[i][j]
|
||||
if bckw is not None:
|
||||
bg = perc2color(bckw / normal)
|
||||
if char == "#":
|
||||
char = "█"
|
||||
text.append(char, style=f"{fg} on {bg}")
|
||||
text.append("\n")
|
||||
console.print(text)
|
||||
|
||||
|
||||
# Find cheats
|
||||
saves: collections.Counter[int] = collections.Counter()
|
||||
for i in rich.progress.track(range(1, height - 1), description="Finding cheats"):
|
||||
for j in range(1, width - 1):
|
||||
char = lines[i][j]
|
||||
if char == "#":
|
||||
continue
|
||||
ovis = forward[i][j]
|
||||
if ovis is None:
|
||||
continue
|
||||
if ovis >= normal:
|
||||
continue
|
||||
min_i = max(1, i - skips)
|
||||
max_i = min(height - 1, i + skips)
|
||||
for ii in range(min_i, max_i + 1):
|
||||
rem = skips - abs(ii - i)
|
||||
min_j = max(1, j - rem)
|
||||
max_j = min(width - 1, j + rem)
|
||||
for jj in range(min_j, max_j + 1):
|
||||
manh = abs(i - ii) + abs(j - jj)
|
||||
if manh > skips:
|
||||
continue
|
||||
cchar = lines[ii][jj]
|
||||
if cchar == "#":
|
||||
continue
|
||||
nvis = backward[ii][jj]
|
||||
if nvis is None:
|
||||
continue
|
||||
orem = normal - ovis
|
||||
nrem = nvis + manh
|
||||
save = orem - nrem
|
||||
if save < minic:
|
||||
continue
|
||||
saves[save] += 1
|
||||
|
||||
log = console.log
|
||||
|
||||
log(f"{normal=}")
|
||||
log(f"{dict(sorted(saves.items()))=}")
|
||||
if demo:
|
||||
log(f"{dict(sorted(canon.items()))=}")
|
||||
diff = canon.copy()
|
||||
diff.subtract(saves)
|
||||
log(f"{dict(sorted(diff.items()))=}")
|
||||
log(f"{(saves == canon)=}")
|
||||
log(f"{saves.total()=}")
|
||||
log(f"{canon.total()=}")
|
||||
difft = 0
|
||||
for v in diff.values():
|
||||
difft += abs(v)
|
||||
log(f"{difft=}")
|
||||
print(saves.total())
|
||||
# 1119834 too high
|
||||
# 982425 correct!
|
172
2024/20/two_fast.py
Normal file
172
2024/20/two_fast.py
Normal file
|
@ -0,0 +1,172 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import collections
|
||||
import colorsys
|
||||
import sys
|
||||
import rich.console
|
||||
|
||||
console = rich.console.Console()
|
||||
|
||||
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])
|
||||
|
||||
# Adjust parameters for part/file
|
||||
part = int(sys.argv[2])
|
||||
assert part in (1, 2)
|
||||
|
||||
if input_file.startswith("input"):
|
||||
minic = 100
|
||||
elif input_file.startswith("reddit_part3"):
|
||||
minic = 30
|
||||
else:
|
||||
if part == 1:
|
||||
minic = 1
|
||||
else:
|
||||
minic = 50
|
||||
skips = 2 if part == 1 else 20
|
||||
canon: collections.Counter[int] = collections.Counter()
|
||||
demo = {}
|
||||
if input_file == "demo":
|
||||
if part == 1:
|
||||
demo = {2: 14, 4: 14, 6: 2, 8: 4, 10: 2} | (
|
||||
{12: 3, 20: 1, 36: 1, 38: 1, 40: 1, 64: 1}
|
||||
)
|
||||
elif part == 2:
|
||||
demo = {50: 32, 52: 31, 54: 29, 56: 39, 58: 25, 60: 23} | (
|
||||
{62: 20, 64: 19, 66: 12, 68: 14, 70: 12, 72: 22, 74: 4, 76: 3}
|
||||
)
|
||||
for k, v in demo.items():
|
||||
canon[k] = v
|
||||
|
||||
vec = tuple[int, int]
|
||||
directions = [
|
||||
(-1, 0), # ^ North
|
||||
(0, 1), # > East
|
||||
(1, 0), # v South
|
||||
(0, -1), # < West
|
||||
]
|
||||
|
||||
# Find start position
|
||||
for i, line in enumerate(lines):
|
||||
if "S" in line:
|
||||
j = line.index("S")
|
||||
start = i, j
|
||||
|
||||
|
||||
# Visit normally
|
||||
normal = None
|
||||
visited: list[list[int | None]] = list()
|
||||
for _ in range(height):
|
||||
visited.append([None] * width)
|
||||
visited[start[0]][start[1]] = 0
|
||||
stack: set[vec] = {start}
|
||||
s = 0
|
||||
while stack:
|
||||
s += 1
|
||||
nstack: set[vec] = set()
|
||||
for pos in stack:
|
||||
i, j = pos
|
||||
for d, direction in enumerate(directions):
|
||||
ii, jj = i + direction[0], j + direction[1]
|
||||
|
||||
cchar = lines[ii][jj]
|
||||
if cchar == "#":
|
||||
continue
|
||||
|
||||
previs = visited[ii][jj]
|
||||
if previs is not None and previs < s:
|
||||
continue
|
||||
visited[ii][jj] = s
|
||||
|
||||
if cchar == "E":
|
||||
if normal is None:
|
||||
normal = s
|
||||
nstack.add((ii, jj))
|
||||
stack = nstack
|
||||
assert normal
|
||||
|
||||
# Print
|
||||
for i in range(height):
|
||||
line = ""
|
||||
for j in range(width):
|
||||
char = lines[i][j]
|
||||
vis = visited[i][j]
|
||||
if (i, j) == (19, 1):
|
||||
char = "[bold red on black]@"
|
||||
elif (i, j) == (15, 1):
|
||||
char = "[bold red on black]a"
|
||||
elif vis is not None and char == ".":
|
||||
hue = vis / normal
|
||||
rgb = colorsys.hsv_to_rgb(hue, 1.0, 1.0)
|
||||
r, g, b = tuple(round(c * 255) for c in rgb)
|
||||
char = f"[on rgb({r},{g},{b})]{vis % 10}"
|
||||
elif char == "#":
|
||||
char = "[white]█"
|
||||
else:
|
||||
char = f"[bold green on black]{char}"
|
||||
line += char
|
||||
console.print(line)
|
||||
print()
|
||||
|
||||
|
||||
# Find cheats
|
||||
saves: collections.Counter[int] = collections.Counter()
|
||||
for i in range(1, height - 1):
|
||||
if height > 100:
|
||||
print(103, i, "/", height-2)
|
||||
for j in range(1, width - 1):
|
||||
char = lines[i][j]
|
||||
if char == "#":
|
||||
continue
|
||||
ovis = visited[i][j]
|
||||
if ovis is None:
|
||||
continue
|
||||
if ovis >= normal:
|
||||
continue
|
||||
min_i = max(1, i-skips)
|
||||
max_i = min(height-1, i+skips)
|
||||
for ii in range(min_i, max_i+1):
|
||||
rem = skips - abs(ii - i)
|
||||
min_j = max(1, j-rem)
|
||||
max_j = min(width-1, j+rem)
|
||||
for jj in range(min_j, max_j+1):
|
||||
manh = abs(i - ii) + abs(j - jj)
|
||||
if manh > skips:
|
||||
continue
|
||||
cchar = lines[ii][jj]
|
||||
if cchar == "#":
|
||||
continue
|
||||
nvis = visited[ii][jj]
|
||||
if nvis is None:
|
||||
continue
|
||||
orem = normal - ovis
|
||||
# Works if there's space after the E, but catches unrelated paths
|
||||
nrem = abs(normal - nvis) + manh
|
||||
save = orem - nrem
|
||||
if save < minic:
|
||||
continue
|
||||
saves[save] += 1
|
||||
|
||||
|
||||
print(f"{normal=}")
|
||||
print(f"{dict(sorted(saves.items()))=}")
|
||||
if demo:
|
||||
print(f"{dict(sorted(canon.items()))=}")
|
||||
diff = canon.copy()
|
||||
diff.subtract(saves)
|
||||
print(f"{dict(sorted(diff.items()))=}")
|
||||
print(f"{(saves == canon)=}")
|
||||
print(f"{saves.total()=}")
|
||||
print(f"{canon.total()=}")
|
||||
difft = 0
|
||||
for v in diff.values():
|
||||
difft += abs(v)
|
||||
print(f"{difft=}")
|
||||
print(saves.total())
|
||||
# 1119834 too high
|
||||
# 982425 correct!
|
Loading…
Add table
Add a link
Reference in a new issue