From 98bd59341cfb0290341fdee2e242bd6cbc23f1bc Mon Sep 17 00:00:00 2001 From: Chris Oates Date: Sun, 12 Dec 2021 13:08:12 +0000 Subject: [PATCH] day12: python Honestly, I was stunned when my part1 worked first time. Part 2 was harder because I'm an idiot and had a bug that kept causing recursion errors. Reckon I'll do a refactor to combine the two parts and memoise, since part 2 took rather long --- day12/day12.py | 99 +++++++++++++++++++++++++++++++++++++++++++++++++ day12/input.txt | 24 ++++++++++++ day12/test.txt | 7 ++++ day12/test1.txt | 10 +++++ day12/test2.txt | 18 +++++++++ 5 files changed, 158 insertions(+) create mode 100644 day12/day12.py create mode 100644 day12/input.txt create mode 100644 day12/test.txt create mode 100644 day12/test1.txt create mode 100644 day12/test2.txt diff --git a/day12/day12.py b/day12/day12.py new file mode 100644 index 0000000..8a417ca --- /dev/null +++ b/day12/day12.py @@ -0,0 +1,99 @@ +from collections import Counter, defaultdict + + +def load_data(path): + graph = defaultdict(list) + + with open(path, 'r') as f: + for line in f: + + a, b = line.strip().split('-') + + if a == 'start': + graph['START'].append(b) + elif b == 'start': + graph['START'].append(a) + + elif b == 'end': + graph[a].append('END') + elif a == 'end': + graph[b].append('END') + + else: + graph[a].append(b) + graph[b].append(a) + + return graph + + +def count_paths(graph, node, visited): + if node == 'END': + return 1 + + neighbours = [ + n for n in graph[node] + if n.isupper() or n not in visited + ] + + paths = 0 + for n in neighbours: + paths += count_paths(graph, n, {n, *visited}) + + return paths + + +def part1(graph): + return count_paths(graph, 'START', set()) + + +def count_paths_with_revisit(graph, node, visited): + if node == 'END': + return 1 + + can_revisit = not any(v == 2 for v in visited.values()) + + paths = 0 + for n in graph[node]: + if n.isupper(): + paths += count_paths_with_revisit(graph, n, visited) + elif visited[n] == 0 or can_revisit: + v = visited.copy() + v[n] += 1 + paths += count_paths_with_revisit(graph, n, v) + + return paths + + +def part2(graph): + return count_paths_with_revisit(graph, 'START', Counter()) + + +def main(): + data = load_data('input.txt') + print(part1(data)) + print(part2(data)) + + +if __name__ == '__main__': + main() + + +class Test: + + def test_part1_small(self): + assert part1(load_data('test.txt')) == 10 + + def test_part1_medium(self): + assert part1(load_data('test1.txt')) == 19 + + def test_part1_large(self): + assert part1(load_data('test2.txt')) == 226 + + def test_part2_small(self): + assert part2(load_data('test.txt')) == 36 + + def test_part2_medium(self): + assert part2(load_data('test1.txt')) == 103 + + def test_part2_large(self): + assert part2(load_data('test2.txt')) == 3509 diff --git a/day12/input.txt b/day12/input.txt new file mode 100644 index 0000000..e408c73 --- /dev/null +++ b/day12/input.txt @@ -0,0 +1,24 @@ +by-TW +start-TW +fw-end +QZ-end +JH-by +ka-start +ka-by +end-JH +QZ-cv +vg-TI +by-fw +QZ-by +JH-ka +JH-vg +vg-fw +TW-cv +QZ-vg +ka-TW +ka-QZ +JH-fw +vg-hu +cv-start +by-cv +ka-cv diff --git a/day12/test.txt b/day12/test.txt new file mode 100644 index 0000000..6fd8c41 --- /dev/null +++ b/day12/test.txt @@ -0,0 +1,7 @@ +start-A +start-b +A-c +A-b +b-d +A-end +b-end diff --git a/day12/test1.txt b/day12/test1.txt new file mode 100644 index 0000000..62cc714 --- /dev/null +++ b/day12/test1.txt @@ -0,0 +1,10 @@ +dc-end +HN-start +start-kj +dc-start +dc-HN +LN-dc +HN-end +kj-sa +kj-HN +kj-dc diff --git a/day12/test2.txt b/day12/test2.txt new file mode 100644 index 0000000..65f3833 --- /dev/null +++ b/day12/test2.txt @@ -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