@@ -21,14 +21,16 @@ def puzzle2(input_file: typing.TextIO):
2121 return len ([path for path in paths if path .contains_small_caves ()])
2222
2323
24- class Node :
24+ class Node ( object ) :
2525 name : str
26+ is_small_cave : bool
2627
27- def __init__ (self , name ):
28+ def __init__ (self , name : str ):
2829 self .name = name
30+ self .is_small_cave = name .islower ()
2931
3032 def is_small (self ) -> bool :
31- return self .name . islower ()
33+ return self .is_small_cave
3234
3335 def is_start (self ) -> bool :
3436 return self .name == 'start'
@@ -52,47 +54,40 @@ def parse_row(row: str) -> (Node, Node):
5254 return Node (nodes [0 ]), Node (nodes [1 ])
5355
5456
55- class Path :
57+ class Path ( object ) :
5658 nodes : [Node ]
57- count : { Node , int }
59+ visited_twice : typing . Union [ Node , None ]
5860
5961 def __init__ (self ):
6062 self .nodes = []
61- self .count = {}
63+ self .visited_twice = None
6264
6365 def __str__ (self ):
6466 return str ([node .name for node in self .nodes ])
6567
66- def __eq__ (self , other ):
67- return self .nodes == other .nodes
68-
69- def __hash__ (self ):
70- return hash (tuple (self .nodes ))
71-
7268 def add (self , node : Node ) -> bool :
7369 if not self .can_be_visited (node ):
7470 return False
7571
76- if node in self .count :
77- self .count [node ] += 1
78- else :
79- self .count [node ] = 1
72+ if node .is_small () and node in self .nodes :
73+ self .visited_twice = node
8074
8175 self .nodes .append (node )
8276
8377 return True
8478
8579 def pop (self ):
8680 node = self .nodes .pop ()
87- self .count [node ] -= 1
8881
89- return node
82+ if node .is_small () and self .visited_twice is not None and self .visited_twice .name == node .name :
83+ self .visited_twice = None
9084
9185 def contains_small_caves (self ) -> bool :
92- return any ([node .is_small () for node in self .nodes ])
86+ for node in self .nodes :
87+ if node .is_small :
88+ return True
9389
94- def contains_small_cave_visited_twice (self ) -> bool :
95- return any ([count > 1 for node , count in self .count .items () if node .is_small ()])
90+ return False
9691
9792 def can_be_visited (self , node : Node ) -> bool :
9893 if not node .is_small ():
@@ -101,10 +96,22 @@ def can_be_visited(self, node: Node) -> bool:
10196 if (node .is_start () or node .is_end ()) and node in self .nodes :
10297 return False
10398
104- return node not in self .nodes or not self .contains_small_cave_visited_twice ()
99+ return self .visited_twice is None or node not in self .nodes
100+
101+ def __copy__ (self , memodict = {}):
102+ copy = Path ()
103+ copy .nodes = self .nodes
104+
105+ return copy
106+
107+ def __deepcopy__ (self , memodict = {}):
108+ copy = Path ()
109+ copy .nodes = self .nodes [:]
110+
111+ return copy
105112
106113
107- class CavesMap :
114+ class CavesMap ( object ) :
108115 points : {str : Node }
109116 edges : {str : [Node ]}
110117
@@ -127,23 +134,23 @@ def __init__(self, edges: (Node, Node)):
127134 self .edges [edge [1 ].name ] = [edge [0 ]]
128135
129136 def find_paths (self ) -> [Path ]:
130- paths = set ()
137+ paths = []
131138
132139 start = self .points ['start' ]
133140
134141 self ._find_paths (start , paths )
135142
136143 return paths
137144
138- def _find_paths (self , current : Node , paths : set [Path ], path : Path = None ):
145+ def _find_paths (self , current : Node , paths : [Path ], path : Path = None ):
139146 if path is None :
140147 path = Path ()
141148
142149 if not path .add (current ):
143150 return
144151
145152 if current .is_end ():
146- paths .add (deepcopy (path ))
153+ paths .append (deepcopy (path ))
147154 path .pop ()
148155 return
149156
0 commit comments