2020 day 20-22

This commit is contained in:
felixm 2024-10-04 18:38:32 -04:00
parent 97b05614ee
commit 6475681cfb
4 changed files with 207 additions and 136 deletions

View File

@ -2,143 +2,36 @@ from collections import defaultdict
from lib import get_data, ints
from math import isqrt
data = """Tile 2311:
..##.#..#.
##..#.....
#...##..#.
####.#...#
##.##.###.
##...#.###
.#.#.#..##
..#....#..
###...#.#.
..###..###
Tile 1951:
#.##...##.
#.####...#
.....#..##
#...######
.##.#....#
.###.#####
###.##.##.
.###....#.
..#.#..#.#
#...##.#..
Tile 1171:
####...##.
#..##.#..#
##.#..#.#.
.###.####.
..###.####
.##....##.
.#...####.
#.##.####.
####..#...
.....##...
Tile 1427:
###.##.#..
.#..#.##..
.#.##.#..#
#.#.#.##.#
....#...##
...##..##.
...#.#####
.#.####.#.
..#..###.#
..##.#..#.
Tile 1489:
##.#.#....
..##...#..
.##..##...
..#...#...
#####...#.
#..#.#.#.#
...#.#.#..
##.#...##.
..##.##.##
###.##.#..
Tile 2473:
#....####.
#..#.##...
#.##..#...
######.#.#
.#...#.#.#
.#########
.###.#..#.
########.#
##...##.#.
..###.#.#.
Tile 2971:
..#.#....#
#...###...
#.#.###...
##.##..#..
.#####..##
.#..####.#
#..#.#..#.
..####.###
..#.#.###.
...#.#.#.#
Tile 2729:
...#.#.#.#
####.#....
..#.#.....
....#..#.#
.##..##.#.
.#.####...
####.#.#..
##.####...
##..#.##..
#.##...##.
Tile 3079:
#.#.#####.
.#..######
..#.......
######....
####.#..#.
.#...#.##.
#.#####.##
..#.###...
..#.......
..#.###..."""
data = get_data(__file__)
def top(rows):
return rows[0]
return tuple(rows[0])
def bottom(rows):
return rows[-1]
return tuple(rows[-1])
def left(rows):
return [row[0] for row in rows]
return tuple(tuple(row[0] for row in rows))
def right(rows):
return [row[-1] for row in rows]
return tuple(tuple(row[-1] for row in rows))
def fliph(rows):
return [row[::-1] for row in rows]
return tuple(tuple(row[::-1] for row in rows))
def flipv(rows):
return rows[::-1]
return tuple(rows[::-1])
def rot90(rows):
return [row for row in zip(*rows[::-1])]
return tuple(tuple(row) for row in zip(*rows[::-1]))
def rot180(rows):
@ -149,10 +42,6 @@ def rot270(rows):
return rot90(rot90(rot90(rows)))
def get_borders(rows):
return tuple(top(rows)), tuple(right(rows)), tuple(bottom(rows)), tuple(left(rows))
TOP = 0
RIGHT = 1
BOTTOM = 2
@ -160,7 +49,7 @@ LEFT = 3
def all(rows) -> list:
orientations = [
return [
rows,
rot90(rows),
rot180(rows),
@ -169,19 +58,19 @@ def all(rows) -> list:
flipv(rows),
rot90(fliph(rows)),
rot90(flipv(rows)),
rot180(fliph(rows)),
rot180(flipv(rows)),
rot270(fliph(rows)),
rot270(flipv(rows)),
# rot180(fliph(rows)),
# rot180(flipv(rows)),
# rot270(fliph(rows)),
# rot270(flipv(rows)),
]
return [get_borders(orientation) for orientation in orientations]
tiles = []
for p in data.strip().split("\n\n"):
lines = p.splitlines()
(id,) = ints(lines[0])
tiles.append((id, all(lines[1:])))
rowst = tuple(map(tuple, lines[1:]))
tiles.append((id, all(rowst)))
rights = defaultdict(list)
@ -189,8 +78,8 @@ bottoms = defaultdict(list)
for id, variants in tiles:
for variant in variants:
rights[variant[LEFT]].append((id, variant))
bottoms[variant[TOP]].append((id, variant))
rights[left(variant)].append((id, variant))
bottoms[top(variant)].append((id, variant))
num_tiles = len(tiles)
rows = isqrt(len(tiles))
@ -198,17 +87,17 @@ rows = isqrt(len(tiles))
def dfs(id_set, id_list, tiles_used):
if len(tiles_used) == num_tiles:
return id_list
return id_list, tiles_used
i = len(tiles_used)
id_variants = None
if i < rows: # first row
id_variants = rights[tiles_used[i - 1][RIGHT]]
id_variants = rights[right(tiles_used[i - 1])]
elif i % rows == 0: # first tile in row
id_variants = bottoms[tiles_used[i - rows][BOTTOM]]
id_variants = bottoms[bottom(tiles_used[i - rows])]
else:
id_variants = set(bottoms[tiles_used[i - rows][BOTTOM]])
id_variants &= set(rights[tiles_used[i - 1][RIGHT]])
id_variants = set(bottoms[bottom(tiles_used[i - rows])])
id_variants &= set(rights[right(tiles_used[i - 1])])
id_variants = list(id_variants)
assert id_variants is not None
@ -225,14 +114,56 @@ def dfs(id_set, id_list, tiles_used):
tiles_used.pop()
id_set.remove(id)
id_list.pop()
return False
return False, None
tiles_used = None
for id, tile_variants in tiles:
for tile in tile_variants:
r = dfs(set([id]), [id], [tile])
r, tiles_used = dfs(set([id]), [id], [tile])
if type(r) is list:
print(r[0] * r[-1] * r[rows - 1] * r[-rows])
exit(0)
break
if tiles_used is not None:
break
else:
print("no result")
exit(0)
tiles_used = [[tile[x][1:-1] for x in range(1, len(tile) - 1)] for tile in tiles_used]
merged_tiles = []
for i in range(0, rows * rows, rows):
for row in range(len(tiles_used[0])):
merged_row = []
for j in range(rows):
merged_row.extend(tiles_used[i + j][row])
merged_tiles.append(merged_row)
seemonster = """ #
# ## ## ###
# # # # # # """
offsets: list[tuple[int, int]] = []
for row, line in enumerate(seemonster.splitlines()):
for col, c in enumerate(line):
if c == "#":
offsets.append((row, col))
total_hashes = sum([row.count("#") for row in merged_tiles])
seemonster_hashes = len(offsets)
max_seemonster_count = 0
for field in all(merged_tiles):
seemonster_count = 0
for ri in range(len(field) - 2):
for ci in range(len(field[0]) - 19):
for ro, co in offsets:
if field[ri + ro][ci + co] != "#":
break
else:
seemonster_count += 1
max_seemonster_count = max(max_seemonster_count, seemonster_count)
print(total_hashes - max_seemonster_count * seemonster_hashes)

50
2020/d21.py Normal file
View File

@ -0,0 +1,50 @@
from collections import defaultdict
from lib import get_data
data = get_data(__file__)
algs_to_ings = defaultdict(set)
ings_counts = defaultdict(int)
for line in data.splitlines():
a, b = line.split(" (contains ")
ings = a.split(" ")
algs = b[:-1].split(", ")
for ing in ings:
ings_counts[ing] += 1
for a in algs:
if a not in algs_to_ings:
algs_to_ings[a] = set(ings)
else:
algs_to_ings[a] &= set(ings)
for ings in algs_to_ings.values():
for ing in ings:
if ing in ings_counts:
del ings_counts[ing]
t = sum(ings_counts.values())
print(t)
algs_to_ings = {a: list(ing) for a, ing in algs_to_ings.items()}
handled = set()
while True:
to_remove = None
for alg, ings in algs_to_ings.items():
if len(ings) == 1 and ings[0] not in handled:
to_remove = ings[0]
break
else:
break
assert to_remove is not None
handled.add(to_remove)
for ings in algs_to_ings.values():
if len(ings) > 1 and to_remove in ings:
ings.remove(to_remove)
xs = sorted([(a, i[0]) for a, i in algs_to_ings.items()])
xs = ",".join([x[1] for x in xs])
print(xs)

86
2020/d22.py Normal file
View File

@ -0,0 +1,86 @@
from collections import deque, defaultdict
from lib import get_data, ints
data = get_data(__file__)
a, b = data.strip().split("\n\n")
a = deque(ints(a)[1:])
b = deque(ints(b)[1:])
while a and b:
x, y = a.popleft(), b.popleft()
if x > y:
a.append(x)
a.append(y)
elif y > x:
b.append(y)
b.append(x)
else:
assert False
for p in [a, b]:
s = 0
for i, c in enumerate(reversed(p)):
s += (i + 1) * c
if s > 0:
print(s)
CACHE = {}
def play(a, b):
if len(a) == 0 or len(b) == 0:
return a, b
s = (tuple(a), tuple(b))
if s in CACHE:
return CACHE[s]
seen = set()
while a and b:
s = (tuple(a), tuple(b))
if s in seen:
return True, False
seen.add(s)
x, y = a.popleft(), b.popleft()
if x <= len(a) and y <= len(b):
ar, br = play(deque(list(a)[:x]), deque(list(b)[:y]))
if ar:
a.append(x)
a.append(y)
elif br:
b.append(y)
b.append(x)
else:
assert False
else:
if x > y:
a.append(x)
a.append(y)
elif y > x:
b.append(y)
b.append(x)
else:
assert False
s = (tuple(a), tuple(b))
if s not in CACHE:
CACHE[s] = (a, b)
return a, b
a, b = data.strip().split("\n\n")
a = deque(ints(a)[1:])
b = deque(ints(b)[1:])
a, b = play(a, b)
for p in [a, b]:
s = 0
for i, c in enumerate(reversed(p)):
s += (i + 1) * c
if s > 0:
print(s)

View File

@ -158,7 +158,11 @@ Solutions and utility script for Advent of Code challenges in Python.
- Day 17: 10:00 (40th)
- Day 18: 80:00 (I am struggling with stuff where parsing is involved)
- Day 19: 78:00 (Should have been faster)
- Day 20:
- Day 20: 95:00 (Lot's of code)
- Day 21: 23:02 (Simply to slow)
- Day 22: 45:49 (Simple and too slow)
- Day 23:
- Day 24:
## AoC 2022