Initial commit

This commit is contained in:
Geoffrey Frogeye 2024-12-25 12:58:02 +01:00
commit 97a4330bc0
Signed by: geoffrey
GPG key ID: C72403E7F82E6AD8
110 changed files with 7006 additions and 0 deletions

2
2024/20/README.md Normal file
View file

@ -0,0 +1,2 @@
Reading comprehension got me on the second part,
a one byte change helped 🙃

4
2024/20/demog Normal file
View file

@ -0,0 +1,4 @@
#####
#S#E#
#...#
#####

32
2024/20/demog2 Normal file
View file

@ -0,0 +1,32 @@
#############################################################################################
#S#........................................................................................E#
#.#########################################################################################.#
#.#########################################################################################.#
#.#########################################################################################.#
#.#########################################################################################.#
#.#########################################################################################.#
#.#########################################################################################.#
#.#########################################################################################.#
#.#########################################################################################.#
#.#########################################################################################.#
#.#########################################################################################.#
#.#########################################################################################.#
#.#########################################################################################.#
#.#########################################################################################.#
#.#########################################################################################.#
#.#########################################################################################.#
#.#########################################################################################.#
#.#########################################################################################.#
#.#########################################################################################.#
#.#########################################################################################.#
#.#########################################################################################.#
#.#########################################################################################.#
#.#########################################################################################.#
#.#########################################################################################.#
#.#########################################################################################.#
#.#########################################################################################.#
#.#########################################################################################.#
#.#########################################################################################.#
#.#########################################################################################.#
#...........................................................................................#
#############################################################################################

5
2024/20/demog3 Normal file
View file

@ -0,0 +1,5 @@
######
#...E#
#S####
#....#
######

129
2024/20/one.py Normal file
View 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
View file

@ -0,0 +1,41 @@
#########################################
#...#.............#.....#.....#.....#...#
###.#.###.#########.###.###.#####.###.#.#
#...#...#.#.#.....#...#...#.#.........#.#
#..##.###.#.#####.#####.#.#.#.#####.#.#.#
#.......#.....#.#.....#.#...#...#...#.#.#
#.###########.#.#.####.####.#.###########
#.#.#...#...#.....#.................#...#
#.#.#.#.#.#.###.#.#.###.#########.#####.#
#.....#...#.....#...#.........#...#.#.#.#
#####.#####.#####.#.#.#.#.#######.#.#.#.#
#.....#.........#.#.#...#...#...#.#...#.#
#.#########.#######.#####.#.##..###.###.#
#...#.......#.....#.#...#.#...#.....#...#
#.###.###########.#.###.#.#.###.#######.#
#.#.#.............#.....#.#...#...#.....#
###.#.#####.#####.#.###.#.#####.#####.###
#...#.#.........#.#...#...#...#.#.....#.#
###.###.#.#########.#####.###.#.#.#.#.#.#
#S#.#...#.#.....#.....#.........#.#.#..E#
#.#.#.#########.#.#########.#.###.#####.#
#.....#.........#...#.#...#.#.....#...#.#
###.#####..##.#.#####.#.###.#####.###.###
#.#.#...#.#.#.#.#...#...#...#.........#.#
#.#.###.###.#.#.#.#####.####.##.#.#####.#
#.#.#.#.#.#...#.........#.#...#.#.#...#.#
#.#.#.#.#.#####.###.#.#.#.###.#.###.###.#
#...#.......#...#...#.#.#.........#.#...#
#######.#####.#####.###.#.#.#####.#.###.#
#.............#.....#.#.#.#.....#.......#
###############.#####.#.#########.#.#.###
#.....#...#.#.........#.#...#...#.#.#.#.#
#.#.#.#.#.#.###.#########.###.###.#####.#
#.#.#.#.#...........#.#.............#...#
###.#.#.###.#######.#.#.#.###.###.#.#.###
#...#...#...#.#...#.#...#...#.#.#.#.#...#
###.#.#######.#.#.#.###.#####.#..##.#.###
#.#.#...#.....#.#.#.......#.#.#...#.....#
#.#.#####.###.#.#.#.#.#####.#####.###.#.#
#.....#.....#.......#.............#...#.#
#########################################

41
2024/20/reddit_part3g Normal file
View file

@ -0,0 +1,41 @@
#########################################
#...#.............#.....#.....#.....#...#
###.#.###.#########.###.###.#####.###.#.#
#...#...#.#.#.....#...#...#.#.........#.#
#..##.###.#.#####.#####.#.#.#.#####.#.#.#
#.......#.....#.#.....#.#...#...#...#.#.#
#.###########.#.#.####.####.#.###########
#.#.#...#...#.....#.................#...#
#.#.#.#.#.#.###.#.#.###.#########.#####.#
#.....#...#.....#...#.........#...#.#.#.#
#####.#####.#####.#.#.#.#.#######.#.#.#.#
#.....#.........#.#.#...#...#...#.#...#.#
#.#########.#######.#####.#.##..###.###.#
#...#.......#.....#.#...#.#...#.....#...#
#.###.###########.#.###.#.#.###.#######.#
#.#.#.............#.....#.#...#...#.....#
###.#.#####.#####.#.###.#.#####.#####.###
#...#.#.........#.#...#...#...#.#.....#.#
###.###.#.#########.#####.###.#.#.#.#.#.#
#S#.#...#.#.....#.....#.........#.#.#..E#
#.#.#.#########.#.#########.#.###.#####.#
#.....#.........#...#.#...#.#.....#...#.#
###.#####..##.#.#####.#.###.#####.###.###
#.#.#...#.#.#.#.#...#...#...#.........#.#
#.#.###.###.#.#.#.#####.####.##.#.#####.#
#.#.#.#.#.#...#.........#.#...#.#.#...#.#
#.#.#.#.#.#####.###.#.#.#.###.#.###.###.#
#...#.......#...#...#.#.#.........#.#...#
#######.#####.#####.###.#.#.#####.#.###.#
#.............#.....#.#.#.#.....#.......#
#####################.#.#########.#.#.###
#.....#...#.#.........#.#...#...#.#.#.#.#
#.#.#.#.#.#.###.#########.###.###.#####.#
#.#.#.#.#...........#.#.............#...#
###.#.#.###.#######.#.#.#.###.###.#.#.###
#...#...#...#.#...#.#...#...#.#.#.#.#...#
###.#.#######.#.#.#.###.#####.#..##.#.###
#.#.#...#.....#.#.#.......#.#.#...#.....#
#.#.#####.###.#.#.#.#.#####.#####.###.#.#
#.....#.....#.......#.............#...#.#
#########################################

153
2024/20/two.py Normal file
View 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
View 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
View 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!