diff --git a/workspaces/adventure-pack/goodies/python3/src/traverse_postorder/__init__.py b/workspaces/adventure-pack/goodies/python3/src/traverse_postorder/__init__.py new file mode 100644 index 00000000..df2a821e --- /dev/null +++ b/workspaces/adventure-pack/goodies/python3/src/traverse_postorder/__init__.py @@ -0,0 +1,30 @@ +from typing import Generator, Optional + + +class TreeNode: + def __init__( + self, + val: int = 0, + left: Optional["TreeNode"] = None, + right: Optional["TreeNode"] = None, + ): + self.val = val + self.left = left + self.right = right + + +def traverse_postorder( + root: Optional[TreeNode], +) -> Generator[TreeNode, None, None]: + stack = [(root, False)] if root else [] + while stack: + node, did_traverse_children = stack.pop() + if did_traverse_children: + yield node + continue + + stack.append((node, True)) + if node.right: + stack.append((node.right, False)) + if node.left: + stack.append((node.left, False)) diff --git a/workspaces/adventure-pack/goodies/python3/src/traverse_postorder/goody.json b/workspaces/adventure-pack/goodies/python3/src/traverse_postorder/goody.json new file mode 100644 index 00000000..eb00d32e --- /dev/null +++ b/workspaces/adventure-pack/goodies/python3/src/traverse_postorder/goody.json @@ -0,0 +1,3 @@ +{ + "name": "traverse_postorder" +} diff --git a/workspaces/adventure-pack/goodies/python3/src/traverse_postorder/test.py b/workspaces/adventure-pack/goodies/python3/src/traverse_postorder/test.py new file mode 100644 index 00000000..bbe67841 --- /dev/null +++ b/workspaces/adventure-pack/goodies/python3/src/traverse_postorder/test.py @@ -0,0 +1,82 @@ +from . import * + + +def test_empty_tree() -> None: + assert list(traverse_postorder(None)) == [] + + +def test_root_only() -> None: + root = TreeNode(10) + assert [node.val for node in traverse_postorder(root)] == [10] + + +def test_left_child_only() -> None: + root = TreeNode(10) + root.left = TreeNode(4) + assert [node.val for node in traverse_postorder(root)] == [4, 10] + + +def test_right_child_only() -> None: + root = TreeNode(10) + root.right = TreeNode(6) + assert [node.val for node in traverse_postorder(root)] == [6, 10] + + +def test_unbalanced_tree() -> None: + root = TreeNode(2) + root.left = TreeNode(4) + root.right = TreeNode(5) + root.left.left = TreeNode(7) + root.left.right = TreeNode(8) + root.left.left.left = TreeNode(10) + + assert [node.val for node in traverse_postorder(root)] == [ + 10, + 7, + 8, + 4, + 5, + 2, + ] + + +def test_large_tree() -> None: + root = TreeNode(1) + root.left = TreeNode(2) + root.right = TreeNode(3) + root.left.left = TreeNode(4) + root.left.right = TreeNode(5) + root.right.left = TreeNode(6) + root.right.right = TreeNode(7) + root.left.left.left = TreeNode(8) + root.left.left.right = TreeNode(9) + root.left.right.left = TreeNode(10) + root.left.right.right = TreeNode(11) + + assert [node.val for node in traverse_postorder(root)] == [ + 8, + 9, + 4, + 10, + 11, + 5, + 2, + 6, + 7, + 3, + 1, + ] + + +# TODO: delete test case once types are enforced for python goodies +def test_traverse_generator() -> None: + root = TreeNode(1) + root.left = TreeNode(2) + root.right = TreeNode(3) + root.left.left = TreeNode(4) + + traverse = traverse_postorder(root) + assert next(traverse).val == 4 + assert next(traverse).val == 2 + assert next(traverse).val == 3 + assert next(traverse).val == 1 diff --git a/workspaces/adventure-pack/goodies/python3/src/traverse_preorder/test.py b/workspaces/adventure-pack/goodies/python3/src/traverse_preorder/test.py index 94c7e865..5e3e2e70 100644 --- a/workspaces/adventure-pack/goodies/python3/src/traverse_preorder/test.py +++ b/workspaces/adventure-pack/goodies/python3/src/traverse_preorder/test.py @@ -61,6 +61,7 @@ def test_large_tree() -> None: ] +# TODO: delete test case once types are enforced for python goodies def test_traverse_generator() -> None: root = TreeNode(1) root.left = TreeNode(2) diff --git a/workspaces/adventure-pack/src/app/__tests__/__snapshots__/equip-test.ts.snap b/workspaces/adventure-pack/src/app/__tests__/__snapshots__/equip-test.ts.snap index c4483bcc..fd75986e 100644 --- a/workspaces/adventure-pack/src/app/__tests__/__snapshots__/equip-test.ts.snap +++ b/workspaces/adventure-pack/src/app/__tests__/__snapshots__/equip-test.ts.snap @@ -2321,6 +2321,45 @@ def is_palindrome(sequence: list | str) -> bool: ########################### END ADVENTURE PACK CODE ############################" `; +exports[`App can equip single goody: Python 3 traverse_postorder 1`] = ` +"########################## BEGIN ADVENTURE PACK CODE ########################### +# Adventure Pack commit fake-commit-hash +# Running at: https://example.com/ + +from typing import Generator, Optional + + +class TreeNode: + def __init__( + self, + val: int = 0, + left: Optional["TreeNode"] = None, + right: Optional["TreeNode"] = None, + ): + self.val = val + self.left = left + self.right = right + + +def traverse_postorder( + root: Optional[TreeNode], +) -> Generator[TreeNode, None, None]: + stack = [(root, False)] if root else [] + while stack: + node, did_traverse_children = stack.pop() + if did_traverse_children: + yield node + continue + + stack.append((node, True)) + if node.right: + stack.append((node.right, False)) + if node.left: + stack.append((node.left, False)) + +########################### END ADVENTURE PACK CODE ############################" +`; + exports[`App can equip single goody: Python 3 traverse_preorder 1`] = ` "########################## BEGIN ADVENTURE PACK CODE ########################### # Adventure Pack commit fake-commit-hash diff --git a/workspaces/adventure-pack/src/app/__tests__/__snapshots__/render-test.ts.snap b/workspaces/adventure-pack/src/app/__tests__/__snapshots__/render-test.ts.snap index e9704e85..3bb3edee 100644 --- a/workspaces/adventure-pack/src/app/__tests__/__snapshots__/render-test.ts.snap +++ b/workspaces/adventure-pack/src/app/__tests__/__snapshots__/render-test.ts.snap @@ -1343,6 +1343,39 @@ exports[`App can render goody: Python 3 is_palindrome 1`] = ` return True" `; +exports[`App can render goody: Python 3 traverse_postorder 1`] = ` +"from typing import Generator, Optional + + +class TreeNode: + def __init__( + self, + val: int = 0, + left: Optional["TreeNode"] = None, + right: Optional["TreeNode"] = None, + ): + self.val = val + self.left = left + self.right = right + + +def traverse_postorder( + root: Optional[TreeNode], +) -> Generator[TreeNode, None, None]: + stack = [(root, False)] if root else [] + while stack: + node, did_traverse_children = stack.pop() + if did_traverse_children: + yield node + continue + + stack.append((node, True)) + if node.right: + stack.append((node.right, False)) + if node.left: + stack.append((node.left, False))" +`; + exports[`App can render goody: Python 3 traverse_preorder 1`] = ` "from typing import Generator, Optional