Added days 18-22, 24
parent
196399df32
commit
75cfd22369
|
@ -0,0 +1,131 @@
|
||||||
|
from functools import total_ordering
|
||||||
|
from collections import defaultdict
|
||||||
|
from itertools import combinations
|
||||||
|
|
||||||
|
@total_ordering
|
||||||
|
class MaxBound:
|
||||||
|
def __gt__(self, other):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def __ge__(self, other):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __le__(self, other):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "MaxBound"
|
||||||
|
|
||||||
|
|
||||||
|
def move_func(maze, i):
|
||||||
|
w = maze.index('\n')+1
|
||||||
|
possible = i+1, i-1, i+w, i-w
|
||||||
|
return [j for j in possible if j < len(maze) and maze[j] not in ('\n', '#')]
|
||||||
|
|
||||||
|
def build_branch(maze, i, w=0, visited=None, edges=None):
|
||||||
|
if visited == None:
|
||||||
|
visited = defaultdict(MaxBound)
|
||||||
|
edges = defaultdict(MaxBound)
|
||||||
|
if visited[i] <= w:
|
||||||
|
return
|
||||||
|
visited[i] = w
|
||||||
|
node = maze[i]
|
||||||
|
if node != '.' and w > 0:
|
||||||
|
edges[node] = min(edges[node], w)
|
||||||
|
return
|
||||||
|
for m in move_func(maze, i):
|
||||||
|
build_branch(maze, m, w+1, visited, edges)
|
||||||
|
return edges
|
||||||
|
|
||||||
|
def build_graph(maze):
|
||||||
|
keys = [c for c in maze if c not in ('#', '.', '\n')]
|
||||||
|
graph = dict()
|
||||||
|
for key in keys:
|
||||||
|
graph[key] = build_branch(maze, maze.index(key))
|
||||||
|
return graph
|
||||||
|
|
||||||
|
def print_graph(graph):
|
||||||
|
for node in graph:
|
||||||
|
print(node, end='')
|
||||||
|
for n, w in graph[node].items():
|
||||||
|
print("--{}--> {}".format(w, n))
|
||||||
|
print(' '*len(node), end='')
|
||||||
|
print()
|
||||||
|
|
||||||
|
def unlock(graph, key):
|
||||||
|
new = dict()
|
||||||
|
if key not in graph:
|
||||||
|
return graph
|
||||||
|
for a in graph:
|
||||||
|
if a == key:
|
||||||
|
continue
|
||||||
|
new[a] = defaultdict(MaxBound)
|
||||||
|
for b, w in graph[a].items():
|
||||||
|
if b == key:
|
||||||
|
continue
|
||||||
|
new[a][b] = w
|
||||||
|
for a, b in combinations(graph[key].keys(), 2):
|
||||||
|
w = graph[key][a] + graph[key][b]
|
||||||
|
new[a][b] = new[b][a] = min(new[a][b], w)
|
||||||
|
return new
|
||||||
|
|
||||||
|
def is_key(c):
|
||||||
|
return c == c.lower()
|
||||||
|
|
||||||
|
def doorof(key):
|
||||||
|
return key.upper() if key.isalpha() else None
|
||||||
|
|
||||||
|
def heu_sort(edges):
|
||||||
|
return sorted(edges.items(), key=lambda x: x[1])
|
||||||
|
|
||||||
|
def search(graph, nodes, w=0, best=MaxBound(), d=0, mem=None, key=''):
|
||||||
|
if mem == None:
|
||||||
|
mem = defaultdict(MaxBound)
|
||||||
|
|
||||||
|
id = "".join(sorted(nodes)) + ''.join(sorted(n for n in graph if n not in nodes and is_key(n)))
|
||||||
|
if w >= best or w >= mem[id]:
|
||||||
|
return best
|
||||||
|
|
||||||
|
if len(mem) < 10**5:
|
||||||
|
mem[id] = w
|
||||||
|
|
||||||
|
graph = unlock(graph, doorof(key))
|
||||||
|
|
||||||
|
for i, node in enumerate(nodes):
|
||||||
|
bridged = unlock(graph, node)
|
||||||
|
|
||||||
|
for n, w2 in heu_sort(graph[node]):
|
||||||
|
if not is_key(n):
|
||||||
|
continue
|
||||||
|
r = search(bridged, nodes[:i] + [n] + nodes[i+1:], w+w2, best, d+1, mem, n)
|
||||||
|
best = min(best, r)
|
||||||
|
if len(graph) == len(nodes) and w < best:
|
||||||
|
best = w
|
||||||
|
return best
|
||||||
|
|
||||||
|
def init_maze(maze):
|
||||||
|
maze = list(maze)
|
||||||
|
for i in range(maze.count('@')):
|
||||||
|
maze[maze.index('@')] = str(i)
|
||||||
|
return ''.join(maze), map(str, range(i+1))
|
||||||
|
|
||||||
|
def prepoc(puzzle_input):
|
||||||
|
return puzzle_input
|
||||||
|
|
||||||
|
def partI(maze):
|
||||||
|
graph = build_graph(maze)
|
||||||
|
return search(graph, ['@'])
|
||||||
|
|
||||||
|
def partII(maze):
|
||||||
|
maze = list(maze)
|
||||||
|
i = maze.index('@')
|
||||||
|
w = maze.index('\n')
|
||||||
|
maze[i-1:i+2] = '###'
|
||||||
|
maze[i-w-2:i-w+1] = maze[i+w:i+w+3] = '@#@'
|
||||||
|
maze, nodes = init_maze(maze)
|
||||||
|
graph = build_graph(maze)
|
||||||
|
return search(graph, list(nodes))
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
from intcode import preproc
|
||||||
|
|
||||||
|
def partI(exe):
|
||||||
|
mp = '\n'.join(''.join(str(next(exe(x, y))) for x in range(50))
|
||||||
|
for y in range(50))
|
||||||
|
return mp.count('1')
|
||||||
|
|
||||||
|
def partII(exe):
|
||||||
|
def is_beam(x, y):
|
||||||
|
return next(exe(x, y)) == 1
|
||||||
|
|
||||||
|
xs = [(0, 0)]
|
||||||
|
y = 100
|
||||||
|
width = 0
|
||||||
|
while len(xs) < 100 or xs[0][1] - xs[-1][0] < 99:
|
||||||
|
x = xs[-1][0]
|
||||||
|
while not is_beam(x, y):
|
||||||
|
x += 1
|
||||||
|
start = x
|
||||||
|
x += width
|
||||||
|
while is_beam(x, y):
|
||||||
|
width += 1
|
||||||
|
x += 1
|
||||||
|
width -= 1
|
||||||
|
end = x-1
|
||||||
|
xs.append((start, end))
|
||||||
|
if len(xs) > 100:
|
||||||
|
xs = xs[-100:]
|
||||||
|
y += 1
|
||||||
|
|
||||||
|
X = start
|
||||||
|
Y = y - 100
|
||||||
|
return 10**4 * X + Y
|
||||||
|
|
|
@ -0,0 +1,264 @@
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
|
||||||
|
WALL = '#'
|
||||||
|
PATH = '.'
|
||||||
|
|
||||||
|
A = ("out", "AA")
|
||||||
|
Z = ("out", "ZZ")
|
||||||
|
|
||||||
|
|
||||||
|
class WeightedGraph(dict):
|
||||||
|
def edges_of(self, a):
|
||||||
|
return self[a]
|
||||||
|
|
||||||
|
def add_edge(self, a, b, w):
|
||||||
|
self[a].append((b, w))
|
||||||
|
self[b].append((a, w))
|
||||||
|
|
||||||
|
def add_node(self, a):
|
||||||
|
if a not in self:
|
||||||
|
self[a] = []
|
||||||
|
|
||||||
|
def rm_loops(self):
|
||||||
|
for a in self.keys():
|
||||||
|
for i, (b, w) in enumerate(self[a]):
|
||||||
|
if a == b:
|
||||||
|
del self[a][i]
|
||||||
|
|
||||||
|
def min_path(self, a, b):
|
||||||
|
weights = dict()
|
||||||
|
visited = set()
|
||||||
|
|
||||||
|
node, w = a, 0
|
||||||
|
while node != b:
|
||||||
|
for c, edge_w in self.edges_of(node):
|
||||||
|
if c in visited:
|
||||||
|
continue
|
||||||
|
if c in weights and weights[c] <= w + edge_w:
|
||||||
|
continue
|
||||||
|
weights[c] = w + edge_w
|
||||||
|
node, w = min(weights.items() , key=lambda nw: nw[1])
|
||||||
|
del weights[node]
|
||||||
|
visited.add(node)
|
||||||
|
return w
|
||||||
|
|
||||||
|
def min_paths(self, a):
|
||||||
|
weights = dict()
|
||||||
|
def aux(a, w):
|
||||||
|
if a in weights.keys() and weights[a] <= w:
|
||||||
|
return
|
||||||
|
|
||||||
|
weights[a] = w
|
||||||
|
|
||||||
|
for b, ab_w in graph[node]:
|
||||||
|
best = aux(b, w + w2, best)
|
||||||
|
|
||||||
|
aux(a, 0, None)
|
||||||
|
return weights
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
return WeightedGraph({a : [bw for bw in bws]for a, bws in self.items()})
|
||||||
|
|
||||||
|
|
||||||
|
def neighbours(maze, vec):
|
||||||
|
x, y = vec
|
||||||
|
ns = [(x+1, y), (x-1, y), (x, y+1), (x, y-1)]
|
||||||
|
width = max(map(len, maze))
|
||||||
|
return filter(lambda vec: 0 <= vec[0] < len(maze) and 0 <= vec[1] < len(maze[x]), ns)
|
||||||
|
|
||||||
|
def find_full_name(maze, vec):
|
||||||
|
x, y = vec
|
||||||
|
A = maze[x][y]
|
||||||
|
assert A.isalpha()
|
||||||
|
for a, b in neighbours(maze, (x, y)):
|
||||||
|
B = maze[a][b]
|
||||||
|
if B.isalpha():
|
||||||
|
return ''.join(sorted(A+B))
|
||||||
|
return None
|
||||||
|
|
||||||
|
def find_node(maze, vec):
|
||||||
|
x, y = vec
|
||||||
|
width = max(map(len, maze))
|
||||||
|
name = find_full_name(maze, (x, y))
|
||||||
|
if x < 2 or len(maze) - 2 <= x or y < 2 or width - 2 <= y:
|
||||||
|
loc = "out"
|
||||||
|
else:
|
||||||
|
loc = "in"
|
||||||
|
node = (loc, name)
|
||||||
|
return node
|
||||||
|
|
||||||
|
def other_node(packed):
|
||||||
|
loc, name = packed
|
||||||
|
if loc == "in":
|
||||||
|
return ("out", name)
|
||||||
|
return ("in", name)
|
||||||
|
|
||||||
|
def make_graph(maze):
|
||||||
|
graph = dict()
|
||||||
|
def search(node, vec, w, visited):
|
||||||
|
x, y = vec
|
||||||
|
if (x, y) in visited:
|
||||||
|
return
|
||||||
|
visited.append((x, y))
|
||||||
|
c = maze[x][y]
|
||||||
|
if c.isalpha():
|
||||||
|
node2 = find_node(maze, (x, y))
|
||||||
|
if node != node2:
|
||||||
|
graph[node].append((node2, w-1))
|
||||||
|
elif c == PATH:
|
||||||
|
for n in neighbours(maze, (x, y)):
|
||||||
|
search(node, n, w+1, visited)
|
||||||
|
|
||||||
|
visited = []
|
||||||
|
for x, line in enumerate(maze):
|
||||||
|
for y, c in enumerate(line):
|
||||||
|
if not c.isalpha():
|
||||||
|
continue
|
||||||
|
node = find_node(maze, (x, y))
|
||||||
|
if node in visited:
|
||||||
|
continue
|
||||||
|
paths = [(x,y) for (x,y) in neighbours(maze, (x,y)) if maze[x][y] == PATH]
|
||||||
|
if paths == []:
|
||||||
|
continue
|
||||||
|
visited.append(node)
|
||||||
|
start = paths[0]
|
||||||
|
graph[node] = []
|
||||||
|
search(node, start, 0, [])
|
||||||
|
graph = WeightedGraph(graph)
|
||||||
|
graph.rm_loops()
|
||||||
|
return graph
|
||||||
|
|
||||||
|
def preproc(puzzle_input):
|
||||||
|
maze = puzzle_input.split('\n')
|
||||||
|
return make_graph(maze)
|
||||||
|
|
||||||
|
def partI(graph):
|
||||||
|
graph = graph.copy()
|
||||||
|
for node in graph.keys():
|
||||||
|
if node[1] in ["AA", "ZZ"]:
|
||||||
|
continue
|
||||||
|
graph.add_edge(node, other_node(node), 1)
|
||||||
|
return graph.min_path(A, Z)
|
||||||
|
|
||||||
|
class RecGraph(WeightedGraph):
|
||||||
|
def edges_of(self, packed):
|
||||||
|
lvl, a = packed
|
||||||
|
edges = [((lvl, b), w) for b, w in self[a]]
|
||||||
|
|
||||||
|
loc, _ = a
|
||||||
|
|
||||||
|
lvl2 = lvl + (1 if loc == "in" else -1)
|
||||||
|
b = other_node(a)
|
||||||
|
|
||||||
|
if b not in self or lvl2 < 0:
|
||||||
|
return edges
|
||||||
|
b_edge = (lvl2, b), 1
|
||||||
|
if lvl2 < lvl:
|
||||||
|
edges = [b_edge] + edges
|
||||||
|
else:
|
||||||
|
edges.append(b_edge)
|
||||||
|
return edges
|
||||||
|
|
||||||
|
|
||||||
|
def partII(graph):
|
||||||
|
graph = RecGraph(graph)
|
||||||
|
return graph.min_path((0, A), (0, Z))
|
||||||
|
|
||||||
|
test =""" A
|
||||||
|
A
|
||||||
|
#######.#########
|
||||||
|
#######.........#
|
||||||
|
#######.#######.#
|
||||||
|
#######.#######.#
|
||||||
|
#######.#######.#
|
||||||
|
##### B ###.#
|
||||||
|
BC...## C ###.#
|
||||||
|
##.## ###.#
|
||||||
|
##...DE F ###.#
|
||||||
|
##### G ###.#
|
||||||
|
#########.#####.#
|
||||||
|
DE..#######...###.#
|
||||||
|
#.#########.###.#
|
||||||
|
FG..#########.....#
|
||||||
|
###########.#####
|
||||||
|
Z
|
||||||
|
Z """
|
||||||
|
|
||||||
|
|
||||||
|
test2 = """ A
|
||||||
|
A
|
||||||
|
#################.#############
|
||||||
|
#.#...#...................#.#.#
|
||||||
|
#.#.#.###.###.###.#########.#.#
|
||||||
|
#.#.#.......#...#.....#.#.#...#
|
||||||
|
#.#########.###.#####.#.#.###.#
|
||||||
|
#.............#.#.....#.......#
|
||||||
|
###.###########.###.#####.#.#.#
|
||||||
|
#.....# A C #.#.#.#
|
||||||
|
####### S P #####.#
|
||||||
|
#.#...# #......VT
|
||||||
|
#.#.#.# #.#####
|
||||||
|
#...#.# YN....#.#
|
||||||
|
#.###.# #####.#
|
||||||
|
DI....#.# #.....#
|
||||||
|
#####.# #.###.#
|
||||||
|
ZZ......# QG....#..AS
|
||||||
|
###.### #######
|
||||||
|
JO..#.#.# #.....#
|
||||||
|
#.#.#.# ###.#.#
|
||||||
|
#...#..DI BU....#..LF
|
||||||
|
#####.# #.#####
|
||||||
|
YN......# VT..#....QG
|
||||||
|
#.###.# #.###.#
|
||||||
|
#.#...# #.....#
|
||||||
|
###.### J L J #.#.###
|
||||||
|
#.....# O F P #.#...#
|
||||||
|
#.###.#####.#.#####.#####.###.#
|
||||||
|
#...#.#.#...#.....#.....#.#...#
|
||||||
|
#.#####.###.###.#.#.#########.#
|
||||||
|
#...#.#.....#...#.#.#.#.....#.#
|
||||||
|
#.###.#####.###.###.#.#.#######
|
||||||
|
#.#.........#...#.............#
|
||||||
|
#########.###.###.#############
|
||||||
|
B J C
|
||||||
|
U P P """
|
||||||
|
|
||||||
|
test3 = """ Z L X W C
|
||||||
|
Z P Q B K
|
||||||
|
###########.#.#.#.#######.###############
|
||||||
|
#...#.......#.#.......#.#.......#.#.#...#
|
||||||
|
###.#.#.#.#.#.#.#.###.#.#.#######.#.#.###
|
||||||
|
#.#...#.#.#...#.#.#...#...#...#.#.......#
|
||||||
|
#.###.#######.###.###.#.###.###.#.#######
|
||||||
|
#...#.......#.#...#...#.............#...#
|
||||||
|
#.#########.#######.#.#######.#######.###
|
||||||
|
#...#.# F R I Z #.#.#.#
|
||||||
|
#.###.# D E C H #.#.#.#
|
||||||
|
#.#...# #...#.#
|
||||||
|
#.###.# #.###.#
|
||||||
|
#.#....OA WB..#.#..ZH
|
||||||
|
#.###.# #.#.#.#
|
||||||
|
CJ......# #.....#
|
||||||
|
####### #######
|
||||||
|
#.#....CK #......IC
|
||||||
|
#.###.# #.###.#
|
||||||
|
#.....# #...#.#
|
||||||
|
###.### #.#.#.#
|
||||||
|
XF....#.# RF..#.#.#
|
||||||
|
#####.# #######
|
||||||
|
#......CJ NM..#...#
|
||||||
|
###.#.# #.###.#
|
||||||
|
RE....#.# #......RF
|
||||||
|
###.### X X L #.#.#.#
|
||||||
|
#.....# F Q P #.#.#.#
|
||||||
|
###.###########.###.#######.#########.###
|
||||||
|
#.....#...#.....#.......#...#.....#.#...#
|
||||||
|
#####.#.###.#######.#######.###.###.#.#.#
|
||||||
|
#.......#.......#.#.#.#.#...#...#...#.#.#
|
||||||
|
#####.###.#####.#.#.#.#.###.###.#.###.###
|
||||||
|
#.......#.....#.#...#...............#...#
|
||||||
|
#############.#.#.###.###################
|
||||||
|
A O F N
|
||||||
|
A A D M """
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
from intcode import preproc
|
||||||
|
from lib import last
|
||||||
|
|
||||||
|
logic1 = """\
|
||||||
|
NOT A J
|
||||||
|
NOT B T
|
||||||
|
OR T J
|
||||||
|
NOT C T
|
||||||
|
OR T J
|
||||||
|
AND D J
|
||||||
|
"""
|
||||||
|
logic2 = logic1 + """\
|
||||||
|
NOT I T
|
||||||
|
NOT T T
|
||||||
|
OR F T
|
||||||
|
AND E T
|
||||||
|
OR H T
|
||||||
|
AND T J
|
||||||
|
"""
|
||||||
|
|
||||||
|
def partI(exe):
|
||||||
|
log = logic1 + 'WALK\n'
|
||||||
|
return last(exe(input_iter = map(ord, log)))
|
||||||
|
|
||||||
|
def partII(exe):
|
||||||
|
log = logic2 + 'RUN\n'
|
||||||
|
return last(exe(input_iter = map(ord, log)))
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
from functools import reduce
|
||||||
|
|
||||||
|
deal = lambda: (-1, -1)
|
||||||
|
dealN = lambda n: (n, 0)
|
||||||
|
cutN = lambda n: (1, -n)
|
||||||
|
id = (1, 0)
|
||||||
|
|
||||||
|
instructions = {"deal into new stack" : deal,
|
||||||
|
"deal with increment" : dealN,
|
||||||
|
"cut" : cutN
|
||||||
|
}
|
||||||
|
|
||||||
|
def egcd(a, b):
|
||||||
|
if a == 0:
|
||||||
|
return (b, 0, 1)
|
||||||
|
else:
|
||||||
|
g, y, x = egcd(b % a, a)
|
||||||
|
return (g, x - (b // a) * y, y)
|
||||||
|
|
||||||
|
def modinv(a, m):
|
||||||
|
g, x, y = egcd(a, m)
|
||||||
|
if g != 1:
|
||||||
|
raise Exception('modular inverse does not exist')
|
||||||
|
else:
|
||||||
|
return x % m
|
||||||
|
|
||||||
|
def comp(ab, cd, mod):
|
||||||
|
a, b = ab
|
||||||
|
c, d = cd
|
||||||
|
return ((a*c) % mod, (a*d + b) % mod)
|
||||||
|
|
||||||
|
def apply(ab, x, mod):
|
||||||
|
a, b = ab
|
||||||
|
return (a*x + b) % mod
|
||||||
|
|
||||||
|
def inverse(ab, mod):
|
||||||
|
a, b = ab
|
||||||
|
x = modinv(a, mod)
|
||||||
|
return (x, (-b * x) % mod)
|
||||||
|
|
||||||
|
def powcomp(ab, pw, mod):
|
||||||
|
a, b = ab
|
||||||
|
return (pow(a, pw, mod), ((pow(a, pw, mod) - 1) * modinv(a-1, mod) * b) % mod)
|
||||||
|
|
||||||
|
def parse(line):
|
||||||
|
for inst in instructions.keys():
|
||||||
|
if line[:len(inst)] == inst:
|
||||||
|
return instructions[inst](*map(int, line[len(inst):].split()))
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
def compile(program, deck):
|
||||||
|
return reduce(lambda f1, f2: comp(f2, f1, deck), program, id)
|
||||||
|
|
||||||
|
|
||||||
|
def preproc(puzzle_input):
|
||||||
|
return list(map(parse, puzzle_input.split('\n')))
|
||||||
|
|
||||||
|
def partI(program):
|
||||||
|
deck = 10007
|
||||||
|
shuffle = compile(program, deck)
|
||||||
|
return apply(shuffle, 2019, deck)
|
||||||
|
|
||||||
|
def partII(program):
|
||||||
|
deck = 119315717514047
|
||||||
|
pw = 101741582076661
|
||||||
|
shuffle = compile(program, deck)
|
||||||
|
invshuffle = inverse(shuffle, deck)
|
||||||
|
|
||||||
|
repeated = powcomp(invshuffle, pw, deck)
|
||||||
|
return apply(repeated, 2020, deck)
|
|
@ -0,0 +1,81 @@
|
||||||
|
|
||||||
|
BUG = '#'
|
||||||
|
EMPTY = '.'
|
||||||
|
LEVEL = '.'*12 + '?' + '.'*12
|
||||||
|
|
||||||
|
edges = {7 : range(0, 5),
|
||||||
|
11 : range(0, 21, 5),
|
||||||
|
13 : range(4, 25, 5),
|
||||||
|
17 : range(20, 25)}
|
||||||
|
|
||||||
|
|
||||||
|
def neighbours(lvl, i):
|
||||||
|
r = []
|
||||||
|
if i > 4:
|
||||||
|
r.append(i-5)
|
||||||
|
if i < 20:
|
||||||
|
r.append(i+5)
|
||||||
|
if (i % 5) < 4:
|
||||||
|
r.append(i+1)
|
||||||
|
if (i % 5) > 0:
|
||||||
|
r.append(i-1)
|
||||||
|
return list(zip(4*[lvl], r))
|
||||||
|
|
||||||
|
def rec_neigh(lvl, i):
|
||||||
|
ns = neighbours(lvl, i)
|
||||||
|
for inner, outer in edges.items():
|
||||||
|
if i == inner:
|
||||||
|
ns += [(lvl+1, j) for j in outer]
|
||||||
|
elif i in outer:
|
||||||
|
ns += [(lvl-1, inner)]
|
||||||
|
return ns
|
||||||
|
|
||||||
|
def fate(val, ns):
|
||||||
|
if val == BUG and ns.count(BUG) != 1:
|
||||||
|
return EMPTY
|
||||||
|
elif val == EMPTY and ns.count(BUG) in (1, 2):
|
||||||
|
return BUG
|
||||||
|
return val
|
||||||
|
|
||||||
|
def trim(stack):
|
||||||
|
while BUG not in stack[-1]:
|
||||||
|
stack.pop()
|
||||||
|
while BUG not in stack[0]:
|
||||||
|
stack.pop(0)
|
||||||
|
|
||||||
|
def next(bug_stack, nfunc=rec_neigh):
|
||||||
|
bug_stack = 2*[LEVEL] + bug_stack + 2*[LEVEL]
|
||||||
|
new = []
|
||||||
|
for lvl in range(1, len(bug_stack)-1):
|
||||||
|
new.append('')
|
||||||
|
for i, val in enumerate(bug_stack[lvl]):
|
||||||
|
ns = nfunc(lvl, i)
|
||||||
|
nvals = [bug_stack[l][j] for l, j in ns]
|
||||||
|
new[-1] += fate(val, nvals)
|
||||||
|
trim(new)
|
||||||
|
return new
|
||||||
|
|
||||||
|
def bugs_sim(bug_stack, i):
|
||||||
|
for i in range(i):
|
||||||
|
bug_stack = next(bug_stack)
|
||||||
|
return bug_stack
|
||||||
|
|
||||||
|
def biodiversity(bugs):
|
||||||
|
return sum(2**pw for pw, c in enumerate(bugs) if c == BUG)
|
||||||
|
|
||||||
|
def preproc(puzzle_input):
|
||||||
|
return puzzle_input.replace('\n', '')
|
||||||
|
|
||||||
|
def partI(bugs):
|
||||||
|
layouts = set()
|
||||||
|
b = bugs
|
||||||
|
while b not in layouts:
|
||||||
|
layouts.add(b)
|
||||||
|
b = next([b], neighbours)[0]
|
||||||
|
|
||||||
|
return biodiversity(b)
|
||||||
|
|
||||||
|
def partII(bugs):
|
||||||
|
bugs = bugs[:12] + '?' + bugs[13:]
|
||||||
|
stack = [bugs]
|
||||||
|
return ''.join(bugs_sim(stack, 200)).count(BUG)
|
Loading…
Reference in New Issue