Skip to content

Commit ddafd77

Browse files
committed
perf: improved and simplified solution 2021 12th
1 parent 412e13c commit ddafd77

File tree

1 file changed

+33
-26
lines changed

1 file changed

+33
-26
lines changed

2021/12/puzzle2.py

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)