87
day12/day12.py
Executable file
87
day12/day12.py
Executable file
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from copy import deepcopy
|
||||
from typing import DefaultDict, MutableMapping, Set
|
||||
import pprint
|
||||
import string
|
||||
|
||||
|
||||
Vertices = DefaultDict[str, Set[str]]
|
||||
SMALL = set(string.ascii_lowercase)
|
||||
BIG = set(string.ascii_uppercase)
|
||||
|
||||
|
||||
def is_small(cave: str):
|
||||
s = set(cave)
|
||||
return (s & SMALL) == s
|
||||
|
||||
|
||||
def part1(vertices: Vertices):
|
||||
small = {cave for cave in vertices.keys() if is_small(cave)}
|
||||
big = set(vertices.keys()) - small
|
||||
assert len(big & small) == 0
|
||||
|
||||
def find_paths(current: str, visited: Set[str] = set(), path: str = "") -> Set[str]:
|
||||
visited = deepcopy(visited)
|
||||
visited |= {current}
|
||||
paths = set()
|
||||
for vertex in vertices[current]:
|
||||
if vertex == "end":
|
||||
paths |= {path}
|
||||
elif vertex in visited and vertex in small:
|
||||
continue
|
||||
else:
|
||||
paths |= find_paths(vertex, visited, path + vertex)
|
||||
return paths
|
||||
|
||||
paths = find_paths("start")
|
||||
print(len(paths))
|
||||
|
||||
|
||||
def part2(vertices: Vertices):
|
||||
small = {cave for cave in vertices.keys() if is_small(cave)}
|
||||
big = set(vertices.keys()) - small
|
||||
assert len(big & small) == 0
|
||||
|
||||
def find_paths(
|
||||
allowed: str,
|
||||
current: str,
|
||||
visited: MutableMapping[str, int] = defaultdict(lambda: 0),
|
||||
path: str = "",
|
||||
) -> Set[str]:
|
||||
if current == allowed:
|
||||
if visited[current] >= 2:
|
||||
# This is a small cave and we've already visited it twice
|
||||
return set()
|
||||
elif current in small and visited[current]:
|
||||
# Visited already
|
||||
return set()
|
||||
visited = deepcopy(visited)
|
||||
visited[current] += 1
|
||||
paths = set()
|
||||
for vertex in vertices[current]:
|
||||
if vertex == "end":
|
||||
paths |= {path}
|
||||
else:
|
||||
paths |= find_paths(allowed, vertex, visited, path + vertex)
|
||||
return paths
|
||||
|
||||
paths = set()
|
||||
for allowed in small - {"start", "end"}:
|
||||
paths |= find_paths(allowed, "start")
|
||||
print(len(paths))
|
||||
|
||||
|
||||
# Doing this comprehension so Mypy is happy
|
||||
edges = [(a, b) for a, b in map(lambda l: l.strip().split("-"), sys.stdin)]
|
||||
vertices: Vertices = defaultdict(set)
|
||||
for a, b in edges:
|
||||
vertices[a] |= {b}
|
||||
vertices[b] |= {a}
|
||||
|
||||
|
||||
print("Part 1")
|
||||
part1(vertices)
|
||||
print("Part 2")
|
||||
part2(vertices)
|
||||
7
day12/example.txt
Normal file
7
day12/example.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
start-A
|
||||
start-b
|
||||
A-c
|
||||
A-b
|
||||
b-d
|
||||
A-end
|
||||
b-end
|
||||
10
day12/example2.txt
Normal file
10
day12/example2.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
dc-end
|
||||
HN-start
|
||||
start-kj
|
||||
dc-start
|
||||
dc-HN
|
||||
LN-dc
|
||||
HN-end
|
||||
kj-sa
|
||||
kj-HN
|
||||
kj-dc
|
||||
18
day12/example3.txt
Normal file
18
day12/example3.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
fs-end
|
||||
he-DX
|
||||
fs-he
|
||||
start-DX
|
||||
pj-DX
|
||||
end-zg
|
||||
zg-sl
|
||||
zg-pj
|
||||
pj-he
|
||||
RW-he
|
||||
fs-DX
|
||||
pj-RW
|
||||
zg-RW
|
||||
start-pj
|
||||
he-WI
|
||||
zg-he
|
||||
pj-fs
|
||||
start-RW
|
||||
21
day12/input.txt
Normal file
21
day12/input.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
ma-start
|
||||
YZ-rv
|
||||
MP-rv
|
||||
vc-MP
|
||||
QD-kj
|
||||
rv-kj
|
||||
ma-rv
|
||||
YZ-zd
|
||||
UB-rv
|
||||
MP-xe
|
||||
start-MP
|
||||
zd-end
|
||||
ma-UB
|
||||
ma-MP
|
||||
UB-xe
|
||||
end-UB
|
||||
ju-MP
|
||||
ma-xe
|
||||
zd-UB
|
||||
start-xe
|
||||
YZ-end
|
||||
Reference in New Issue
Block a user