From c3faa9ea58e06fdc3c6a79353c7962789850fef7 Mon Sep 17 00:00:00 2001 From: daviddoji Date: Sat, 13 Aug 2022 21:37:12 +0200 Subject: [PATCH] Solution to problem 12 part 1 in Python --- src/Year_2021/P12.py | 160 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 src/Year_2021/P12.py diff --git a/src/Year_2021/P12.py b/src/Year_2021/P12.py new file mode 100644 index 0000000..5d4b39f --- /dev/null +++ b/src/Year_2021/P12.py @@ -0,0 +1,160 @@ +# --- Day 12: Passage Pathing --- + +# With your submarine's subterranean subsystems subsisting suboptimally, the +# only way you're getting out of this cave anytime soon is by finding a path +# yourself. Not just a path - the only way to know if you've found the best +# path is to find all of them. + +# Fortunately, the sensors are still mostly working, and so you build a rough +# map of the remaining caves (your puzzle input). For example: + +# start-A +# start-b +# A-c +# A-b +# b-d +# A-end +# b-end + +# This is a list of how all of the caves are connected. You start in the cave +# named start, and your destination is the cave named end. An entry like b-d +# means that cave b is connected to cave d - that is, you can move between +# them. + +# So, the above cave system looks roughly like this: + +# start +# / \ +# c--A-----b--d +# \ / +# end + +# Your goal is to find the number of distinct paths that start at start, end at +# end, and don't visit small caves more than once. There are two types of +# caves: big caves (written in uppercase, like A) and small caves (written in +# lowercase, like b). It would be a waste of time to visit any small cave more +# than once, but big caves are large enough that it might be worth visiting +# them multiple times. So, all paths you find should visit small caves at most +# once, and can visit big caves any number of times. + +# Given these rules, there are 10 paths through this example cave system: + +# start,A,b,A,c,A,end +# start,A,b,A,end +# start,A,b,end +# start,A,c,A,b,A,end +# start,A,c,A,b,end +# start,A,c,A,end +# start,A,end +# start,b,A,c,A,end +# start,b,A,end +# start,b,end + +# (Each line in the above list corresponds to a single path; the caves visited +# by that path are listed in the order they are visited and separated by +# commas.) + +# Note that in this cave system, cave d is never visited by any path: to do so, +# cave b would need to be visited twice (once on the way to cave d and a second +# time when returning from cave d), and since cave b is small, this is not +# allowed. + +# Here is a slightly larger example: + +# dc-end +# HN-start +# start-kj +# dc-start +# dc-HN +# LN-dc +# HN-end +# kj-sa +# kj-HN +# kj-dc + +# The 19 paths through it are as follows: + +# start,HN,dc,HN,end +# start,HN,dc,HN,kj,HN,end +# start,HN,dc,end +# start,HN,dc,kj,HN,end +# start,HN,end +# start,HN,kj,HN,dc,HN,end +# start,HN,kj,HN,dc,end +# start,HN,kj,HN,end +# start,HN,kj,dc,HN,end +# start,HN,kj,dc,end +# start,dc,HN,end +# start,dc,HN,kj,HN,end +# start,dc,end +# start,dc,kj,HN,end +# start,kj,HN,dc,HN,end +# start,kj,HN,dc,end +# start,kj,HN,end +# start,kj,dc,HN,end +# start,kj,dc,end + +# Finally, this even larger example has 226 paths through it: + +# 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 + +# How many paths through this cave system are there that visit small caves at +# most once? + +from collections import defaultdict +from typing import DefaultDict + +caves_map = defaultdict(list) +with open("files/P12.txt") as f: + for row in f: + start, end = row.strip().split("-") + caves_map[start].append(end) + caves_map[end].append(start) + + +def dfs( + node: str, + graph: DefaultDict[str, list[str]], + visited: set[str], + already_visited: bool, + counter: int = 0, +): + if node == "end": + return 1 + for neighbour in graph[node]: + if neighbour.isupper(): + counter += dfs(neighbour, graph, visited, already_visited) + else: + if neighbour not in visited: + counter += dfs( + neighbour, graph, visited | {neighbour}, already_visited + ) + elif already_visited and neighbour not in {"start", "end"}: + counter += dfs(neighbour, graph, visited, False) + return counter + + +def part_1() -> None: + ans = dfs("start", caves_map, {"start"}, already_visited=False) + print(f"There are {ans} paths visiting small caves") + + +if __name__ == "__main__": + part_1()