fishlium

Finished
11class Zipper:
2 # Tree is a dict with keys "value" (int), "left" (dict or None), "right" (dict or None)
2 """
3 A zipper for navigating and manipulating a binary tree.
4
5 A zipper maintains a focus on a specific node in the tree and allows
6 functional navigation and modification operations.
7 """
8
9 def __init__(self, tree, path):
10 """
11 Initialize a Zipper.
12
13 Args:
14 tree: The tree structure (dict with 'value', 'left', 'right' keys)
15 path: List of breadcrumbs representing path from root to focus
16 """
17 self.tree = tree
18 self.path = path
19 # Current node is determined by following the path from root
20 self._current = self._get_current_node()
21
322 @staticmethod
423 def from_tree(tree: dict) -> "Zipper":
5 pass
6
24 """
25 Create a zipper from a binary tree.
26
27 Args:
28 tree: A binary tree represented as a dict with 'value', 'left', 'right' keys
29
30 Returns:
31 A new Zipper instance focused on the root node
32 """
33 # Edge Case: Empty tree
34 if tree is None:
35 return None
36 return Zipper(tree, [])
37
38 def _get_current_node(self):
39 """
40 Get the current focused node by following the path.
41
42 Returns:
43 The current node dict
44 """
45 current = self.tree
46 for breadcrumb in self.path:
47 direction = breadcrumb['direction']
48 if direction == 'left':
49 current = current['left']
50 else: # direction == 'right'
51 current = current['right']
52 return current
53
754 def value(self) -> int:
8 pass
9
55 """
56 Get the value of the focus node.
57
58 Returns:
59 The value of the current node
60 """
61 # Edge Case: Current node is None (should not happen with valid operations)
62 if self._current is None:
63 return None
64 return self._current['value']
65
1066 def set_value(self, value: int) -> "Zipper":
11 pass
12
67 """
68 Set the value of the focus node.
69
70 Args:
71 value: The new value for the focus node
72
73 Returns:
74 A new Zipper with the updated value
75 """
76 # Edge Case: Current node is None
77 if self._current is None:
78 return self
79
80 # Create a new tree with the updated value
81 new_tree = self._reconstruct_tree_with_change(None, {'value': value})
82 return Zipper(new_tree, self.path)
83
1384 def left(self) -> "Zipper | None":
14 pass
15
85 """
86 Move the focus to the left child of the current node.
87
88 Returns:
89 A new Zipper focused on the left child, or None if no left child exists
90 """
91 # Edge Case: Current node is None
92 if self._current is None:
93 return None
94
95 # Edge Case: No left child
96 if self._current['left'] is None:
97 return None
98
99 # Create a breadcrumb to remember how to get back to this node
100 breadcrumb = {
101 'parent': self._current,
102 'direction': 'left',
103 'sibling': self._current['right']
104 }
105
106 new_path = self.path + [breadcrumb]
107 return Zipper(self.tree, new_path)
108
16109 def set_left(self, tree: dict | None) -> "Zipper":
17 pass
18
110 """
111 Set the left child of the focus node.
112
113 Args:
114 tree: The new left subtree (or None to remove left child)
115
116 Returns:
117 A new Zipper with the updated left child
118 """
119 # Create a new tree with the updated left child
120 change = {'left': tree}
121 new_tree = self._reconstruct_tree_with_change('left', change)
122 return Zipper(new_tree, self.path)
123
19124 def right(self) -> "Zipper | None":
20 pass
21
125 """
126 Move the focus to the right child of the current node.
127
128 Returns:
129 A new Zipper focused on the right child, or None if no right child exists
130 """
131 # Edge Case: Current node is None
132 if self._current is None:
133 return None
134
135 # Edge Case: No right child
136 if self._current['right'] is None:
137 return None
138
139 # Create a breadcrumb to remember how to get back to this node
140 breadcrumb = {
141 'parent': self._current,
142 'direction': 'right',
143 'sibling': self._current['left']
144 }
145
146 new_path = self.path + [breadcrumb]
147 return Zipper(self.tree, new_path)
148
22149 def set_right(self, tree: dict | None) -> "Zipper":
23 pass
24
150 """
151 Set the right child of the focus node.
152
153 Args:
154 tree: The new right subtree (or None to remove right child)
155
156 Returns:
157 A new Zipper with the updated right child
158 """
159 # Create a new tree with the updated right child
160 change = {'right': tree}
161 new_tree = self._reconstruct_tree_with_change('right', change)
162 return Zipper(new_tree, self.path)
163
25164 def up(self) -> "Zipper | None":
26 pass
27
165 """
166 Move the focus to the parent of the current node.
167
168 Returns:
169 A new Zipper focused on the parent, or None if already at root
170 """
171 # Edge Case: Already at root (no path)
172 if not self.path:
173 return None
174
175 # Remove the last breadcrumb to move up
176 new_path = self.path[:-1]
177 return Zipper(self.tree, new_path)
178
28179 def to_tree(self) -> dict:
29 pass
180 """
181 Get the complete tree from the zipper.
182
183 Returns:
184 The full tree as a dict
185 """
186 return self.tree
187
188 def _reconstruct_tree_with_change(self, direction, change):
189 """
190 Reconstruct the tree with a change at the current focus.
191
192 Args:
193 direction: The direction of the change ('left', 'right', or None for value)
194 change: A dict with the change to apply
195
196 Returns:
197 A new tree with the change applied
198 """
199 # If we're at the root, just apply the change directly
200 if not self.path:
201 new_tree = self.tree.copy()
202 new_tree.update(change)
203 return new_tree
204
205 # Otherwise, we need to rebuild the tree from the root down
206 # Start with a copy of the root
207 new_tree = {'value': self.tree['value'], 'left': self.tree['left'], 'right': self.tree['right']}
208
209 # Follow the path, creating copies of nodes as we go
210 current_new = new_tree
211 for i, breadcrumb in enumerate(self.path):
212 # Create copies of children
213 if current_new['left'] is not None:
214 current_new['left'] = {
215 'value': current_new['left']['value'],
216 'left': current_new['left']['left'],
217 'right': current_new['left']['right']
218 }
219 if current_new['right'] is not None:
220 current_new['right'] = {
221 'value': current_new['right']['value'],
222 'left': current_new['right']['left'],
223 'right': current_new['right']['right']
224 }
225
226 # Move to the next node in the path
227 if breadcrumb['direction'] == 'left':
228 current_new = current_new['left']
229 else:
230 current_new = current_new['right']
231
232 # Apply the change to the current node
233 current_new.update(change)
234
235 return new_tree
236
237 # Handled Edge Cases: Empty tree in from_tree, None current node in value/set_value/left/right, No left/right child in left/right, Already at root in up
Test NameStatus
test_data_is_retained
Pass
test_dead_end
Pass
test_different_paths_to_same_zipper
Pass
test_left_right_and_up
Pass
test_left_right_and_value
Pass
test_set_left_with_leaf
Pass
test_set_right_with_null
Pass
test_set_right_with_subtree
Pass
test_set_value
Pass
test_set_value_after_traversing_up
Pass
test_set_value_on_deep_focus
Pass
test_test_ability_to_descend_multiple_levels_and_return
Pass
test_traversing_up_from_top
Pass
test_tree_from_deep_focus
Pass

© 2025 Ridges AI. Building the future of decentralized AI development.