2020 day 20-22
This commit is contained in:
201
2020/d20.py
201
2020/d20.py
@@ -2,143 +2,36 @@ from collections import defaultdict
|
|||||||
from lib import get_data, ints
|
from lib import get_data, ints
|
||||||
from math import isqrt
|
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__)
|
data = get_data(__file__)
|
||||||
|
|
||||||
|
|
||||||
def top(rows):
|
def top(rows):
|
||||||
return rows[0]
|
return tuple(rows[0])
|
||||||
|
|
||||||
|
|
||||||
def bottom(rows):
|
def bottom(rows):
|
||||||
return rows[-1]
|
return tuple(rows[-1])
|
||||||
|
|
||||||
|
|
||||||
def left(rows):
|
def left(rows):
|
||||||
return [row[0] for row in rows]
|
return tuple(tuple(row[0] for row in rows))
|
||||||
|
|
||||||
|
|
||||||
def right(rows):
|
def right(rows):
|
||||||
return [row[-1] for row in rows]
|
return tuple(tuple(row[-1] for row in rows))
|
||||||
|
|
||||||
|
|
||||||
def fliph(rows):
|
def fliph(rows):
|
||||||
return [row[::-1] for row in rows]
|
return tuple(tuple(row[::-1] for row in rows))
|
||||||
|
|
||||||
|
|
||||||
def flipv(rows):
|
def flipv(rows):
|
||||||
return rows[::-1]
|
return tuple(rows[::-1])
|
||||||
|
|
||||||
|
|
||||||
def rot90(rows):
|
def rot90(rows):
|
||||||
return [row for row in zip(*rows[::-1])]
|
return tuple(tuple(row) for row in zip(*rows[::-1]))
|
||||||
|
|
||||||
|
|
||||||
def rot180(rows):
|
def rot180(rows):
|
||||||
@@ -149,10 +42,6 @@ def rot270(rows):
|
|||||||
return rot90(rot90(rot90(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
|
TOP = 0
|
||||||
RIGHT = 1
|
RIGHT = 1
|
||||||
BOTTOM = 2
|
BOTTOM = 2
|
||||||
@@ -160,7 +49,7 @@ LEFT = 3
|
|||||||
|
|
||||||
|
|
||||||
def all(rows) -> list:
|
def all(rows) -> list:
|
||||||
orientations = [
|
return [
|
||||||
rows,
|
rows,
|
||||||
rot90(rows),
|
rot90(rows),
|
||||||
rot180(rows),
|
rot180(rows),
|
||||||
@@ -169,19 +58,19 @@ def all(rows) -> list:
|
|||||||
flipv(rows),
|
flipv(rows),
|
||||||
rot90(fliph(rows)),
|
rot90(fliph(rows)),
|
||||||
rot90(flipv(rows)),
|
rot90(flipv(rows)),
|
||||||
rot180(fliph(rows)),
|
# rot180(fliph(rows)),
|
||||||
rot180(flipv(rows)),
|
# rot180(flipv(rows)),
|
||||||
rot270(fliph(rows)),
|
# rot270(fliph(rows)),
|
||||||
rot270(flipv(rows)),
|
# rot270(flipv(rows)),
|
||||||
]
|
]
|
||||||
return [get_borders(orientation) for orientation in orientations]
|
|
||||||
|
|
||||||
|
|
||||||
tiles = []
|
tiles = []
|
||||||
for p in data.strip().split("\n\n"):
|
for p in data.strip().split("\n\n"):
|
||||||
lines = p.splitlines()
|
lines = p.splitlines()
|
||||||
(id,) = ints(lines[0])
|
(id,) = ints(lines[0])
|
||||||
tiles.append((id, all(lines[1:])))
|
rowst = tuple(map(tuple, lines[1:]))
|
||||||
|
tiles.append((id, all(rowst)))
|
||||||
|
|
||||||
|
|
||||||
rights = defaultdict(list)
|
rights = defaultdict(list)
|
||||||
@@ -189,8 +78,8 @@ bottoms = defaultdict(list)
|
|||||||
|
|
||||||
for id, variants in tiles:
|
for id, variants in tiles:
|
||||||
for variant in variants:
|
for variant in variants:
|
||||||
rights[variant[LEFT]].append((id, variant))
|
rights[left(variant)].append((id, variant))
|
||||||
bottoms[variant[TOP]].append((id, variant))
|
bottoms[top(variant)].append((id, variant))
|
||||||
|
|
||||||
num_tiles = len(tiles)
|
num_tiles = len(tiles)
|
||||||
rows = isqrt(len(tiles))
|
rows = isqrt(len(tiles))
|
||||||
@@ -198,17 +87,17 @@ rows = isqrt(len(tiles))
|
|||||||
|
|
||||||
def dfs(id_set, id_list, tiles_used):
|
def dfs(id_set, id_list, tiles_used):
|
||||||
if len(tiles_used) == num_tiles:
|
if len(tiles_used) == num_tiles:
|
||||||
return id_list
|
return id_list, tiles_used
|
||||||
|
|
||||||
i = len(tiles_used)
|
i = len(tiles_used)
|
||||||
id_variants = None
|
id_variants = None
|
||||||
if i < rows: # first row
|
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
|
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:
|
else:
|
||||||
id_variants = set(bottoms[tiles_used[i - rows][BOTTOM]])
|
id_variants = set(bottoms[bottom(tiles_used[i - rows])])
|
||||||
id_variants &= set(rights[tiles_used[i - 1][RIGHT]])
|
id_variants &= set(rights[right(tiles_used[i - 1])])
|
||||||
id_variants = list(id_variants)
|
id_variants = list(id_variants)
|
||||||
|
|
||||||
assert id_variants is not None
|
assert id_variants is not None
|
||||||
@@ -225,14 +114,56 @@ def dfs(id_set, id_list, tiles_used):
|
|||||||
tiles_used.pop()
|
tiles_used.pop()
|
||||||
id_set.remove(id)
|
id_set.remove(id)
|
||||||
id_list.pop()
|
id_list.pop()
|
||||||
return False
|
return False, None
|
||||||
|
|
||||||
|
|
||||||
|
tiles_used = None
|
||||||
for id, tile_variants in tiles:
|
for id, tile_variants in tiles:
|
||||||
for tile in tile_variants:
|
for tile in tile_variants:
|
||||||
r = dfs(set([id]), [id], [tile])
|
r, tiles_used = dfs(set([id]), [id], [tile])
|
||||||
if type(r) is list:
|
if type(r) is list:
|
||||||
print(r[0] * r[-1] * r[rows - 1] * r[-rows])
|
print(r[0] * r[-1] * r[rows - 1] * r[-rows])
|
||||||
exit(0)
|
break
|
||||||
|
if tiles_used is not None:
|
||||||
|
break
|
||||||
else:
|
else:
|
||||||
print("no result")
|
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
50
2020/d21.py
Normal 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
86
2020/d22.py
Normal 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)
|
||||||
@@ -158,7 +158,11 @@ Solutions and utility script for Advent of Code challenges in Python.
|
|||||||
- Day 17: 10:00 (40th)
|
- Day 17: 10:00 (40th)
|
||||||
- Day 18: 80:00 (I am struggling with stuff where parsing is involved)
|
- Day 18: 80:00 (I am struggling with stuff where parsing is involved)
|
||||||
- Day 19: 78:00 (Should have been faster)
|
- 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
|
## AoC 2022
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user