2020 day 19 and day 20 part 1

This commit is contained in:
felixm 2024-09-30 20:04:33 -04:00
parent 36f20610ae
commit 97b05614ee
4 changed files with 305 additions and 1 deletions

62
2020/d19.py Normal file
View File

@ -0,0 +1,62 @@
from lib import get_data
data = get_data(__file__)
rules = {}
msgs = []
for line in data.splitlines():
if len(line.strip()) == 0:
continue
if ":" in line:
id, rule = line.split(":")
id = int(id)
branches = [[]]
for part in rule.split():
if part.startswith('"') and part.endswith('"'):
branches = part[1]
elif part == "|":
assert type(branches) is list
branches.append([])
else:
assert type(branches) is list
branches[-1].append(int(part))
rules[id] = branches
else:
msgs.append(line.strip())
def matches(xs, rule):
if xs == "" and rule == []:
return True
elif xs == "" or rule == []:
return False
current = rules[rule[0]]
if current == xs[0]:
return matches(xs[1:], rule[1:])
elif type(current) is str:
return False
elif len(current) >= 1:
for ys in current:
if matches(xs, ys + rule[1:]):
return True
return False
t = 0
for m in msgs:
if matches(m, rules[0][0]):
t += 1
print(t)
rules[8] = [[42], [42, 8]]
rules[11] = [[42, 31], [42, 11, 31]]
t = 0
for m in msgs:
if matches(m, rules[0][0]):
t += 1
print(t)

238
2020/d20.py Normal file
View File

@ -0,0 +1,238 @@
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]
def bottom(rows):
return rows[-1]
def left(rows):
return [row[0] for row in rows]
def right(rows):
return [row[-1] for row in rows]
def fliph(rows):
return [row[::-1] for row in rows]
def flipv(rows):
return rows[::-1]
def rot90(rows):
return [row for row in zip(*rows[::-1])]
def rot180(rows):
return rot90(rot90(rows))
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
LEFT = 3
def all(rows) -> list:
orientations = [
rows,
rot90(rows),
rot180(rows),
rot270(rows),
fliph(rows),
flipv(rows),
rot90(fliph(rows)),
rot90(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:])))
rights = defaultdict(list)
bottoms = defaultdict(list)
for id, variants in tiles:
for variant in variants:
rights[variant[LEFT]].append((id, variant))
bottoms[variant[TOP]].append((id, variant))
num_tiles = len(tiles)
rows = isqrt(len(tiles))
def dfs(id_set, id_list, tiles_used):
if len(tiles_used) == num_tiles:
return id_list
i = len(tiles_used)
id_variants = None
if i < rows: # first row
id_variants = rights[tiles_used[i - 1][RIGHT]]
elif i % rows == 0: # first tile in row
id_variants = bottoms[tiles_used[i - rows][BOTTOM]]
else:
id_variants = set(bottoms[tiles_used[i - rows][BOTTOM]])
id_variants &= set(rights[tiles_used[i - 1][RIGHT]])
id_variants = list(id_variants)
assert id_variants is not None
for id, variant in id_variants:
if id in id_set:
continue
id_set.add(id)
id_list.append(id)
tiles_used.append(variant)
r = dfs(id_set, id_list, tiles_used)
if r is not False:
return r
tiles_used.pop()
id_set.remove(id)
id_list.pop()
return False
for id, tile_variants in tiles:
for tile in tile_variants:
r = dfs(set([id]), [id], [tile])
if type(r) is list:
print(r[0] * r[-1] * r[rows - 1] * r[-rows])
exit(0)
else:
print("no result")

View File

@ -157,7 +157,8 @@ Solutions and utility script for Advent of Code challenges in Python.
- Day 16: 33:00 (Not too unhappy really.)
- Day 17: 10:00 (40th)
- Day 18: 80:00 (I am struggling with stuff where parsing is involved)
- Day 19:
- Day 19: 78:00 (Should have been faster)
- Day 20:
## AoC 2022

3
lib.py
View File

@ -202,6 +202,9 @@ def str_to_ints(line: str) -> list[int]:
return list(map(int, r.findall(line)))
ints = str_to_ints
def str_to_lines_no_empty(text: str) -> list[str]:
return list(filter(lambda l: l.strip() != "", text.splitlines()))