summaryrefslogtreecommitdiffstats
path: root/day12
diff options
context:
space:
mode:
authorGravatar Tom van der Lee <tom@vanderlee.io>2021-12-13 10:20:50 +0100
committerGravatar Tom van der Lee <tom@vanderlee.io>2021-12-13 10:20:50 +0100
commit7bbeb8155521686bd9bbd28fec5cb91ffb8360af (patch)
treed0f272a59681223e0af204363b500a1f78626f09 /day12
parent2de80670eb989467111da967ccc78de7c00f06bc (diff)
download2021-7bbeb8155521686bd9bbd28fec5cb91ffb8360af.tar.gz
2021-7bbeb8155521686bd9bbd28fec5cb91ffb8360af.tar.bz2
2021-7bbeb8155521686bd9bbd28fec5cb91ffb8360af.zip
Day 12
Diffstat (limited to 'day12')
-rw-r--r--day12/__init__.py116
-rw-r--r--day12/example.txt10
-rw-r--r--day12/input.txt23
-rw-r--r--day12/test_init.py72
4 files changed, 221 insertions, 0 deletions
diff --git a/day12/__init__.py b/day12/__init__.py
new file mode 100644
index 0000000..aad531d
--- /dev/null
+++ b/day12/__init__.py
@@ -0,0 +1,116 @@
1from abc import ABC
2from collections import Counter
3from dataclasses import dataclass, field
4from typing import List, Tuple, Dict, Set
5
6from aoc import BaseAssignment
7
8Coordinate = Tuple[int, int]
9Field = List[List[int]]
10
11
12@dataclass
13class Node:
14 id: str
15 big: bool = False
16 nodes: Set['Node'] = field(default_factory=set)
17
18 def __eq__(self, other: 'Node'):
19 return self.id == other.id
20
21 def __hash__(self):
22 return hash(self.id)
23
24 def __repr__(self):
25 return f'Node(id={self.id})'
26
27 def __lt__(self, other):
28 return self.id < other.id
29
30class Assignment(BaseAssignment, ABC):
31 def parse_item(self, item: str) -> Tuple[str, str]:
32 return tuple(item.split('-'))
33
34 @classmethod
35 def get_or_create_node(cls, nodes: Dict[str, Node], id) -> Node:
36 if id not in nodes:
37 nodes[id] = Node(id=id, big=id.upper() == id)
38 return nodes[id]
39
40 def read_input(self, example = False) -> Dict[str, Node]:
41 nodes = {}
42 for a, b in super().read_input(example):
43 node_a = self.get_or_create_node(nodes, a)
44 node_b = self.get_or_create_node(nodes, b)
45
46 node_a.nodes.add(node_b)
47 node_b.nodes.add(node_a)
48
49 return nodes
50
51 @classmethod
52 def calculate_all_paths(cls, start: Node, end: Node, visited: List[Node] = []) -> List[List[Node]]:
53 raise NotImplementedError
54
55 def run(self, input: Dict[str, Node]) -> int:
56 return len(self.calculate_all_paths(input['start'], input['end']))
57
58
59class AssignmentOne(Assignment):
60 example_result = 19
61
62 @classmethod
63 def calculate_all_paths(cls, start: Node, end: Node, visited: List[Node] = []) -> List[List[Node]]:
64 if start == end:
65 return [[end]]
66
67 return [
68 [start, *path]
69 for node in start.nodes
70 if node.big or node not in visited
71 for path in cls.calculate_all_paths(node, end, visited=[*visited, start])
72 ]
73
74
75class AssignmentTwo(Assignment):
76 example_result = 103
77
78 @classmethod
79 def can_be_visited(cls, node: Node, visited: List[Node]) -> bool:
80 if node.big:
81 return True
82
83 visited_counter = Counter([node for node in visited if not node.big])
84
85 if node.id in ['start', 'end']:
86 return visited_counter.get(node, 0) < 1
87
88 small_node_visited_twice = any(
89 v == 2
90 for n, v
91 in visited_counter.items()
92 )
93
94 return visited_counter.get(node, 0) < 1 if small_node_visited_twice else 2
95
96
97 @classmethod
98 def calculate_all_paths(cls, start: Node, end: Node, visited: List[Node] = []) -> List[List[Node]]:
99 if start == end:
100 return [[end]]
101
102 return [
103 [start, *path]
104 for node in start.nodes
105 if cls.can_be_visited(node, [*visited, start])
106 for path in cls.calculate_all_paths(node, end, visited=[*visited, start])
107 ]
108
109 def run(self, input: Dict[str, Node]) -> int:
110 paths = sorted(self.calculate_all_paths(input['start'], input['end']))
111
112 print()
113 for path in paths:
114 print(','.join([ n.id for n in path ]))
115
116 return len(paths)
diff --git a/day12/example.txt b/day12/example.txt
new file mode 100644
index 0000000..62cc714
--- /dev/null
+++ b/day12/example.txt
@@ -0,0 +1,10 @@
1dc-end
2HN-start
3start-kj
4dc-start
5dc-HN
6LN-dc
7HN-end
8kj-sa
9kj-HN
10kj-dc
diff --git a/day12/input.txt b/day12/input.txt
new file mode 100644
index 0000000..96b504b
--- /dev/null
+++ b/day12/input.txt
@@ -0,0 +1,23 @@
1vn-DD
2qm-DD
3MV-xy
4end-xy
5KG-end
6end-kw
7qm-xy
8start-vn
9MV-vn
10vn-ko
11lj-KG
12DD-xy
13lj-kh
14lj-MV
15ko-MV
16kw-qm
17qm-MV
18lj-kw
19VH-lj
20ko-qm
21ko-start
22MV-start
23DD-ko
diff --git a/day12/test_init.py b/day12/test_init.py
new file mode 100644
index 0000000..f6e78e1
--- /dev/null
+++ b/day12/test_init.py
@@ -0,0 +1,72 @@
1from day12 import Node, AssignmentOne, AssignmentTwo
2
3
4def test_calculate_all_paths_assignment_one():
5 start = Node(id='start')
6 end = Node(id='end')
7
8 start.nodes.add(end)
9 end.nodes.add(start)
10
11 assert AssignmentOne.calculate_all_paths(start, end) == [
12 [start, end]
13 ]
14
15 a = Node(id='a')
16 start.nodes = { a }
17 a.nodes = { start, end }
18 end.nodes = { end }
19
20 assert AssignmentOne.calculate_all_paths(start, end) == [
21 [start, a, end]
22 ]
23
24 b = Node(id='b')
25 start.nodes = { a, b }
26 b.nodes = { start, end }
27 a.nodes = { start, end }
28 end.nodes = { a, b }
29
30 assert sorted(AssignmentOne.calculate_all_paths(start, end)) == sorted([
31 [start, a, end],
32 [start, b, end]
33 ])
34
35 a.nodes.add(b)
36 b.nodes.add(a)
37
38 assert sorted(AssignmentOne.calculate_all_paths(start, end)) == sorted([
39 [start, a, end],
40 [start, a, b, end],
41 [start, b, end],
42 [start, b, a, end]
43 ])
44
45 a.big = True
46
47 assert sorted(AssignmentOne.calculate_all_paths(start, end)) == sorted([
48 [start, a, end],
49 [start, a, b, end],
50 [start, a, b, a, end],
51 [start, b, end],
52 [start, b, a, end],
53 ])
54
55
56def test_calculate_all_paths_assignment_two():
57 start = Node(id='start')
58 end = Node(id='end')
59
60 a = Node(id='a')
61 b = Node(id='b')
62
63 start.nodes.add(a)
64 a.nodes.add(b)
65 a.nodes.add(start)
66 b.nodes.add(a)
67 b.nodes.add(end)
68 end.nodes.add(b)
69
70 assert sorted(AssignmentTwo.calculate_all_paths(start, end)) == sorted([
71 [start, a, b, end]
72 ])