From 915a3472c3152dfea8d649e746e23909a37b997f Mon Sep 17 00:00:00 2001 From: Nenad Date: Sat, 2 Nov 2024 17:05:29 +0100 Subject: [PATCH 01/12] Make 1st 6 tests pass --- config.json | 8 + .../practice/zipper/.docs/instructions.md | 27 ++++ exercises/practice/zipper/.meta/config.json | 15 ++ exercises/practice/zipper/.meta/example.cairo | 0 exercises/practice/zipper/.meta/tests.toml | 52 ++++++ exercises/practice/zipper/Scarb.toml | 7 + exercises/practice/zipper/src/lib.cairo | 150 ++++++++++++++++++ exercises/practice/zipper/tests/zipper.cairo | 85 ++++++++++ 8 files changed, 344 insertions(+) create mode 100644 exercises/practice/zipper/.docs/instructions.md create mode 100644 exercises/practice/zipper/.meta/config.json create mode 100644 exercises/practice/zipper/.meta/example.cairo create mode 100644 exercises/practice/zipper/.meta/tests.toml create mode 100644 exercises/practice/zipper/Scarb.toml create mode 100644 exercises/practice/zipper/src/lib.cairo create mode 100644 exercises/practice/zipper/tests/zipper.cairo diff --git a/config.json b/config.json index 2229d4a4..b007c0fd 100644 --- a/config.json +++ b/config.json @@ -827,6 +827,14 @@ "practices": [], "prerequisites": [], "difficulty": 4 + }, + { + "slug": "zipper", + "name": "Zipper", + "uuid": "61120275-6457-43ce-b40b-7e86a18b7f5b", + "practices": [], + "prerequisites": [], + "difficulty": 1 } ], "foregone": [ diff --git a/exercises/practice/zipper/.docs/instructions.md b/exercises/practice/zipper/.docs/instructions.md new file mode 100644 index 00000000..5445db00 --- /dev/null +++ b/exercises/practice/zipper/.docs/instructions.md @@ -0,0 +1,27 @@ +# Instructions + +Creating a zipper for a binary tree. + +[Zippers][zipper] are a purely functional way of navigating within a data structure and manipulating it. +They essentially contain a data structure and a pointer into that data structure (called the focus). + +For example given a rose tree (where each node contains a value and a list of child nodes) a zipper might support these operations: + +- `from_tree` (get a zipper out of a rose tree, the focus is on the root node) +- `to_tree` (get the rose tree out of the zipper) +- `value` (get the value of the focus node) +- `prev` (move the focus to the previous child of the same parent, + returns a new zipper) +- `next` (move the focus to the next child of the same parent, returns a + new zipper) +- `up` (move the focus to the parent, returns a new zipper) +- `set_value` (set the value of the focus node, returns a new zipper) +- `insert_before` (insert a new subtree before the focus node, it + becomes the `prev` of the focus node, returns a new zipper) +- `insert_after` (insert a new subtree after the focus node, it becomes + the `next` of the focus node, returns a new zipper) +- `delete` (removes the focus node and all subtrees, focus moves to the + `next` node if possible otherwise to the `prev` node if possible, + otherwise to the parent node, returns a new zipper) + +[zipper]: https://en.wikipedia.org/wiki/Zipper_%28data_structure%29 diff --git a/exercises/practice/zipper/.meta/config.json b/exercises/practice/zipper/.meta/config.json new file mode 100644 index 00000000..71c68622 --- /dev/null +++ b/exercises/practice/zipper/.meta/config.json @@ -0,0 +1,15 @@ +{ + "authors": [], + "files": { + "solution": [ + "src/lib.cairo" + ], + "test": [ + "tests/zipper.cairo" + ], + "example": [ + ".meta/example.cairo" + ] + }, + "blurb": "Creating a zipper for a binary tree." +} diff --git a/exercises/practice/zipper/.meta/example.cairo b/exercises/practice/zipper/.meta/example.cairo new file mode 100644 index 00000000..e69de29b diff --git a/exercises/practice/zipper/.meta/tests.toml b/exercises/practice/zipper/.meta/tests.toml new file mode 100644 index 00000000..e93932b1 --- /dev/null +++ b/exercises/practice/zipper/.meta/tests.toml @@ -0,0 +1,52 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[771c652e-0754-4ef0-945c-0675d12ef1f5] +description = "data is retained" + +[d7dcbb92-47fc-4d01-b81a-df3353bc09ff] +description = "left, right and value" + +[613d8286-b05c-4453-b205-e6f9c5966339] +description = "dead end" + +[dda31af7-1c68-4e29-933a-c9d198d94284] +description = "tree from deep focus" + +[1e3072a6-f85b-430b-b014-cdb4087e3577] +description = "traversing up from top" + +[b8505f6a-aed4-4c2e-824f-a0ed8570d74b] +description = "left, right, and up" + +[b9aa8d54-07b7-4bfd-ab6b-7ff7f35930b6] +description = "test ability to descend multiple levels and return" + +[47df1a27-b709-496e-b381-63a03b82ea5f] +description = "set_value" + +[16a1f1a8-dbed-456d-95ac-1cbb6093e0ab] +description = "set_value after traversing up" + +[535a91af-a02e-49cd-8d2c-ecb6e4647174] +description = "set_left with leaf" + +[b3f60c4b-a788-4ffd-be5d-1e69aee61de3] +description = "set_right with null" + +[e91c221d-7b90-4604-b4ec-46638a673a12] +description = "set_right with subtree" + +[c246be85-6648-4e9c-866f-b08cd495149a] +description = "set_value on deep focus" + +[47aa85a0-5240-48a4-9f42-e2ac636710ea] +description = "different paths to same zipper" diff --git a/exercises/practice/zipper/Scarb.toml b/exercises/practice/zipper/Scarb.toml new file mode 100644 index 00000000..d34df34b --- /dev/null +++ b/exercises/practice/zipper/Scarb.toml @@ -0,0 +1,7 @@ +[package] +name = "zipper" +version = "0.1.0" +edition = "2024_07" + +[dev-dependencies] +cairo_test = "2.8.2" diff --git a/exercises/practice/zipper/src/lib.cairo b/exercises/practice/zipper/src/lib.cairo new file mode 100644 index 00000000..477248b9 --- /dev/null +++ b/exercises/practice/zipper/src/lib.cairo @@ -0,0 +1,150 @@ +pub type BinaryTree = Option>; + +#[derive(Drop, Debug, PartialEq, Copy)] +pub struct Node { + value: u32, + left: BinaryTree, + right: BinaryTree, +} + +pub impl BinaryTreePartialEq of PartialEq>> { + fn eq(lhs: @Option>, rhs: @Option>) -> bool { + match (lhs, rhs) { + (Option::Some(lhs), Option::Some(rhs)) => (*lhs).unbox() == (*rhs).unbox(), + (Option::None, Option::None) => true, + _ => false + } + } +} + +impl NodeIntoBinaryTree of Into { + fn into(self: Node) -> BinaryTree { + Option::Some(BoxTrait::new(self)) + } +} + +#[generate_trait] +impl NodeImpl of NodeTrait { + fn with_left(self: Node, left: BinaryTree) -> Node { + Node { left, ..self } + } + + fn with_right(self: Node, right: BinaryTree) -> Node { + Node { right, ..self } + } +} + +#[generate_trait] +pub impl BinaryTreeImpl of BinaryTreeTrait { + fn new(value: u32, left: BinaryTree, right: BinaryTree) -> BinaryTree { + Option::Some(BoxTrait::new(Node { value, left, right })) + } + + fn value(self: @BinaryTree) -> Option { + Option::Some((*self)?.value) + } + + fn left(self: @BinaryTree) -> @BinaryTree { + @match self { + Option::None => Option::None, + Option::Some(bst) => bst.left + } + } + + fn right(self: @BinaryTree) -> @BinaryTree { + @match self { + Option::None => Option::None, + Option::Some(bst) => bst.right + } + } +} + +#[derive(Drop, Copy)] +enum Path { + Left, + Right +} + +#[derive(Drop, Copy)] +struct Ancestor { + path: Path, + node: Node +} + +#[derive(Drop, Copy)] +struct Zipper { + tree: BinaryTree, + ancestors: Span +} + +#[generate_trait] +pub impl ZipperImpl of ZipperTrait { + fn from_tree(tree: BinaryTree) -> Zipper { + Self::init(tree, array![].span()) + } + + fn init(tree: BinaryTree, ancestors: Span) -> Zipper { + Zipper { tree, ancestors } + } + + fn to_tree(self: Zipper) -> BinaryTree { + if self.ancestors.is_empty() { + self.tree + } else { + (*self.ancestors[0]).node.into() + } + } + + fn value(self: @Zipper) -> Option { + self.tree.value() + } + + fn left(self: Zipper) -> Option { + Option::Some( + Self::init( + Option::Some((*self.tree.left())?), + self + .ancestors + .append(Ancestor { path: Path::Left, node: self.tree.unwrap().unbox() }) + ) + ) + } + + fn right(self: Zipper) -> Option { + Option::Some( + Self::init( + Option::Some((*self.tree.right())?), + self + .ancestors + .append(Ancestor { path: Path::Right, node: self.tree.unwrap().unbox() }) + ) + ) + } + + fn up(self: Zipper) -> Option { + if self.ancestors.is_empty() { + Option::None + } else { + let mut ancestors = self.ancestors; + Option::Some( + Self::init(Self::from_trail(self.tree, *ancestors.pop_back().unwrap()), ancestors) + ) + } + } + + fn from_trail(tree: BinaryTree, ancestor: Ancestor) -> BinaryTree { + match ancestor.path { + Path::Left => ancestor.node.with_left(tree).into(), + Path::Right => ancestor.node.with_right(tree).into(), + } + } +} + +#[generate_trait] +impl SpanAppendImpl of SpanAppendTrait { + fn append, +Clone>(self: Span, value: T) -> Span { + let mut arr: Array = self.into(); + arr.append(value); + arr.span() + } +} diff --git a/exercises/practice/zipper/tests/zipper.cairo b/exercises/practice/zipper/tests/zipper.cairo new file mode 100644 index 00000000..e93e4023 --- /dev/null +++ b/exercises/practice/zipper/tests/zipper.cairo @@ -0,0 +1,85 @@ +use zipper::{ZipperTrait as Zipper, BinaryTreeTrait as BinaryTree, BinaryTreePartialEq}; + +#[test] +fn data_is_retained() { + let initial_tree = BinaryTree::new( + 1, + BinaryTree::new(2, Option::None, BinaryTree::new(3, Option::None, Option::None)), + BinaryTree::new(4, Option::None, Option::None) + ); + let expected = initial_tree.clone(); + let zipper = Zipper::from_tree(initial_tree); + assert_eq!(expected, zipper.to_tree()); +} + +#[test] +fn left_right_and_value() { + let initial_tree = BinaryTree::new( + 1, + BinaryTree::new(2, Option::None, BinaryTree::new(3, Option::None, Option::None)), + BinaryTree::new(4, Option::None, Option::None) + ); + let zipper = Zipper::from_tree(initial_tree); + assert_eq!(Option::Some(3), zipper.left().unwrap().right().unwrap().value()); +} + +#[test] +fn dead_end() { + let initial_tree = BinaryTree::new( + 1, + BinaryTree::new(2, Option::None, BinaryTree::new(3, Option::None, Option::None)), + BinaryTree::new(4, Option::None, Option::None) + ); + let zipper = Zipper::from_tree(initial_tree); + assert!(zipper.left().unwrap().left().is_none()); +} + +#[test] +fn tree_from_deep_focus() { + let initial_tree = BinaryTree::new( + 1, + BinaryTree::new(2, Option::None, BinaryTree::new(3, Option::None, Option::None)), + BinaryTree::new(4, Option::None, Option::None) + ); + let expected = initial_tree.clone(); + let zipper = Zipper::from_tree(initial_tree); + assert_eq!(expected, zipper.left().unwrap().right().unwrap().to_tree()); +} + +#[test] +fn traversing_up_from_top() { + let initial_tree = BinaryTree::new( + 1, + BinaryTree::new(2, Option::None, BinaryTree::new(3, Option::None, Option::None)), + BinaryTree::new(4, Option::None, Option::None) + ); + let zipper = Zipper::from_tree(initial_tree); + assert!(zipper.up().is_none()); +} + +#[test] +fn left_right_and_up() { + let initial_tree = BinaryTree::new( + 1, + BinaryTree::new(2, Option::None, BinaryTree::new(3, Option::None, Option::None)), + BinaryTree::new(4, Option::None, Option::None) + ); + let zipper = Zipper::from_tree(initial_tree); + assert_eq!( + Option::Some(3), + zipper + .left() + .unwrap() + .up() + .unwrap() + .right() + .unwrap() + .up() + .unwrap() + .left() + .unwrap() + .right() + .unwrap() + .value() + ); +} From 9fe7390eb99ffe1be99cfc7374d365c41cdb6f47 Mon Sep 17 00:00:00 2001 From: Nenad Date: Sun, 3 Nov 2024 19:59:40 +0100 Subject: [PATCH 02/12] implement set_value + fix to_tree --- exercises/practice/zipper/src/lib.cairo | 31 ++++++++++++++++---- exercises/practice/zipper/tests/zipper.cairo | 29 ++++++++++++++++++ 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/exercises/practice/zipper/src/lib.cairo b/exercises/practice/zipper/src/lib.cairo index 477248b9..a6ecbd9b 100644 --- a/exercises/practice/zipper/src/lib.cairo +++ b/exercises/practice/zipper/src/lib.cairo @@ -25,6 +25,10 @@ impl NodeIntoBinaryTree of Into { #[generate_trait] impl NodeImpl of NodeTrait { + fn with_value(self: Node, right: BinaryTree) -> Node { + Node { right, ..self } + } + fn with_left(self: Node, left: BinaryTree) -> Node { Node { left, ..self } } @@ -40,6 +44,10 @@ pub impl BinaryTreeImpl of BinaryTreeTrait { Option::Some(BoxTrait::new(Node { value, left, right })) } + fn set_value(self: BinaryTree, value: u32) -> BinaryTree { + Self::new(value, *self.left(), *self.right()) + } + fn value(self: @BinaryTree) -> Option { Option::Some((*self)?.value) } @@ -87,14 +95,19 @@ pub impl ZipperImpl of ZipperTrait { Zipper { tree, ancestors } } - fn to_tree(self: Zipper) -> BinaryTree { - if self.ancestors.is_empty() { - self.tree + fn rebuild_tree(tree: BinaryTree, ancestors: Span) -> BinaryTree { + let mut ancestors = ancestors; + if let Option::Some(last) = ancestors.pop_back() { + Self::rebuild_tree(Self::from_ancestor(tree, *last), ancestors) } else { - (*self.ancestors[0]).node.into() + tree } } + fn to_tree(self: Zipper) -> BinaryTree { + Self::rebuild_tree(self.tree, self.ancestors) + } + fn value(self: @Zipper) -> Option { self.tree.value() } @@ -127,17 +140,23 @@ pub impl ZipperImpl of ZipperTrait { } else { let mut ancestors = self.ancestors; Option::Some( - Self::init(Self::from_trail(self.tree, *ancestors.pop_back().unwrap()), ancestors) + Self::init( + Self::from_ancestor(self.tree, *ancestors.pop_back().unwrap()), ancestors + ) ) } } - fn from_trail(tree: BinaryTree, ancestor: Ancestor) -> BinaryTree { + fn from_ancestor(tree: BinaryTree, ancestor: Ancestor) -> BinaryTree { match ancestor.path { Path::Left => ancestor.node.with_left(tree).into(), Path::Right => ancestor.node.with_right(tree).into(), } } + + fn set_value(self: Zipper, value: u32) -> Zipper { + Self::init(self.tree.set_value(value), self.ancestors) + } } #[generate_trait] diff --git a/exercises/practice/zipper/tests/zipper.cairo b/exercises/practice/zipper/tests/zipper.cairo index e93e4023..178a36d1 100644 --- a/exercises/practice/zipper/tests/zipper.cairo +++ b/exercises/practice/zipper/tests/zipper.cairo @@ -83,3 +83,32 @@ fn left_right_and_up() { .value() ); } + +#[test] +fn test_ability_to_descend_multiple_levels_and_return() { + let initial_tree = BinaryTree::new( + 1, + BinaryTree::new(2, Option::None, BinaryTree::new(3, Option::None, Option::None)), + BinaryTree::new(4, Option::None, Option::None) + ); + let zipper = Zipper::from_tree(initial_tree); + assert_eq!( + Option::Some(1), zipper.left().unwrap().right().unwrap().up().unwrap().up().unwrap().value() + ); +} + +#[test] +fn set_value() { + let initial_tree = BinaryTree::new( + 1, + BinaryTree::new(2, Option::None, BinaryTree::new(3, Option::None, Option::None)), + BinaryTree::new(4, Option::None, Option::None) + ); + let expected = BinaryTree::new( + 1, + BinaryTree::new(5, Option::None, BinaryTree::new(3, Option::None, Option::None)), + BinaryTree::new(4, Option::None, Option::None) + ); + let zipper = Zipper::from_tree(initial_tree); + assert_eq!(expected, zipper.left().unwrap().set_value(5).to_tree()); +} From e634a46d75ebd618026deb5a702327638424f3cb Mon Sep 17 00:00:00 2001 From: Nenad Date: Sun, 3 Nov 2024 20:01:45 +0100 Subject: [PATCH 03/12] refactor up --- exercises/practice/zipper/src/lib.cairo | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/exercises/practice/zipper/src/lib.cairo b/exercises/practice/zipper/src/lib.cairo index a6ecbd9b..83e8aa19 100644 --- a/exercises/practice/zipper/src/lib.cairo +++ b/exercises/practice/zipper/src/lib.cairo @@ -135,16 +135,9 @@ pub impl ZipperImpl of ZipperTrait { } fn up(self: Zipper) -> Option { - if self.ancestors.is_empty() { - Option::None - } else { - let mut ancestors = self.ancestors; - Option::Some( - Self::init( - Self::from_ancestor(self.tree, *ancestors.pop_back().unwrap()), ancestors - ) - ) - } + let mut ancestors = self.ancestors; + let ancestor = *ancestors.pop_back()?; + Option::Some(Self::init(Self::from_ancestor(self.tree, ancestor), ancestors)) } fn from_ancestor(tree: BinaryTree, ancestor: Ancestor) -> BinaryTree { From 4d48de10b248507ab3ae63ff7866d026e4227c95 Mon Sep 17 00:00:00 2001 From: Nenad Date: Sun, 3 Nov 2024 20:02:40 +0100 Subject: [PATCH 04/12] set_value_after_traversing_up --- exercises/practice/zipper/tests/zipper.cairo | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/exercises/practice/zipper/tests/zipper.cairo b/exercises/practice/zipper/tests/zipper.cairo index 178a36d1..fb197b37 100644 --- a/exercises/practice/zipper/tests/zipper.cairo +++ b/exercises/practice/zipper/tests/zipper.cairo @@ -112,3 +112,21 @@ fn set_value() { let zipper = Zipper::from_tree(initial_tree); assert_eq!(expected, zipper.left().unwrap().set_value(5).to_tree()); } + +#[test] +fn set_value_after_traversing_up() { + let initial_tree = BinaryTree::new( + 1, + BinaryTree::new(2, Option::None, BinaryTree::new(3, Option::None, Option::None)), + BinaryTree::new(4, Option::None, Option::None) + ); + let expected = BinaryTree::new( + 1, + BinaryTree::new(5, Option::None, BinaryTree::new(3, Option::None, Option::None)), + BinaryTree::new(4, Option::None, Option::None) + ); + let zipper = Zipper::from_tree(initial_tree); + assert_eq!( + expected, zipper.left().unwrap().right().unwrap().up().unwrap().set_value(5).to_tree() + ); +} From 45846183c138e1d1c14a7e76b065471697a2747e Mon Sep 17 00:00:00 2001 From: Nenad Date: Sun, 3 Nov 2024 20:09:03 +0100 Subject: [PATCH 05/12] Implement set_left + set_right --- exercises/practice/zipper/src/lib.cairo | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/exercises/practice/zipper/src/lib.cairo b/exercises/practice/zipper/src/lib.cairo index 83e8aa19..d3463085 100644 --- a/exercises/practice/zipper/src/lib.cairo +++ b/exercises/practice/zipper/src/lib.cairo @@ -48,6 +48,7 @@ pub impl BinaryTreeImpl of BinaryTreeTrait { Self::new(value, *self.left(), *self.right()) } + // TODO: return snapshot of value fn value(self: @BinaryTree) -> Option { Option::Some((*self)?.value) } @@ -148,7 +149,23 @@ pub impl ZipperImpl of ZipperTrait { } fn set_value(self: Zipper, value: u32) -> Zipper { - Self::init(self.tree.set_value(value), self.ancestors) + Self::init( + BinaryTreeTrait::new(value, *self.tree.left(), *self.tree.right()), self.ancestors + ) + } + + fn set_left(self: Zipper, left: BinaryTree) -> Zipper { + Self::init( + BinaryTreeTrait::new(self.tree.value().unwrap(), left, *self.tree.right()), + self.ancestors + ) + } + + fn set_right(self: Zipper, right: BinaryTree) -> Zipper { + Self::init( + BinaryTreeTrait::new(self.tree.value().unwrap(), *self.tree.left(), right), + self.ancestors + ) } } From bdf36f5f3761f38fa7db2d082e12057442dedeac Mon Sep 17 00:00:00 2001 From: Nenad Date: Sun, 3 Nov 2024 22:40:06 +0100 Subject: [PATCH 06/12] implement all tests --- exercises/practice/zipper/src/lib.cairo | 14 ++- exercises/practice/zipper/tests/zipper.cairo | 89 ++++++++++++++++++++ 2 files changed, 100 insertions(+), 3 deletions(-) diff --git a/exercises/practice/zipper/src/lib.cairo b/exercises/practice/zipper/src/lib.cairo index d3463085..ffa6f7ee 100644 --- a/exercises/practice/zipper/src/lib.cairo +++ b/exercises/practice/zipper/src/lib.cairo @@ -40,10 +40,18 @@ impl NodeImpl of NodeTrait { #[generate_trait] pub impl BinaryTreeImpl of BinaryTreeTrait { + fn empty() -> BinaryTree { + Option::None + } + fn new(value: u32, left: BinaryTree, right: BinaryTree) -> BinaryTree { Option::Some(BoxTrait::new(Node { value, left, right })) } + fn leaf(value: u32) -> BinaryTree { + Option::Some(BoxTrait::new(Node { value, left: Self::empty(), right: Self::empty() })) + } + fn set_value(self: BinaryTree, value: u32) -> BinaryTree { Self::new(value, *self.left(), *self.right()) } @@ -68,19 +76,19 @@ pub impl BinaryTreeImpl of BinaryTreeTrait { } } -#[derive(Drop, Copy)] +#[derive(Drop, Copy, Debug, PartialEq)] enum Path { Left, Right } -#[derive(Drop, Copy)] +#[derive(Drop, Copy, Debug, PartialEq)] struct Ancestor { path: Path, node: Node } -#[derive(Drop, Copy)] +#[derive(Drop, Copy, Debug, PartialEq)] struct Zipper { tree: BinaryTree, ancestors: Span diff --git a/exercises/practice/zipper/tests/zipper.cairo b/exercises/practice/zipper/tests/zipper.cairo index fb197b37..73671ef9 100644 --- a/exercises/practice/zipper/tests/zipper.cairo +++ b/exercises/practice/zipper/tests/zipper.cairo @@ -125,8 +125,97 @@ fn set_value_after_traversing_up() { BinaryTree::new(5, Option::None, BinaryTree::new(3, Option::None, Option::None)), BinaryTree::new(4, Option::None, Option::None) ); + let zipper = Zipper::from_tree(initial_tree); + assert_eq!( expected, zipper.left().unwrap().right().unwrap().up().unwrap().set_value(5).to_tree() ); } + +#[test] +fn set_left_with_leaf() { + let initial_tree = BinaryTree::new( + 1, + BinaryTree::new(2, Option::None, BinaryTree::new(3, Option::None, Option::None)), + BinaryTree::new(4, Option::None, Option::None) + ); + let expected = BinaryTree::new( + 1, + BinaryTree::new( + 2, + BinaryTree::new(5, Option::None, Option::None), + BinaryTree::new(3, Option::None, Option::None) + ), + BinaryTree::new(4, Option::None, Option::None) + ); + + let zipper = Zipper::from_tree(initial_tree); + + assert_eq!( + expected, + zipper.left().unwrap().set_left(BinaryTree::new(5, Option::None, Option::None)).to_tree() + ); +} + +#[test] +fn set_right_with_leaf() { + let initial_tree = BinaryTree::new( + 1, + BinaryTree::new(2, Option::None, BinaryTree::new(3, Option::None, Option::None)), + BinaryTree::new(4, Option::None, Option::None) + ); + let expected = BinaryTree::new( + 1, + BinaryTree::new(2, BinaryTree::empty(), BinaryTree::empty()), + BinaryTree::new(4, BinaryTree::empty(), BinaryTree::empty()) + ); + + let zipper = Zipper::from_tree(initial_tree); + + assert_eq!(expected, zipper.left().unwrap().set_right(BinaryTree::empty()).to_tree()); +} + +#[test] +fn set_right_with_subtree() { + let initial_tree = BinaryTree::new( + 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) + ); + let expected = BinaryTree::new( + 1, + BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), + BinaryTree::new(6, BinaryTree::leaf(7), BinaryTree::leaf(8)) + ); + + let zipper = Zipper::from_tree(initial_tree); + + assert_eq!( + expected, + zipper.set_right(BinaryTree::new(6, BinaryTree::leaf(7), BinaryTree::leaf(8))).to_tree() + ); +} + +#[test] +fn set_value_on_deep_focus() { + let initial_tree = BinaryTree::new( + 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) + ); + let expected = BinaryTree::new( + 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(5)), BinaryTree::leaf(4) + ); + + let zipper = Zipper::from_tree(initial_tree); + + assert_eq!(expected, zipper.left().unwrap().right().unwrap().set_value(5).to_tree()); +} + +#[test] +fn different_paths_to_same_zipper() { + let initial_tree = BinaryTree::new( + 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) + ); + let expected = Zipper::from_tree(initial_tree).right(); + let actual = Zipper::from_tree(initial_tree).left().unwrap().up().unwrap().right(); + + assert_eq!(expected, actual); +} From 05553b4bc2de7ec169602755b7be5bcb2de0166b Mon Sep 17 00:00:00 2001 From: Nenad Date: Sun, 3 Nov 2024 22:54:11 +0100 Subject: [PATCH 07/12] Refactor --- exercises/practice/zipper/src/lib.cairo | 66 +++++++++--------- exercises/practice/zipper/tests/zipper.cairo | 71 +++++--------------- 2 files changed, 49 insertions(+), 88 deletions(-) diff --git a/exercises/practice/zipper/src/lib.cairo b/exercises/practice/zipper/src/lib.cairo index ffa6f7ee..7a19a74e 100644 --- a/exercises/practice/zipper/src/lib.cairo +++ b/exercises/practice/zipper/src/lib.cairo @@ -17,12 +17,6 @@ pub impl BinaryTreePartialEq of PartialEq>> { } } -impl NodeIntoBinaryTree of Into { - fn into(self: Node) -> BinaryTree { - Option::Some(BoxTrait::new(self)) - } -} - #[generate_trait] impl NodeImpl of NodeTrait { fn with_value(self: Node, right: BinaryTree) -> Node { @@ -38,6 +32,12 @@ impl NodeImpl of NodeTrait { } } +impl NodeIntoBinaryTree of Into { + fn into(self: Node) -> BinaryTree { + Option::Some(BoxTrait::new(self)) + } +} + #[generate_trait] pub impl BinaryTreeImpl of BinaryTreeTrait { fn empty() -> BinaryTree { @@ -49,7 +49,7 @@ pub impl BinaryTreeImpl of BinaryTreeTrait { } fn leaf(value: u32) -> BinaryTree { - Option::Some(BoxTrait::new(Node { value, left: Self::empty(), right: Self::empty() })) + Self::new(value, Self::empty(), Self::empty()) } fn set_value(self: BinaryTree, value: u32) -> BinaryTree { @@ -96,25 +96,16 @@ struct Zipper { #[generate_trait] pub impl ZipperImpl of ZipperTrait { - fn from_tree(tree: BinaryTree) -> Zipper { - Self::init(tree, array![].span()) - } - - fn init(tree: BinaryTree, ancestors: Span) -> Zipper { + fn new(tree: BinaryTree, ancestors: Span) -> Zipper { Zipper { tree, ancestors } } - fn rebuild_tree(tree: BinaryTree, ancestors: Span) -> BinaryTree { - let mut ancestors = ancestors; - if let Option::Some(last) = ancestors.pop_back() { - Self::rebuild_tree(Self::from_ancestor(tree, *last), ancestors) - } else { - tree - } + fn from_tree(tree: BinaryTree) -> Zipper { + Self::new(tree, array![].span()) } fn to_tree(self: Zipper) -> BinaryTree { - Self::rebuild_tree(self.tree, self.ancestors) + rebuild_tree(self.tree, self.ancestors) } fn value(self: @Zipper) -> Option { @@ -123,7 +114,7 @@ pub impl ZipperImpl of ZipperTrait { fn left(self: Zipper) -> Option { Option::Some( - Self::init( + Self::new( Option::Some((*self.tree.left())?), self .ancestors @@ -134,7 +125,7 @@ pub impl ZipperImpl of ZipperTrait { fn right(self: Zipper) -> Option { Option::Some( - Self::init( + Self::new( Option::Some((*self.tree.right())?), self .ancestors @@ -146,37 +137,46 @@ pub impl ZipperImpl of ZipperTrait { fn up(self: Zipper) -> Option { let mut ancestors = self.ancestors; let ancestor = *ancestors.pop_back()?; - Option::Some(Self::init(Self::from_ancestor(self.tree, ancestor), ancestors)) - } - - fn from_ancestor(tree: BinaryTree, ancestor: Ancestor) -> BinaryTree { - match ancestor.path { - Path::Left => ancestor.node.with_left(tree).into(), - Path::Right => ancestor.node.with_right(tree).into(), - } + Option::Some(Self::new(from_ancestor(self.tree, ancestor), ancestors)) } fn set_value(self: Zipper, value: u32) -> Zipper { - Self::init( + Self::new( BinaryTreeTrait::new(value, *self.tree.left(), *self.tree.right()), self.ancestors ) } fn set_left(self: Zipper, left: BinaryTree) -> Zipper { - Self::init( + Self::new( BinaryTreeTrait::new(self.tree.value().unwrap(), left, *self.tree.right()), self.ancestors ) } fn set_right(self: Zipper, right: BinaryTree) -> Zipper { - Self::init( + Self::new( BinaryTreeTrait::new(self.tree.value().unwrap(), *self.tree.left(), right), self.ancestors ) } } +fn from_ancestor(tree: BinaryTree, ancestor: Ancestor) -> BinaryTree { + match ancestor.path { + Path::Left => ancestor.node.with_left(tree).into(), + Path::Right => ancestor.node.with_right(tree).into(), + } +} + +fn rebuild_tree(tree: BinaryTree, ancestors: Span) -> BinaryTree { + let mut ancestors = ancestors; + if let Option::Some(last) = ancestors.pop_back() { + rebuild_tree(from_ancestor(tree, *last), ancestors) + } else { + tree + } +} + #[generate_trait] impl SpanAppendImpl of SpanAppendTrait { fn append, +Clone>(self: Span, value: T) -> Span { diff --git a/exercises/practice/zipper/tests/zipper.cairo b/exercises/practice/zipper/tests/zipper.cairo index 73671ef9..ce643f67 100644 --- a/exercises/practice/zipper/tests/zipper.cairo +++ b/exercises/practice/zipper/tests/zipper.cairo @@ -3,9 +3,7 @@ use zipper::{ZipperTrait as Zipper, BinaryTreeTrait as BinaryTree, BinaryTreePar #[test] fn data_is_retained() { let initial_tree = BinaryTree::new( - 1, - BinaryTree::new(2, Option::None, BinaryTree::new(3, Option::None, Option::None)), - BinaryTree::new(4, Option::None, Option::None) + 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); let expected = initial_tree.clone(); let zipper = Zipper::from_tree(initial_tree); @@ -15,9 +13,7 @@ fn data_is_retained() { #[test] fn left_right_and_value() { let initial_tree = BinaryTree::new( - 1, - BinaryTree::new(2, Option::None, BinaryTree::new(3, Option::None, Option::None)), - BinaryTree::new(4, Option::None, Option::None) + 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); let zipper = Zipper::from_tree(initial_tree); assert_eq!(Option::Some(3), zipper.left().unwrap().right().unwrap().value()); @@ -26,9 +22,7 @@ fn left_right_and_value() { #[test] fn dead_end() { let initial_tree = BinaryTree::new( - 1, - BinaryTree::new(2, Option::None, BinaryTree::new(3, Option::None, Option::None)), - BinaryTree::new(4, Option::None, Option::None) + 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); let zipper = Zipper::from_tree(initial_tree); assert!(zipper.left().unwrap().left().is_none()); @@ -37,9 +31,7 @@ fn dead_end() { #[test] fn tree_from_deep_focus() { let initial_tree = BinaryTree::new( - 1, - BinaryTree::new(2, Option::None, BinaryTree::new(3, Option::None, Option::None)), - BinaryTree::new(4, Option::None, Option::None) + 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); let expected = initial_tree.clone(); let zipper = Zipper::from_tree(initial_tree); @@ -49,9 +41,7 @@ fn tree_from_deep_focus() { #[test] fn traversing_up_from_top() { let initial_tree = BinaryTree::new( - 1, - BinaryTree::new(2, Option::None, BinaryTree::new(3, Option::None, Option::None)), - BinaryTree::new(4, Option::None, Option::None) + 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); let zipper = Zipper::from_tree(initial_tree); assert!(zipper.up().is_none()); @@ -60,9 +50,7 @@ fn traversing_up_from_top() { #[test] fn left_right_and_up() { let initial_tree = BinaryTree::new( - 1, - BinaryTree::new(2, Option::None, BinaryTree::new(3, Option::None, Option::None)), - BinaryTree::new(4, Option::None, Option::None) + 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); let zipper = Zipper::from_tree(initial_tree); assert_eq!( @@ -87,9 +75,7 @@ fn left_right_and_up() { #[test] fn test_ability_to_descend_multiple_levels_and_return() { let initial_tree = BinaryTree::new( - 1, - BinaryTree::new(2, Option::None, BinaryTree::new(3, Option::None, Option::None)), - BinaryTree::new(4, Option::None, Option::None) + 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); let zipper = Zipper::from_tree(initial_tree); assert_eq!( @@ -100,14 +86,10 @@ fn test_ability_to_descend_multiple_levels_and_return() { #[test] fn set_value() { let initial_tree = BinaryTree::new( - 1, - BinaryTree::new(2, Option::None, BinaryTree::new(3, Option::None, Option::None)), - BinaryTree::new(4, Option::None, Option::None) + 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); let expected = BinaryTree::new( - 1, - BinaryTree::new(5, Option::None, BinaryTree::new(3, Option::None, Option::None)), - BinaryTree::new(4, Option::None, Option::None) + 1, BinaryTree::new(5, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); let zipper = Zipper::from_tree(initial_tree); assert_eq!(expected, zipper.left().unwrap().set_value(5).to_tree()); @@ -116,14 +98,10 @@ fn set_value() { #[test] fn set_value_after_traversing_up() { let initial_tree = BinaryTree::new( - 1, - BinaryTree::new(2, Option::None, BinaryTree::new(3, Option::None, Option::None)), - BinaryTree::new(4, Option::None, Option::None) + 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); let expected = BinaryTree::new( - 1, - BinaryTree::new(5, Option::None, BinaryTree::new(3, Option::None, Option::None)), - BinaryTree::new(4, Option::None, Option::None) + 1, BinaryTree::new(5, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); let zipper = Zipper::from_tree(initial_tree); @@ -136,40 +114,23 @@ fn set_value_after_traversing_up() { #[test] fn set_left_with_leaf() { let initial_tree = BinaryTree::new( - 1, - BinaryTree::new(2, Option::None, BinaryTree::new(3, Option::None, Option::None)), - BinaryTree::new(4, Option::None, Option::None) + 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); let expected = BinaryTree::new( - 1, - BinaryTree::new( - 2, - BinaryTree::new(5, Option::None, Option::None), - BinaryTree::new(3, Option::None, Option::None) - ), - BinaryTree::new(4, Option::None, Option::None) + 1, BinaryTree::new(2, BinaryTree::leaf(5), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); let zipper = Zipper::from_tree(initial_tree); - assert_eq!( - expected, - zipper.left().unwrap().set_left(BinaryTree::new(5, Option::None, Option::None)).to_tree() - ); + assert_eq!(expected, zipper.left().unwrap().set_left(BinaryTree::leaf(5)).to_tree()); } #[test] fn set_right_with_leaf() { let initial_tree = BinaryTree::new( - 1, - BinaryTree::new(2, Option::None, BinaryTree::new(3, Option::None, Option::None)), - BinaryTree::new(4, Option::None, Option::None) - ); - let expected = BinaryTree::new( - 1, - BinaryTree::new(2, BinaryTree::empty(), BinaryTree::empty()), - BinaryTree::new(4, BinaryTree::empty(), BinaryTree::empty()) + 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); + let expected = BinaryTree::new(1, BinaryTree::leaf(2), BinaryTree::leaf(4)); let zipper = Zipper::from_tree(initial_tree); From d24b7479f032f2b9385647a54c924fa810bc5ada Mon Sep 17 00:00:00 2001 From: Nenad Date: Sun, 3 Nov 2024 22:54:51 +0100 Subject: [PATCH 08/12] Fill metadata --- exercises/practice/zipper/.meta/config.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/exercises/practice/zipper/.meta/config.json b/exercises/practice/zipper/.meta/config.json index 71c68622..109f8a8d 100644 --- a/exercises/practice/zipper/.meta/config.json +++ b/exercises/practice/zipper/.meta/config.json @@ -1,5 +1,7 @@ { - "authors": [], + "authors": [ + "0xNeshi" + ], "files": { "solution": [ "src/lib.cairo" @@ -9,6 +11,9 @@ ], "example": [ ".meta/example.cairo" + ], + "invalidator": [ + "Scarb.toml" ] }, "blurb": "Creating a zipper for a binary tree." From a467feee88d4d706e3199daf33a47ceca4f3b954 Mon Sep 17 00:00:00 2001 From: Nenad Date: Sun, 3 Nov 2024 23:04:00 +0100 Subject: [PATCH 09/12] increase difficulty --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index b007c0fd..f7192142 100644 --- a/config.json +++ b/config.json @@ -834,7 +834,7 @@ "uuid": "61120275-6457-43ce-b40b-7e86a18b7f5b", "practices": [], "prerequisites": [], - "difficulty": 1 + "difficulty": 6 } ], "foregone": [ From 3902f1c88475488977a54576845fb5ebb76069a1 Mon Sep 17 00:00:00 2001 From: Nenad Date: Sun, 3 Nov 2024 23:35:42 +0100 Subject: [PATCH 10/12] Assume Node exists in Zipper --- exercises/practice/zipper/src/lib.cairo | 81 ++++++++------------ exercises/practice/zipper/tests/zipper.cairo | 38 +++++---- 2 files changed, 49 insertions(+), 70 deletions(-) diff --git a/exercises/practice/zipper/src/lib.cairo b/exercises/practice/zipper/src/lib.cairo index 7a19a74e..e79fe8fe 100644 --- a/exercises/practice/zipper/src/lib.cairo +++ b/exercises/practice/zipper/src/lib.cairo @@ -1,14 +1,14 @@ -pub type BinaryTree = Option>; +pub type BinaryTree = Option>; #[derive(Drop, Debug, PartialEq, Copy)] -pub struct Node { +pub struct BinaryTreeNode { value: u32, left: BinaryTree, right: BinaryTree, } -pub impl BinaryTreePartialEq of PartialEq>> { - fn eq(lhs: @Option>, rhs: @Option>) -> bool { +pub impl BinaryTreePartialEq of PartialEq>> { + fn eq(lhs: @Option>, rhs: @Option>) -> bool { match (lhs, rhs) { (Option::Some(lhs), Option::Some(rhs)) => (*lhs).unbox() == (*rhs).unbox(), (Option::None, Option::None) => true, @@ -19,21 +19,21 @@ pub impl BinaryTreePartialEq of PartialEq>> { #[generate_trait] impl NodeImpl of NodeTrait { - fn with_value(self: Node, right: BinaryTree) -> Node { - Node { right, ..self } + fn set_value(self: BinaryTreeNode, value: u32) -> BinaryTreeNode { + BinaryTreeNode { value, ..self } } - fn with_left(self: Node, left: BinaryTree) -> Node { - Node { left, ..self } + fn set_left(self: BinaryTreeNode, left: BinaryTree) -> BinaryTreeNode { + BinaryTreeNode { left, ..self } } - fn with_right(self: Node, right: BinaryTree) -> Node { - Node { right, ..self } + fn set_right(self: BinaryTreeNode, right: BinaryTree) -> BinaryTreeNode { + BinaryTreeNode { right, ..self } } } -impl NodeIntoBinaryTree of Into { - fn into(self: Node) -> BinaryTree { +impl NodeIntoBinaryTree of Into { + fn into(self: BinaryTreeNode) -> BinaryTree { Option::Some(BoxTrait::new(self)) } } @@ -45,7 +45,7 @@ pub impl BinaryTreeImpl of BinaryTreeTrait { } fn new(value: u32, left: BinaryTree, right: BinaryTree) -> BinaryTree { - Option::Some(BoxTrait::new(Node { value, left, right })) + Option::Some(BoxTrait::new(BinaryTreeNode { value, left, right })) } fn leaf(value: u32) -> BinaryTree { @@ -56,7 +56,6 @@ pub impl BinaryTreeImpl of BinaryTreeTrait { Self::new(value, *self.left(), *self.right()) } - // TODO: return snapshot of value fn value(self: @BinaryTree) -> Option { Option::Some((*self)?.value) } @@ -85,86 +84,68 @@ enum Path { #[derive(Drop, Copy, Debug, PartialEq)] struct Ancestor { path: Path, - node: Node + node: BinaryTreeNode } #[derive(Drop, Copy, Debug, PartialEq)] struct Zipper { - tree: BinaryTree, + node: BinaryTreeNode, ancestors: Span } #[generate_trait] pub impl ZipperImpl of ZipperTrait { - fn new(tree: BinaryTree, ancestors: Span) -> Zipper { - Zipper { tree, ancestors } + fn new(tree: BinaryTree, ancestors: Span) -> Option { + Option::Some(Zipper { node: tree?.unbox(), ancestors }) } - fn from_tree(tree: BinaryTree) -> Zipper { + fn from_tree(tree: BinaryTree) -> Option { Self::new(tree, array![].span()) } fn to_tree(self: Zipper) -> BinaryTree { - rebuild_tree(self.tree, self.ancestors) + rebuild_tree(self.node.into(), self.ancestors) } - fn value(self: @Zipper) -> Option { - self.tree.value() + fn value(self: @Zipper) -> @u32 { + self.node.value } fn left(self: Zipper) -> Option { - Option::Some( - Self::new( - Option::Some((*self.tree.left())?), - self - .ancestors - .append(Ancestor { path: Path::Left, node: self.tree.unwrap().unbox() }) - ) + Self::new( + self.node.left, self.ancestors.append(Ancestor { path: Path::Left, node: self.node }) ) } fn right(self: Zipper) -> Option { - Option::Some( - Self::new( - Option::Some((*self.tree.right())?), - self - .ancestors - .append(Ancestor { path: Path::Right, node: self.tree.unwrap().unbox() }) - ) + Self::new( + self.node.right, self.ancestors.append(Ancestor { path: Path::Right, node: self.node }) ) } fn up(self: Zipper) -> Option { let mut ancestors = self.ancestors; let ancestor = *ancestors.pop_back()?; - Option::Some(Self::new(from_ancestor(self.tree, ancestor), ancestors)) + Self::new(from_ancestor(self.node.into(), ancestor), ancestors) } fn set_value(self: Zipper, value: u32) -> Zipper { - Self::new( - BinaryTreeTrait::new(value, *self.tree.left(), *self.tree.right()), self.ancestors - ) + Self::new(self.node.set_value(value).into(), self.ancestors).unwrap() } fn set_left(self: Zipper, left: BinaryTree) -> Zipper { - Self::new( - BinaryTreeTrait::new(self.tree.value().unwrap(), left, *self.tree.right()), - self.ancestors - ) + Self::new(self.node.set_left(left).into(), self.ancestors).unwrap() } fn set_right(self: Zipper, right: BinaryTree) -> Zipper { - Self::new( - BinaryTreeTrait::new(self.tree.value().unwrap(), *self.tree.left(), right), - self.ancestors - ) + Self::new(self.node.set_right(right).into(), self.ancestors).unwrap() } } fn from_ancestor(tree: BinaryTree, ancestor: Ancestor) -> BinaryTree { match ancestor.path { - Path::Left => ancestor.node.with_left(tree).into(), - Path::Right => ancestor.node.with_right(tree).into(), + Path::Left => ancestor.node.set_left(tree).into(), + Path::Right => ancestor.node.set_right(tree).into(), } } diff --git a/exercises/practice/zipper/tests/zipper.cairo b/exercises/practice/zipper/tests/zipper.cairo index ce643f67..c0a0cfb3 100644 --- a/exercises/practice/zipper/tests/zipper.cairo +++ b/exercises/practice/zipper/tests/zipper.cairo @@ -6,7 +6,7 @@ fn data_is_retained() { 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); let expected = initial_tree.clone(); - let zipper = Zipper::from_tree(initial_tree); + let zipper = Zipper::from_tree(initial_tree).unwrap(); assert_eq!(expected, zipper.to_tree()); } @@ -15,8 +15,8 @@ fn left_right_and_value() { let initial_tree = BinaryTree::new( 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); - let zipper = Zipper::from_tree(initial_tree); - assert_eq!(Option::Some(3), zipper.left().unwrap().right().unwrap().value()); + let zipper = Zipper::from_tree(initial_tree).unwrap(); + assert_eq!(@3, zipper.left().unwrap().right().unwrap().value()); } #[test] @@ -24,7 +24,7 @@ fn dead_end() { let initial_tree = BinaryTree::new( 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); - let zipper = Zipper::from_tree(initial_tree); + let zipper = Zipper::from_tree(initial_tree).unwrap(); assert!(zipper.left().unwrap().left().is_none()); } @@ -34,7 +34,7 @@ fn tree_from_deep_focus() { 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); let expected = initial_tree.clone(); - let zipper = Zipper::from_tree(initial_tree); + let zipper = Zipper::from_tree(initial_tree).unwrap(); assert_eq!(expected, zipper.left().unwrap().right().unwrap().to_tree()); } @@ -43,7 +43,7 @@ fn traversing_up_from_top() { let initial_tree = BinaryTree::new( 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); - let zipper = Zipper::from_tree(initial_tree); + let zipper = Zipper::from_tree(initial_tree).unwrap(); assert!(zipper.up().is_none()); } @@ -52,9 +52,9 @@ fn left_right_and_up() { let initial_tree = BinaryTree::new( 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); - let zipper = Zipper::from_tree(initial_tree); + let zipper = Zipper::from_tree(initial_tree).unwrap(); assert_eq!( - Option::Some(3), + @3, zipper .left() .unwrap() @@ -77,10 +77,8 @@ fn test_ability_to_descend_multiple_levels_and_return() { let initial_tree = BinaryTree::new( 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); - let zipper = Zipper::from_tree(initial_tree); - assert_eq!( - Option::Some(1), zipper.left().unwrap().right().unwrap().up().unwrap().up().unwrap().value() - ); + let zipper = Zipper::from_tree(initial_tree).unwrap(); + assert_eq!(@1, zipper.left().unwrap().right().unwrap().up().unwrap().up().unwrap().value()); } #[test] @@ -91,7 +89,7 @@ fn set_value() { let expected = BinaryTree::new( 1, BinaryTree::new(5, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); - let zipper = Zipper::from_tree(initial_tree); + let zipper = Zipper::from_tree(initial_tree).unwrap(); assert_eq!(expected, zipper.left().unwrap().set_value(5).to_tree()); } @@ -104,7 +102,7 @@ fn set_value_after_traversing_up() { 1, BinaryTree::new(5, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); - let zipper = Zipper::from_tree(initial_tree); + let zipper = Zipper::from_tree(initial_tree).unwrap(); assert_eq!( expected, zipper.left().unwrap().right().unwrap().up().unwrap().set_value(5).to_tree() @@ -120,7 +118,7 @@ fn set_left_with_leaf() { 1, BinaryTree::new(2, BinaryTree::leaf(5), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); - let zipper = Zipper::from_tree(initial_tree); + let zipper = Zipper::from_tree(initial_tree).unwrap(); assert_eq!(expected, zipper.left().unwrap().set_left(BinaryTree::leaf(5)).to_tree()); } @@ -132,7 +130,7 @@ fn set_right_with_leaf() { ); let expected = BinaryTree::new(1, BinaryTree::leaf(2), BinaryTree::leaf(4)); - let zipper = Zipper::from_tree(initial_tree); + let zipper = Zipper::from_tree(initial_tree).unwrap(); assert_eq!(expected, zipper.left().unwrap().set_right(BinaryTree::empty()).to_tree()); } @@ -148,7 +146,7 @@ fn set_right_with_subtree() { BinaryTree::new(6, BinaryTree::leaf(7), BinaryTree::leaf(8)) ); - let zipper = Zipper::from_tree(initial_tree); + let zipper = Zipper::from_tree(initial_tree).unwrap(); assert_eq!( expected, @@ -165,7 +163,7 @@ fn set_value_on_deep_focus() { 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(5)), BinaryTree::leaf(4) ); - let zipper = Zipper::from_tree(initial_tree); + let zipper = Zipper::from_tree(initial_tree).unwrap(); assert_eq!(expected, zipper.left().unwrap().right().unwrap().set_value(5).to_tree()); } @@ -175,8 +173,8 @@ fn different_paths_to_same_zipper() { let initial_tree = BinaryTree::new( 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); - let expected = Zipper::from_tree(initial_tree).right(); - let actual = Zipper::from_tree(initial_tree).left().unwrap().up().unwrap().right(); + let expected = Zipper::from_tree(initial_tree).unwrap().right(); + let actual = Zipper::from_tree(initial_tree).unwrap().left().unwrap().up().unwrap().right(); assert_eq!(expected, actual); } From 462dd1e48c1dab9bdbdc965df587cf5080578219 Mon Sep 17 00:00:00 2001 From: Nenad Date: Sun, 3 Nov 2024 23:48:49 +0100 Subject: [PATCH 11/12] Set up scaffold + update difficulty --- config.json | 2 +- exercises/practice/zipper/.meta/example.cairo | 168 ++++++++++++++++++ exercises/practice/zipper/src/lib.cairo | 78 ++------ exercises/practice/zipper/tests/zipper.cairo | 2 +- 4 files changed, 184 insertions(+), 66 deletions(-) diff --git a/config.json b/config.json index f7192142..a07830b7 100644 --- a/config.json +++ b/config.json @@ -834,7 +834,7 @@ "uuid": "61120275-6457-43ce-b40b-7e86a18b7f5b", "practices": [], "prerequisites": [], - "difficulty": 6 + "difficulty": 8 } ], "foregone": [ diff --git a/exercises/practice/zipper/.meta/example.cairo b/exercises/practice/zipper/.meta/example.cairo index e69de29b..a9c539ce 100644 --- a/exercises/practice/zipper/.meta/example.cairo +++ b/exercises/practice/zipper/.meta/example.cairo @@ -0,0 +1,168 @@ +type BinaryTree = Option>; + +#[derive(Drop, Debug, PartialEq, Copy)] +struct BinaryTreeNode { + value: u32, + left: BinaryTree, + right: BinaryTree, +} + +pub impl OptionalBinaryTreeNodePartialEq of PartialEq>> { + fn eq(lhs: @Option>, rhs: @Option>) -> bool { + match (lhs, rhs) { + (Option::Some(lhs), Option::Some(rhs)) => (*lhs).unbox() == (*rhs).unbox(), + (Option::None, Option::None) => true, + _ => false + } + } +} + +#[generate_trait] +impl NodeImpl of NodeTrait { + fn set_value(self: BinaryTreeNode, value: u32) -> BinaryTreeNode { + BinaryTreeNode { value, ..self } + } + + fn set_left(self: BinaryTreeNode, left: BinaryTree) -> BinaryTreeNode { + BinaryTreeNode { left, ..self } + } + + fn set_right(self: BinaryTreeNode, right: BinaryTree) -> BinaryTreeNode { + BinaryTreeNode { right, ..self } + } +} + +impl NodeIntoBinaryTree of Into { + fn into(self: BinaryTreeNode) -> BinaryTree { + Option::Some(BoxTrait::new(self)) + } +} + +#[generate_trait] +pub impl BinaryTreeImpl of BinaryTreeTrait { + fn empty() -> BinaryTree { + Option::None + } + + fn new(value: u32, left: BinaryTree, right: BinaryTree) -> BinaryTree { + Option::Some(BoxTrait::new(BinaryTreeNode { value, left, right })) + } + + fn leaf(value: u32) -> BinaryTree { + Self::new(value, Self::empty(), Self::empty()) + } + + fn set_value(self: BinaryTree, value: u32) -> BinaryTree { + Self::new(value, *self.left(), *self.right()) + } + + fn value(self: @BinaryTree) -> Option { + Option::Some((*self)?.value) + } + + fn left(self: @BinaryTree) -> @BinaryTree { + @match self { + Option::None => Option::None, + Option::Some(bst) => bst.left + } + } + + fn right(self: @BinaryTree) -> @BinaryTree { + @match self { + Option::None => Option::None, + Option::Some(bst) => bst.right + } + } +} + +#[derive(Drop, Copy, Debug, PartialEq)] +enum Path { + Left, + Right +} + +#[derive(Drop, Copy, Debug, PartialEq)] +struct Ancestor { + path: Path, + node: BinaryTreeNode +} + +#[derive(Drop, Debug, PartialEq)] +struct Zipper { + node: BinaryTreeNode, + ancestors: Span +} + +#[generate_trait] +pub impl ZipperImpl of ZipperTrait { + fn new(tree: BinaryTree, ancestors: Span) -> Option { + Option::Some(Zipper { node: tree?.unbox(), ancestors }) + } + + fn from_tree(tree: BinaryTree) -> Option { + Self::new(tree, array![].span()) + } + + fn to_tree(self: Zipper) -> BinaryTree { + rebuild_tree(self.node.into(), self.ancestors) + } + + fn value(self: @Zipper) -> @u32 { + self.node.value + } + + fn left(self: Zipper) -> Option { + Self::new( + self.node.left, self.ancestors.append(Ancestor { path: Path::Left, node: self.node }) + ) + } + + fn right(self: Zipper) -> Option { + Self::new( + self.node.right, self.ancestors.append(Ancestor { path: Path::Right, node: self.node }) + ) + } + + fn up(self: Zipper) -> Option { + let mut ancestors = self.ancestors; + let ancestor = *ancestors.pop_back()?; + Self::new(from_ancestor(self.node.into(), ancestor), ancestors) + } + + fn set_value(self: Zipper, value: u32) -> Zipper { + Self::new(self.node.set_value(value).into(), self.ancestors).unwrap() + } + + fn set_left(self: Zipper, left: BinaryTree) -> Zipper { + Self::new(self.node.set_left(left).into(), self.ancestors).unwrap() + } + + fn set_right(self: Zipper, right: BinaryTree) -> Zipper { + Self::new(self.node.set_right(right).into(), self.ancestors).unwrap() + } +} + +fn from_ancestor(tree: BinaryTree, ancestor: Ancestor) -> BinaryTree { + match ancestor.path { + Path::Left => ancestor.node.set_left(tree).into(), + Path::Right => ancestor.node.set_right(tree).into(), + } +} + +fn rebuild_tree(tree: BinaryTree, ancestors: Span) -> BinaryTree { + let mut ancestors = ancestors; + if let Option::Some(last) = ancestors.pop_back() { + rebuild_tree(from_ancestor(tree, *last), ancestors) + } else { + tree + } +} + +#[generate_trait] +impl SpanAppendImpl of SpanAppendTrait { + fn append, +Clone>(self: Span, value: T) -> Span { + let mut arr: Array = self.into(); + arr.append(value); + arr.span() + } +} diff --git a/exercises/practice/zipper/src/lib.cairo b/exercises/practice/zipper/src/lib.cairo index e79fe8fe..8f35de8c 100644 --- a/exercises/practice/zipper/src/lib.cairo +++ b/exercises/practice/zipper/src/lib.cairo @@ -1,13 +1,13 @@ -pub type BinaryTree = Option>; +type BinaryTree = Option>; #[derive(Drop, Debug, PartialEq, Copy)] -pub struct BinaryTreeNode { +struct BinaryTreeNode { value: u32, left: BinaryTree, right: BinaryTree, } -pub impl BinaryTreePartialEq of PartialEq>> { +pub impl OptionalBinaryTreeNodePartialEq of PartialEq>> { fn eq(lhs: @Option>, rhs: @Option>) -> bool { match (lhs, rhs) { (Option::Some(lhs), Option::Some(rhs)) => (*lhs).unbox() == (*rhs).unbox(), @@ -75,94 +75,44 @@ pub impl BinaryTreeImpl of BinaryTreeTrait { } } -#[derive(Drop, Copy, Debug, PartialEq)] -enum Path { - Left, - Right -} - -#[derive(Drop, Copy, Debug, PartialEq)] -struct Ancestor { - path: Path, - node: BinaryTreeNode -} - -#[derive(Drop, Copy, Debug, PartialEq)] -struct Zipper { - node: BinaryTreeNode, - ancestors: Span -} +#[derive(Drop, Debug, PartialEq)] +struct Zipper {} #[generate_trait] pub impl ZipperImpl of ZipperTrait { - fn new(tree: BinaryTree, ancestors: Span) -> Option { - Option::Some(Zipper { node: tree?.unbox(), ancestors }) - } - fn from_tree(tree: BinaryTree) -> Option { - Self::new(tree, array![].span()) + panic!("implement `ZipperTrait::from_tree`") } fn to_tree(self: Zipper) -> BinaryTree { - rebuild_tree(self.node.into(), self.ancestors) + panic!("implement `ZipperTrait::to_tree`") } fn value(self: @Zipper) -> @u32 { - self.node.value + panic!("implement `ZipperTrait::value`") } fn left(self: Zipper) -> Option { - Self::new( - self.node.left, self.ancestors.append(Ancestor { path: Path::Left, node: self.node }) - ) + panic!("implement `ZipperTrait::left`") } fn right(self: Zipper) -> Option { - Self::new( - self.node.right, self.ancestors.append(Ancestor { path: Path::Right, node: self.node }) - ) + panic!("implement `ZipperTrait::right`") } fn up(self: Zipper) -> Option { - let mut ancestors = self.ancestors; - let ancestor = *ancestors.pop_back()?; - Self::new(from_ancestor(self.node.into(), ancestor), ancestors) + panic!("implement `ZipperTrait::up`") } fn set_value(self: Zipper, value: u32) -> Zipper { - Self::new(self.node.set_value(value).into(), self.ancestors).unwrap() + panic!("implement `ZipperTrait::set_value`") } fn set_left(self: Zipper, left: BinaryTree) -> Zipper { - Self::new(self.node.set_left(left).into(), self.ancestors).unwrap() + panic!("implement `ZipperTrait::set_left`") } fn set_right(self: Zipper, right: BinaryTree) -> Zipper { - Self::new(self.node.set_right(right).into(), self.ancestors).unwrap() - } -} - -fn from_ancestor(tree: BinaryTree, ancestor: Ancestor) -> BinaryTree { - match ancestor.path { - Path::Left => ancestor.node.set_left(tree).into(), - Path::Right => ancestor.node.set_right(tree).into(), - } -} - -fn rebuild_tree(tree: BinaryTree, ancestors: Span) -> BinaryTree { - let mut ancestors = ancestors; - if let Option::Some(last) = ancestors.pop_back() { - rebuild_tree(from_ancestor(tree, *last), ancestors) - } else { - tree - } -} - -#[generate_trait] -impl SpanAppendImpl of SpanAppendTrait { - fn append, +Clone>(self: Span, value: T) -> Span { - let mut arr: Array = self.into(); - arr.append(value); - arr.span() + panic!("implement `ZipperTrait::set_right`") } } diff --git a/exercises/practice/zipper/tests/zipper.cairo b/exercises/practice/zipper/tests/zipper.cairo index c0a0cfb3..d6d18c90 100644 --- a/exercises/practice/zipper/tests/zipper.cairo +++ b/exercises/practice/zipper/tests/zipper.cairo @@ -1,4 +1,4 @@ -use zipper::{ZipperTrait as Zipper, BinaryTreeTrait as BinaryTree, BinaryTreePartialEq}; +use zipper::{ZipperTrait as Zipper, BinaryTreeTrait as BinaryTree, OptionalBinaryTreeNodePartialEq}; #[test] fn data_is_retained() { From 8331807b77cb90c011cae26ee7a943ac2f6c2cab Mon Sep 17 00:00:00 2001 From: Nenad Date: Mon, 4 Nov 2024 00:01:13 +0100 Subject: [PATCH 12/12] Ret options from tests (replace unwrap() with ?) --- exercises/practice/zipper/tests/zipper.cairo | 110 +++++++++---------- 1 file changed, 53 insertions(+), 57 deletions(-) diff --git a/exercises/practice/zipper/tests/zipper.cairo b/exercises/practice/zipper/tests/zipper.cairo index d6d18c90..8b06fa6b 100644 --- a/exercises/practice/zipper/tests/zipper.cairo +++ b/exercises/practice/zipper/tests/zipper.cairo @@ -1,100 +1,92 @@ use zipper::{ZipperTrait as Zipper, BinaryTreeTrait as BinaryTree, OptionalBinaryTreeNodePartialEq}; #[test] -fn data_is_retained() { +fn data_is_retained() -> Option<()> { let initial_tree = BinaryTree::new( 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); let expected = initial_tree.clone(); - let zipper = Zipper::from_tree(initial_tree).unwrap(); + let zipper = Zipper::from_tree(initial_tree)?; assert_eq!(expected, zipper.to_tree()); + Option::Some(()) } #[test] -fn left_right_and_value() { +fn left_right_and_value() -> Option<()> { let initial_tree = BinaryTree::new( 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); - let zipper = Zipper::from_tree(initial_tree).unwrap(); - assert_eq!(@3, zipper.left().unwrap().right().unwrap().value()); + let zipper = Zipper::from_tree(initial_tree)?; + assert_eq!(@3, zipper.left()?.right()?.value()); + Option::Some(()) } #[test] -fn dead_end() { +fn dead_end() -> Option<()> { let initial_tree = BinaryTree::new( 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); - let zipper = Zipper::from_tree(initial_tree).unwrap(); - assert!(zipper.left().unwrap().left().is_none()); + let zipper = Zipper::from_tree(initial_tree)?; + assert!(zipper.left()?.left().is_none()); + Option::Some(()) } #[test] -fn tree_from_deep_focus() { +fn tree_from_deep_focus() -> Option<()> { let initial_tree = BinaryTree::new( 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); let expected = initial_tree.clone(); - let zipper = Zipper::from_tree(initial_tree).unwrap(); - assert_eq!(expected, zipper.left().unwrap().right().unwrap().to_tree()); + let zipper = Zipper::from_tree(initial_tree)?; + assert_eq!(expected, zipper.left()?.right()?.to_tree()); + Option::Some(()) } #[test] -fn traversing_up_from_top() { +fn traversing_up_from_top() -> Option<()> { let initial_tree = BinaryTree::new( 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); - let zipper = Zipper::from_tree(initial_tree).unwrap(); + let zipper = Zipper::from_tree(initial_tree)?; assert!(zipper.up().is_none()); + Option::Some(()) } #[test] -fn left_right_and_up() { +fn left_right_and_up() -> Option<()> { let initial_tree = BinaryTree::new( 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); - let zipper = Zipper::from_tree(initial_tree).unwrap(); - assert_eq!( - @3, - zipper - .left() - .unwrap() - .up() - .unwrap() - .right() - .unwrap() - .up() - .unwrap() - .left() - .unwrap() - .right() - .unwrap() - .value() - ); + let zipper = Zipper::from_tree(initial_tree)?; + assert_eq!(@3, zipper.left()?.up()?.right()?.up()?.left()?.right()?.value()); + Option::Some(()) } #[test] -fn test_ability_to_descend_multiple_levels_and_return() { +fn test_ability_to_descend_multiple_levels_and_return() -> Option<()> { let initial_tree = BinaryTree::new( 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); - let zipper = Zipper::from_tree(initial_tree).unwrap(); - assert_eq!(@1, zipper.left().unwrap().right().unwrap().up().unwrap().up().unwrap().value()); + let zipper = Zipper::from_tree(initial_tree)?; + assert_eq!(@1, zipper.left()?.right()?.up()?.up()?.value()); + Option::Some(()) } #[test] -fn set_value() { +fn set_value() -> Option<()> { let initial_tree = BinaryTree::new( 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); let expected = BinaryTree::new( 1, BinaryTree::new(5, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); - let zipper = Zipper::from_tree(initial_tree).unwrap(); - assert_eq!(expected, zipper.left().unwrap().set_value(5).to_tree()); + let zipper = Zipper::from_tree(initial_tree)?; + assert_eq!(expected, zipper.left()?.set_value(5).to_tree()); + Option::Some(()) } #[test] -fn set_value_after_traversing_up() { +fn set_value_after_traversing_up() -> Option<()> { let initial_tree = BinaryTree::new( 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); @@ -102,15 +94,14 @@ fn set_value_after_traversing_up() { 1, BinaryTree::new(5, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); - let zipper = Zipper::from_tree(initial_tree).unwrap(); + let zipper = Zipper::from_tree(initial_tree)?; - assert_eq!( - expected, zipper.left().unwrap().right().unwrap().up().unwrap().set_value(5).to_tree() - ); + assert_eq!(expected, zipper.left()?.right()?.up()?.set_value(5).to_tree()); + Option::Some(()) } #[test] -fn set_left_with_leaf() { +fn set_left_with_leaf() -> Option<()> { let initial_tree = BinaryTree::new( 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); @@ -118,25 +109,27 @@ fn set_left_with_leaf() { 1, BinaryTree::new(2, BinaryTree::leaf(5), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); - let zipper = Zipper::from_tree(initial_tree).unwrap(); + let zipper = Zipper::from_tree(initial_tree)?; - assert_eq!(expected, zipper.left().unwrap().set_left(BinaryTree::leaf(5)).to_tree()); + assert_eq!(expected, zipper.left()?.set_left(BinaryTree::leaf(5)).to_tree()); + Option::Some(()) } #[test] -fn set_right_with_leaf() { +fn set_right_with_leaf() -> Option<()> { let initial_tree = BinaryTree::new( 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); let expected = BinaryTree::new(1, BinaryTree::leaf(2), BinaryTree::leaf(4)); - let zipper = Zipper::from_tree(initial_tree).unwrap(); + let zipper = Zipper::from_tree(initial_tree)?; - assert_eq!(expected, zipper.left().unwrap().set_right(BinaryTree::empty()).to_tree()); + assert_eq!(expected, zipper.left()?.set_right(BinaryTree::empty()).to_tree()); + Option::Some(()) } #[test] -fn set_right_with_subtree() { +fn set_right_with_subtree() -> Option<()> { let initial_tree = BinaryTree::new( 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); @@ -146,16 +139,17 @@ fn set_right_with_subtree() { BinaryTree::new(6, BinaryTree::leaf(7), BinaryTree::leaf(8)) ); - let zipper = Zipper::from_tree(initial_tree).unwrap(); + let zipper = Zipper::from_tree(initial_tree)?; assert_eq!( expected, zipper.set_right(BinaryTree::new(6, BinaryTree::leaf(7), BinaryTree::leaf(8))).to_tree() ); + Option::Some(()) } #[test] -fn set_value_on_deep_focus() { +fn set_value_on_deep_focus() -> Option<()> { let initial_tree = BinaryTree::new( 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); @@ -163,18 +157,20 @@ fn set_value_on_deep_focus() { 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(5)), BinaryTree::leaf(4) ); - let zipper = Zipper::from_tree(initial_tree).unwrap(); + let zipper = Zipper::from_tree(initial_tree)?; - assert_eq!(expected, zipper.left().unwrap().right().unwrap().set_value(5).to_tree()); + assert_eq!(expected, zipper.left()?.right()?.set_value(5).to_tree()); + Option::Some(()) } #[test] -fn different_paths_to_same_zipper() { +fn different_paths_to_same_zipper() -> Option<()> { let initial_tree = BinaryTree::new( 1, BinaryTree::new(2, BinaryTree::empty(), BinaryTree::leaf(3)), BinaryTree::leaf(4) ); - let expected = Zipper::from_tree(initial_tree).unwrap().right(); - let actual = Zipper::from_tree(initial_tree).unwrap().left().unwrap().up().unwrap().right(); + let expected = Zipper::from_tree(initial_tree)?.right(); + let actual = Zipper::from_tree(initial_tree)?.left()?.up()?.right(); assert_eq!(expected, actual); + Option::Some(()) }