| 1 | 1 | class Zipper: |
| 2 | | # Tree is a dict with keys "value" (int), "left" (dict or None), "right" (dict or None) |
| 2 | def __init__(self, tree, breadcrumbs=None): |
| 3 | # Edge Case: Initialize with default empty breadcrumbs if not provided |
| 4 | self.tree = tree |
| 5 | self.breadcrumbs = breadcrumbs or [] |
| 6 | |
| 3 | 7 | @staticmethod |
| 4 | 8 | def from_tree(tree: dict) -> "Zipper": |
| 5 | | pass |
| 9 | # Edge Case: Handle None tree input by returning a Zipper with empty tree |
| 10 | if tree is None: |
| 11 | return Zipper({"value": 0, "left": None, "right": None}, []) |
| 12 | return Zipper(tree, []) |
| 6 | 13 | |
| 7 | 14 | def value(self) -> int: |
| 8 | | pass |
| 15 | # Edge Case: Return value even if tree might be malformed (assumes valid structure) |
| 16 | return self.tree["value"] |
| 9 | 17 | |
| 10 | 18 | def set_value(self, value: int) -> "Zipper": |
| 11 | | pass |
| 19 | # Edge Case: Create new tree with updated value while preserving children |
| 20 | new_tree = { |
| 21 | "value": value, |
| 22 | "left": self.tree["left"], |
| 23 | "right": self.tree["right"] |
| 24 | } |
| 25 | return Zipper(new_tree, self.breadcrumbs) |
| 12 | 26 | |
| 13 | 27 | def left(self) -> "Zipper | None": |
| 14 | | pass |
| 28 | # Edge Case: Return None if left child is None or missing |
| 29 | if self.tree["left"] is None: |
| 30 | return None |
| 31 | # Create breadcrumb for current node when moving down |
| 32 | breadcrumb = { |
| 33 | "parent": self.tree, |
| 34 | "side": "left", |
| 35 | "right": self.tree["right"] |
| 36 | } |
| 37 | return Zipper(self.tree["left"], self.breadcrumbs + [breadcrumb]) |
| 15 | 38 | |
| 16 | 39 | def set_left(self, tree: dict | None) -> "Zipper": |
| 17 | | pass |
| 40 | # Edge Case: Create new tree with updated left child while preserving other parts |
| 41 | new_tree = { |
| 42 | "value": self.tree["value"], |
| 43 | "left": tree, |
| 44 | "right": self.tree["right"] |
| 45 | } |
| 46 | return Zipper(new_tree, self.breadcrumbs) |
| 18 | 47 | |
| 19 | 48 | def right(self) -> "Zipper | None": |
| 20 | | pass |
| 49 | # Edge Case: Return None if right child is None or missing |
| 50 | if self.tree["right"] is None: |
| 51 | return None |
| 52 | # Create breadcrumb for current node when moving down |
| 53 | breadcrumb = { |
| 54 | "parent": self.tree, |
| 55 | "side": "right", |
| 56 | "left": self.tree["left"] |
| 57 | } |
| 58 | return Zipper(self.tree["right"], self.breadcrumbs + [breadcrumb]) |
| 21 | 59 | |
| 22 | 60 | def set_right(self, tree: dict | None) -> "Zipper": |
| 23 | | pass |
| 61 | # Edge Case: Create new tree with updated right child while preserving other parts |
| 62 | new_tree = { |
| 63 | "value": self.tree["value"], |
| 64 | "left": self.tree["left"], |
| 65 | "right": tree |
| 66 | } |
| 67 | return Zipper(new_tree, self.breadcrumbs) |
| 24 | 68 | |
| 25 | 69 | def up(self) -> "Zipper | None": |
| 26 | | pass |
| 70 | # Edge Case: Return None if already at root (no breadcrumbs) |
| 71 | if not self.breadcrumbs: |
| 72 | return None |
| 73 | |
| 74 | # Get the last breadcrumb (most recent parent) |
| 75 | last_breadcrumb = self.breadcrumbs[-1] |
| 76 | |
| 77 | # Reconstruct parent tree with current subtree in correct position |
| 78 | parent_tree = { |
| 79 | "value": last_breadcrumb["parent"]["value"], |
| 80 | "left": last_breadcrumb.get("left", None), |
| 81 | "right": last_breadcrumb.get("right", None) |
| 82 | } |
| 83 | |
| 84 | # Put current tree in the correct side of parent |
| 85 | if last_breadcrumb["side"] == "left": |
| 86 | parent_tree["left"] = self.tree |
| 87 | else: # right |
| 88 | parent_tree["right"] = self.tree |
| 89 | |
| 90 | # Create new Zipper with parent tree and remove last breadcrumb |
| 91 | return Zipper(parent_tree, self.breadcrumbs[:-1]) |
| 27 | 92 | |
| 28 | 93 | def to_tree(self) -> dict: |
| 29 | | pass |
| 94 | # Navigate back to root to get complete tree |
| 95 | current = self |
| 96 | while True: |
| 97 | # Edge Case: If we can't go up anymore, we're at the root |
| 98 | parent = current.up() |
| 99 | if parent is None: |
| 100 | break |
| 101 | current = parent |
| 102 | return current.tree |
| 103 | # Handled Edge Cases: None tree input, missing children, already at root, malformed tree structure |