diff --git a/concepts/control-flow/.meta/config.json b/concepts/control-flow/.meta/config.json index 17756acf..6058fa32 100644 --- a/concepts/control-flow/.meta/config.json +++ b/concepts/control-flow/.meta/config.json @@ -1,5 +1,5 @@ { - "blurb": "Control flow in Cairo uses `if` expressions to conditionally execute code and loops to run code repeatedly.", + "blurb": "Control flow in Cairo uses `if` expressions to conditionally execute code, and loops to run code repeatedly.", "authors": ["Falilah"], "contributors": ["0xNeshi"] } diff --git a/concepts/control-flow/links.json b/concepts/control-flow/links.json index 2cc370a3..efe514a5 100644 --- a/concepts/control-flow/links.json +++ b/concepts/control-flow/links.json @@ -1,6 +1,6 @@ [ { "url": "https://book.cairo-lang.org/ch02-05-control-flow.html", - "description": "Control flow concept in cairo book" + "description": "Control Flow Concept in The Cairo Book" } ] diff --git a/concepts/smart-pointers/.meta/config.json b/concepts/smart-pointers/.meta/config.json index 35b1d32b..0dfbb489 100644 --- a/concepts/smart-pointers/.meta/config.json +++ b/concepts/smart-pointers/.meta/config.json @@ -1,7 +1,7 @@ { - "blurb": "", + "blurb": "Smart pointers in Cairo are special data structures that manage memory safely by ensuring that memory is accessed in a controlled way.", "authors": [ - "" + "0xNeshi" ], "contributors": [] } diff --git a/concepts/smart-pointers/about.md b/concepts/smart-pointers/about.md index bf8e8d62..435e99c6 100644 --- a/concepts/smart-pointers/about.md +++ b/concepts/smart-pointers/about.md @@ -1 +1,127 @@ # Smart Pointers + +Smart pointers in Cairo are a powerful tool that provide safe and efficient management of memory. + +A smart pointer is a data structure that acts like a regular pointer, but with added safety features to avoid common memory management issues like dereferencing null pointers or accessing uninitialized memory. + +## What is a Smart Pointer? + +In general, a pointer is a variable that stores a memory address, typically pointing to a value stored at that location. + +However, raw pointers can be dangerous: if the pointer doesn't point to valid memory or is incorrectly dereferenced, it can lead to crashes or unpredictable behavior. + +Smart pointers solve this issue by enforcing strict rules on memory management, ensuring that memory is accessed in a safe and controlled manner. + +Cairo, like many modern languages such as Rust, uses smart pointers to prevent unsafe memory access. + +A smart pointer in Cairo not only stores a memory address but also tracks ownership and ensures memory safety. + +## Types of Smart Pointers in Cairo + +Cairo provides several types of smart pointers, including `Box` and `Nullable`, each serving a different purpose. + +Let's take a closer look at how these types work and when you might use them. + +### `Box` + +The `Box` type is the principal smart pointer in Cairo. + +It allows you to store data in a special memory segment called the "boxed segment." A `Box` is a pointer that points to this segment, and when you create a box, you allocate space for the data in this segment. + +Boxes are ideal in situations where: + +- You need to store a value of a type whose size cannot be determined at compile time. +- You have a large amount of data and want to transfer ownership without copying it. + +By using a box, you can store large data structures more efficiently. + +When passing a `Box` to a function, only the pointer is passed, avoiding the need to copy the entire data, which improves performance, especially with large structures. + +### `Nullable` + +The `Nullable` type is another important smart pointer in Cairo. + +It can either point to a valid value of type `T` or be `null` if there is no value. + +This type is useful in cases where you need to store values that may not always exist, such as in a dictionary that can contain optional elements. + +In Cairo, `Nullable` is typically used in dictionaries to handle cases where no default value can be applied. + +It allows you to store values conditionally, making it easier to handle the absence of data safely. + +## Memory Safety with Smart Pointers + +One of the primary advantages of using smart pointers is that they help ensure memory safety. + +By managing ownership and access rules, Cairo prevents common issues such as dereferencing null or dangling pointers. + +Smart pointers track when data is no longer needed and can automatically deallocate memory when it goes out of scope, reducing the risk of memory leaks. + +### Example: Using a `Box` for Recursive Types + +A common challenge in many programming languages is handling recursive types. + +Recursive types refer to types that contain references to themselves. + +Without proper memory management, defining a recursive type can lead to issues such as infinite recursion. + +In Cairo, `Box` makes it possible to define recursive types safely. + +For instance, you can use `Box` to implement a binary tree, where each node contains a reference to another node. + +By storing references in boxes, Cairo ensures that memory usage is finite, and the compiler can determine the required memory size for the structure. + +```rust +use core::box::{BoxTrait}; + +#[derive(Copy, Drop)] +enum BinaryTree { + Leaf: u32, + Node: (u32, Box, Box), +} + +fn main() { + let leaf1 = BinaryTree::Leaf(1); + let leaf2 = BinaryTree::Leaf(2); + let node = BinaryTree::Node((3, BoxTrait::new(leaf1), BoxTrait::new(leaf2))); + println!("{:?}", node); +} +``` + +### Performance Benefits of Smart Pointers + +Smart pointers also improve the performance of your programs. + +When you use `Box`, only the pointer to the data is passed around, instead of copying the entire data structure. + +This is especially useful when dealing with large datasets, as it significantly reduces the overhead of memory operations. + +In the following example, the data is passed by reference using a `Box` to avoid the cost of copying the entire structure: + +```rust +#[derive(Drop)] +struct Cart { + paid: bool, + items: u256, + buyer: ByteArray, +} + +fn pass_data(cart: Cart) { + println!("{} is shopping today and bought {} items", cart.buyer, cart.items); +} + +fn pass_pointer(cart: Box) { + let cart = cart.unbox(); + println!("{} is shopping today and bought {} items", cart.buyer, cart.items); +} + +fn main() { + let new_cart = Cart { paid: true, items: 1, buyer: "John" }; + pass_data(new_cart); + + let new_box = BoxTrait::new(Cart { paid: false, items: 3, buyer: "Jane" }); + pass_pointer(new_box); +} +``` + +In this example, `pass_pointer` takes a `Box` instead of a `Cart`, reducing the amount of memory copied during the function call. diff --git a/concepts/smart-pointers/introduction.md b/concepts/smart-pointers/introduction.md index e10b99d0..77bfcbde 100644 --- a/concepts/smart-pointers/introduction.md +++ b/concepts/smart-pointers/introduction.md @@ -1 +1,7 @@ # Introduction + +Smart pointers in Cairo are special data structures that manage memory safely by ensuring that memory is accessed in a controlled way. + +They act like regular pointers but include additional features like ownership rules and metadata to prevent common errors, such as dereferencing uninitialized memory. + +This makes them essential for working with complex data structures and improving program safety and performance. diff --git a/concepts/smart-pointers/links.json b/concepts/smart-pointers/links.json index fe51488c..743fa914 100644 --- a/concepts/smart-pointers/links.json +++ b/concepts/smart-pointers/links.json @@ -1 +1,10 @@ -[] +[ + { + "url": "https://book.cairo-lang.org/ch11-02-smart-pointers.html", + "description": "Smart Pointers in The Cairo Book" + }, + { + "url": "https://book.cairo-lang.org/ch03-02-dictionaries.html#dictionaries-of-types-not-supported-natively", + "description": "Nullable Use Case with Dictionaries" + } +] diff --git a/config.json b/config.json index 574ec5e8..02009822 100644 --- a/config.json +++ b/config.json @@ -261,14 +261,15 @@ "status": "wip" }, { - "slug": "chrono-realms-time-tree", - "name": "Chrono Realms Time Tree", - "uuid": "a72139a1-825e-4349-a6b5-400b665fbe07", + "slug": "chrono-realms-chrono-chain", + "name": "Chrono Realms Chrono Chain", + "uuid": "e04f808a-25dc-4448-bc45-d3da0db9819a", "concepts": [ "smart-pointers" ], "prerequisites": [ - "structs" + "traits", + "enums" ], "status": "wip" } diff --git a/exercises/concept/chrono-realms-chrono-chain/.docs/hints.md b/exercises/concept/chrono-realms-chrono-chain/.docs/hints.md new file mode 100644 index 00000000..d4fcf74e --- /dev/null +++ b/exercises/concept/chrono-realms-chrono-chain/.docs/hints.md @@ -0,0 +1,18 @@ +# Hints + +## General + +- [The Cairo Book: Smart Pointers][smart-pointers] + +## 1. Build the ChronoChain from an array of `u32` values + +- We can iterate through the array and construct a chain in reverse, starting from the `End` and linking each value with the `Link` variant. +- Consider using `span.pop_back()` to iterate through the array in reverse order, this will help us create the chain from the end to the start. + +## 2. Sum the values in the ChronoChain + +- Use pattern matching to handle the two variants of `ChronoChain`. +- When you reach `End`, the sum is 0, and when you reach `Link`, you add the value and recursively sum the rest of the chain. +- This approach is similar to a recursive function that traverses the structure until it reaches the base case (`End`). + +[smart-pointers]: https://book.cairo-lang.org/ch11-02-smart-pointers.html diff --git a/exercises/concept/chrono-realms-chrono-chain/.docs/instructions.md b/exercises/concept/chrono-realms-chrono-chain/.docs/instructions.md new file mode 100644 index 00000000..0201d2c8 --- /dev/null +++ b/exercises/concept/chrono-realms-chrono-chain/.docs/instructions.md @@ -0,0 +1,46 @@ +# Instructions + +In **Chrono Realms**, Time Keepers often deal with not just trees of timelines, but **Chrono Chains**-sequences of linked **TimeNodes**, each representing a specific moment in time. +A **Chrono Chain** is a straight path of sequential moments, where each **TimeNode** connects to the next. +These **Chrono Chains** are useful when traveling through a series of specific events, as they allow Time Keepers to follow a single timeline. + +However, to handle these potentially long **Chrono Chains**, Time Keepers use **Smart Pointers (Box)** to safely manage and traverse these lists of moments without causing unnecessary memory duplication or overflow. +Each **TimeNode** holds a reference to the next node, forming a recursive structure. + +Your task as an apprentice is to implement a **Chrono Chain** as a recursive list structure using smart pointers. + +In this exercise, you will: + +1. Create a recursive `ChronoChain` enum, representing a list of moments. +2. Use the `Box` smart pointer to store the recursive nodes. +3. Implement a function to create a `ChronoChain` from an array of `u32` values. +4. Implement a function to traverse the `ChronoChain` and sum up the values stored in the list. + +## 1. Define the Recursive `ChronoChain` Enum + +Create a recursive enum `ChronoChain` with two variants: + +- `End`: Represents the end of the list. +- `Link`: Contains a `u32` value and a boxed reference to the next node in the chain. + +## 2. Create a Function to Build a ChronoChain + +Write a function `ChronoChain::build` that takes an array of `u32` values and returns a `ChronoChain`, linking the values sequentially using smart pointers. + +## 3. Implement the Sum Function + +Write a function `ChronoChain::sum` to recursively traverse the `ChronoChain` and sum the values of all nodes. + +## Example Usage + +```rust +fn main() { + // Create a ChronoChain from an array of values + let chrono_chain = ChronoChain::build(array![10, 20, 30]); + + // Sum the values in the ChronoChain + let total_sum = chrono_chain.sum(); + + println!("Total Time Power: {}", total_sum); +} +``` diff --git a/exercises/concept/chrono-realms-chrono-chain/.docs/introduction.md b/exercises/concept/chrono-realms-chrono-chain/.docs/introduction.md new file mode 100644 index 00000000..880a6084 --- /dev/null +++ b/exercises/concept/chrono-realms-chrono-chain/.docs/introduction.md @@ -0,0 +1,52 @@ +# Introduction + +Smart pointers in Cairo are advanced data structures that ensure safe and efficient memory management by adding safety features to regular pointers, preventing common issues like dereferencing null pointers or accessing uninitialized memory. + +## What is a Smart Pointer? + +A smart pointer behaves like a regular pointer but tracks ownership and ensures safe memory access, preventing issues like null or dangling pointer dereferencing. + +## Types of Smart Pointers + +Cairo provides several smart pointer types, such as `Box` and `Nullable`: + +- **`Box`**: Stores data in a special memory segment, ideal for large or dynamically-sized data. + It allows transferring ownership without copying the data. +- **`Nullable`**: Points to either a valid value of type `T` or `null`, useful for handling optional values. + +## Memory Safety + +Smart pointers help prevent unsafe memory access, ensuring memory is automatically deallocated when no longer needed, thus reducing the risk of memory leaks. + +### Example: Using `Box` for Recursive Types + +Smart pointers like `Box` allow for safe handling of recursive types, such as in a binary tree, by allocating memory efficiently and avoiding infinite recursion. + +```rust +use core::box::{BoxTrait}; + +#[derive(Copy, Drop)] +enum BinaryTree { + Leaf: u32, + Node: (u32, Box, Box), +} + +fn main() { + let leaf1 = BinaryTree::Leaf(1); + let leaf2 = BinaryTree::Leaf(2); + let node = BinaryTree::Node((3, BoxTrait::new(leaf1), BoxTrait::new(leaf2))); + println!("{:?}", node); +} +``` + +## Performance Benefits + +Smart pointers improve performance by passing references to data instead of copying large structures, reducing memory overhead. + +```rust +// `Cart` is a large struct that contains a lot of information +fn pass_pointer(cart: Box) { + let cart = cart.unbox(); + println!("{} is shopping today and bought {} items", cart.buyer, cart.items); +} +``` diff --git a/exercises/concept/chrono-realms-time-tree/.meta/config.json b/exercises/concept/chrono-realms-chrono-chain/.meta/config.json similarity index 65% rename from exercises/concept/chrono-realms-time-tree/.meta/config.json rename to exercises/concept/chrono-realms-chrono-chain/.meta/config.json index edd96af6..8d9e967a 100644 --- a/exercises/concept/chrono-realms-time-tree/.meta/config.json +++ b/exercises/concept/chrono-realms-chrono-chain/.meta/config.json @@ -7,7 +7,7 @@ "src/lib.cairo" ], "test": [ - "tests/chrono_realms_time_tree.cairo" + "tests/chrono_realms_chrono_chain.cairo" ], "exemplar": [ ".meta/exemplar.cairo" @@ -16,5 +16,5 @@ "Scarb.toml" ] }, - "blurb": "" + "blurb": "Learn smart pointers by building the magical Chrono Chain" } diff --git a/exercises/concept/chrono-realms-chrono-chain/.meta/design.md b/exercises/concept/chrono-realms-chrono-chain/.meta/design.md new file mode 100644 index 00000000..bdb2a7a2 --- /dev/null +++ b/exercises/concept/chrono-realms-chrono-chain/.meta/design.md @@ -0,0 +1,36 @@ +# Design + +## Goal + +Introduce the student to working with recursive types and smart pointers in Cairo. + +## Learning objectives + +- Understand how to define and use recursive types with enums in Cairo. +- Learn how to use smart pointers (`Box`) for handling recursive data structures. +- Practice working with recursive functions to traverse and manipulate linked data. + +## Out of scope + +- Advanced memory management concepts related to smart pointers beyond `Box`. +- Deep dive into optimization of recursive data structures. + +## Concepts + +- Enums +- Recursive types +- Smart pointers (`Box`) + +## Prerequisites + +- Traits +- Basic understanding of enums and data types in Cairo. +- Familiarity with smart pointers in Cairo. + +## Resources to refer to + +- [Cairo Book - The Box Type][box] +- [Cairo Book - Enums][enums] + +[box]: https://book.cairo-lang.org/ch11-02-smart-pointers.html#the-boxt-type-to-manipulate-pointers +[enums]: https://book.cairo-lang.org/ch06-01-enums.html diff --git a/exercises/concept/chrono-realms-chrono-chain/.meta/exemplar.cairo b/exercises/concept/chrono-realms-chrono-chain/.meta/exemplar.cairo new file mode 100644 index 00000000..a1a0cecc --- /dev/null +++ b/exercises/concept/chrono-realms-chrono-chain/.meta/exemplar.cairo @@ -0,0 +1,30 @@ +// Define the recursive ChronoChain enum +#[derive(Copy, Drop)] +pub enum ChronoChain { + End, + Link: (u32, Box), +} + +#[generate_trait] +pub impl ChronoChainImpl of ChronoChainTrait { + // Function to build a ChronoChain from an array of u32 values + fn build(arr: Array) -> ChronoChain { + let mut chain = ChronoChain::End; + + // Iterate in reverse to build the chain from the end to the beginning + let mut span = arr.span(); + while let Option::Some(value) = span.pop_back() { + chain = ChronoChain::Link((*value, BoxTrait::new(chain))); + }; + + chain + } + + // Function to sum the values in the ChronoChain + fn sum(self: ChronoChain) -> u64 { + match self { + ChronoChain::End => 0, + ChronoChain::Link((value, next)) => value.into() + next.unbox().sum(), + } + } +} diff --git a/exercises/concept/chrono-realms-time-tree/Scarb.toml b/exercises/concept/chrono-realms-chrono-chain/Scarb.toml similarity index 71% rename from exercises/concept/chrono-realms-time-tree/Scarb.toml rename to exercises/concept/chrono-realms-chrono-chain/Scarb.toml index 8865ffcb..e5af8176 100644 --- a/exercises/concept/chrono-realms-time-tree/Scarb.toml +++ b/exercises/concept/chrono-realms-chrono-chain/Scarb.toml @@ -1,5 +1,5 @@ [package] -name = "chrono_realms_time_tree" +name = "chrono_realms_chrono_chain" version = "0.1.0" edition = "2024_07" diff --git a/exercises/concept/chrono-realms-chrono-chain/src/lib.cairo b/exercises/concept/chrono-realms-chrono-chain/src/lib.cairo new file mode 100644 index 00000000..6d3b5410 --- /dev/null +++ b/exercises/concept/chrono-realms-chrono-chain/src/lib.cairo @@ -0,0 +1,19 @@ +// Define the recursive ChronoChain enum +#[derive(Copy, Drop)] +pub enum ChronoChain { + End, + Link: (u32, Box), +} + +#[generate_trait] +pub impl ChronoChainImpl of ChronoChainTrait { + // Function to build a ChronoChain from an array of u32 values + fn build(arr: Array) -> ChronoChain { + panic!("implement `ChronoChain::build`") + } + + // Function to sum the values in the ChronoChain + fn sum(self: ChronoChain) -> u64 { + panic!("implement `ChronoChain::sum`") + } +} diff --git a/exercises/concept/chrono-realms-chrono-chain/tests/chrono_realms_chrono_chain.cairo b/exercises/concept/chrono-realms-chrono-chain/tests/chrono_realms_chrono_chain.cairo new file mode 100644 index 00000000..5ccb740a --- /dev/null +++ b/exercises/concept/chrono-realms-chrono-chain/tests/chrono_realms_chrono_chain.cairo @@ -0,0 +1,230 @@ +use chrono_realms_chrono_chain::{ChronoChainTrait, ChronoChain}; + +const U32_MAX: u32 = 0xFFFFFFFF; + +#[test] +fn build_empty_array() { + let chrono_chain = ChronoChainTrait::build(array![]); + + match chrono_chain { + ChronoChain::End => (), + _ => panic!("Expected ChronoChain to be End for an empty array"), + } +} + +#[test] +#[ignore] +fn build_single_element_array() { + let chrono_chain = ChronoChainTrait::build(array![42]); + + match chrono_chain { + ChronoChain::Link(( + value, next, + )) => { + assert_eq!(value, 42); + match next.unbox() { + ChronoChain::End => (), + _ => panic!("Expected next to be End"), + } + }, + _ => panic!("Expected ChronoChain to be Link for a single element array"), + } +} + +#[test] +#[ignore] +fn build_multiple_elements_array() { + let chrono_chain = ChronoChainTrait::build(array![1, 2, 3]); + + match chrono_chain { + ChronoChain::Link(( + value, next, + )) => { + assert_eq!(value, 1); + match next.unbox() { + ChronoChain::Link(( + value, next, + )) => { + assert_eq!(value, 2); + match next.unbox() { + ChronoChain::Link(( + value, next, + )) => { + assert_eq!(value, 3); + match next.unbox() { + ChronoChain::End => (), + _ => panic!("Expected next to be End after the last link"), + } + }, + _ => panic!("Expected second link to be Link"), + } + }, + _ => panic!("Expected third link to be Link"), + } + }, + _ => panic!("Expected ChronoChain to be Link for multiple elements"), + } +} + +#[test] +#[ignore] +fn build_duplicate_values_array() { + let chrono_chain = ChronoChainTrait::build(array![5, 5, 5]); + + match chrono_chain { + ChronoChain::Link(( + value, next, + )) => { + assert_eq!(value, 5); + match next.unbox() { + ChronoChain::Link(( + value, next, + )) => { + assert_eq!(value, 5); + match next.unbox() { + ChronoChain::Link(( + value, next, + )) => { + assert_eq!(value, 5); + match next.unbox() { + ChronoChain::End => (), + _ => panic!("Expected next to be End after the last link"), + } + }, + _ => panic!("Expected third link to be Link"), + } + }, + _ => panic!("Expected second link to be Link"), + } + }, + _ => panic!("Expected ChronoChain to be Link for duplicate values"), + } +} + + +#[test] +#[ignore] +fn build_large_values_array() { + let chrono_chain = ChronoChainTrait::build(array![U32_MAX, U32_MAX]); + + match chrono_chain { + ChronoChain::Link(( + value, next, + )) => { + assert_eq!(value, U32_MAX); + match next.unbox() { + ChronoChain::Link(( + value, next, + )) => { + assert_eq!(value, U32_MAX); + match next.unbox() { + ChronoChain::End => (), + _ => panic!("Expected next to be End after the last link"), + } + }, + _ => panic!("Expected second link to be Link"), + } + }, + _ => panic!("Expected ChronoChain to be Link for large values"), + } +} + +#[test] +#[ignore] +fn build_large_array() { + let mut chrono_chain = ChronoChainTrait::build(array_in_range((1..1000))); + + let mut count = 1; + while let ChronoChain::Link((value, next)) = chrono_chain { + assert_eq!(value, count); + count += 1; + chrono_chain = next.unbox(); + }; + + match chrono_chain { + ChronoChain::End => (), + _ => panic!("Expected ChronoChain to be End at the end of the chain"), + } +} + +#[test] +#[ignore] +fn sum_chain() { + let chrono_chain = ChronoChainTrait::build(array![1, 2, 3]); + + let sum = chrono_chain.sum(); + assert_eq!(sum, 6); +} + +#[test] +#[ignore] +fn sum_empty_chain() { + let chrono_chain = ChronoChainTrait::build(array![]); + + let sum = chrono_chain.sum(); + assert_eq!(sum, 0); +} + +#[test] +#[ignore] +fn sum_single_link_chain() { + let chrono_chain = ChronoChainTrait::build(array![5]); + + let sum = chrono_chain.sum(); + assert_eq!(sum, 5); +} + +#[test] +#[ignore] +fn sum_two_link_chain() { + let chrono_chain = ChronoChainTrait::build(array![3, 7]); + + let sum = chrono_chain.sum(); + assert_eq!(sum, 10); +} + +#[test] +#[ignore] +fn sum_large_chain() { + let chrono_chain = ChronoChainTrait::build(array![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + + let sum = chrono_chain.sum(); + assert_eq!(sum, 55); +} + +#[test] +#[ignore] +fn sum_large_values_in_chain() { + let chrono_chain = ChronoChainTrait::build(array![U32_MAX, U32_MAX]); + + let expected_sum: u64 = U32_MAX.into() * 2; + let sum = chrono_chain.sum(); + assert_eq!(sum, expected_sum); +} + +#[test] +#[ignore] +fn sum_zero_values_in_chain() { + let chrono_chain = ChronoChainTrait::build(array![0, 0, 0, 0, 0]); + + let sum = chrono_chain.sum(); + assert_eq!(sum, 0); +} + +#[test] +#[ignore] +fn sum_very_large_chain() { + let chrono_chain = ChronoChainTrait::build(array_in_range((1..1000))); + + let expected_sum = 999 * (999 + 1) / 2; + let sum = chrono_chain.sum(); + assert_eq!(sum, expected_sum); +} + +fn array_in_range(range: core::ops::Range) -> Array { + let mut arr = array![]; + for elem in range { + arr.append(elem); + }; + arr +} diff --git a/exercises/concept/chrono-realms-time-tree/.docs/hints.md b/exercises/concept/chrono-realms-time-tree/.docs/hints.md deleted file mode 100644 index e69de29b..00000000 diff --git a/exercises/concept/chrono-realms-time-tree/.docs/instructions.md b/exercises/concept/chrono-realms-time-tree/.docs/instructions.md deleted file mode 100644 index 9522b7f4..00000000 --- a/exercises/concept/chrono-realms-time-tree/.docs/instructions.md +++ /dev/null @@ -1,46 +0,0 @@ -# Instructions - -In **ChronoRealms**, TimeKeepers often deal with not just trees of timelines, but **ChronoChains**-sequences of linked **TimeNodes**, each representing a specific moment in time. -A **ChronoChain** is a straight path of sequential moments, where each **TimeNode** connects to the next. -These **ChronoChains** are useful when traveling through a series of specific events, as they allow TimeKeepers to follow a single timeline. - -However, to handle these potentially long **ChronoChains**, TimeKeepers use **Smart Pointers (Box)** to safely manage and traverse these lists of moments without causing unnecessary memory duplication or overflow. -Each **TimeNode** holds a reference to the next node, forming a recursive structure. - -Your task as an apprentice is to implement a **ChronoChain** as a recursive list structure using smart pointers. - -In this exercise, you will: - -1. Create a recursive `ChronoChain` enum, representing a list of moments. -2. Use the `Box` smart pointer to store the recursive nodes. -3. Implement a function to create a **ChronoChain** from an array of `u32` values. -4. Implement a function to traverse the **ChronoChain** and sum up the values stored in the list. - -## 1. Define the Recursive `ChronoChain` Enum - -Create a recursive enum `ChronoChain` with two variants: - -- `End`: Represents the end of the list. -- `Link`: Contains a `u32` value and a boxed reference to the next node in the chain. - -## 2. Create a Function to Build a ChronoChain - -Write a function `build_chrono_chain` that takes an array of `u32` values and returns a **ChronoChain**, linking the values sequentially using smart pointers. - -## 3. Implement the Sum Function - -Write a function `sum_chain` to recursively traverse the **ChronoChain** and sum the values of all nodes. - -## Example Usage - -```rust -fn main() { - // Create a ChronoChain from an array of values - let chrono_chain = build_chrono_chain([10, 20, 30]); - - // Sum the values in the ChronoChain - let total_sum = sum_chain(&chrono_chain); - - println!("Total Time Power: {}", total_sum); -} -``` diff --git a/exercises/concept/chrono-realms-time-tree/.docs/introduction.md b/exercises/concept/chrono-realms-time-tree/.docs/introduction.md deleted file mode 100644 index e69de29b..00000000 diff --git a/exercises/concept/chrono-realms-time-tree/.meta/design.md b/exercises/concept/chrono-realms-time-tree/.meta/design.md deleted file mode 100644 index e69de29b..00000000 diff --git a/exercises/concept/chrono-realms-time-tree/.meta/exemplar.cairo b/exercises/concept/chrono-realms-time-tree/.meta/exemplar.cairo deleted file mode 100644 index f47658eb..00000000 --- a/exercises/concept/chrono-realms-time-tree/.meta/exemplar.cairo +++ /dev/null @@ -1,27 +0,0 @@ -// Define the recursive ChronoChain enum -#[derive(Copy, Drop)] -pub enum ChronoChain { - End, - Link: (u32, Box), -} - -// Function to build a ChronoChain from an array of u32 values -pub fn build_chrono_chain(arr: Array) -> Box { - let mut chain = ChronoChain::End; - - // Iterate in reverse to build the chain from the end to the beginning - let mut span = arr.span(); - while let Option::Some(value) = span.pop_back() { - chain = ChronoChain::Link((*value, BoxTrait::new(chain))); - }; - - BoxTrait::new(chain) -} - -// Function to sum the values in the ChronoChain -pub fn sum_chain(chain: @ChronoChain) -> u32 { - match chain { - ChronoChain::End => 0, - ChronoChain::Link((value, next)) => *value + sum_chain(@(*next).unbox()), - } -} diff --git a/exercises/concept/chrono-realms-time-tree/src/lib.cairo b/exercises/concept/chrono-realms-time-tree/src/lib.cairo deleted file mode 100644 index 3a558df7..00000000 --- a/exercises/concept/chrono-realms-time-tree/src/lib.cairo +++ /dev/null @@ -1,16 +0,0 @@ -// Define the recursive ChronoChain enum -#[derive(Copy, Drop)] -pub enum ChronoChain { - End, - Link: (u32, Box), -} - -// Function to build a ChronoChain from an array of u32 values -pub fn build_chrono_chain(arr: Array) -> Box { - panic!("implement 'build_chrono_chain'") -} - -// Function to sum the values in the ChronoChain -pub fn sum_chain(chain: @ChronoChain) -> u32 { - panic!("implement 'sum_chain'") -} diff --git a/exercises/concept/chrono-realms-time-tree/tests/chrono_realms_time_tree.cairo b/exercises/concept/chrono-realms-time-tree/tests/chrono_realms_time_tree.cairo deleted file mode 100644 index f5dbe78a..00000000 --- a/exercises/concept/chrono-realms-time-tree/tests/chrono_realms_time_tree.cairo +++ /dev/null @@ -1,38 +0,0 @@ -use chrono_realms_time_tree::{ChronoChain, build_chrono_chain, sum_chain}; - -#[test] -fn test_build_chrono_chain() { - let chrono_chain = build_chrono_chain(array![10, 20, 30]); - // Verify the structure of the chain - if let ChronoChain::Link((first, next)) = chrono_chain.unbox() { - assert_eq!(first, 10); - - if let ChronoChain::Link((second, next)) = next.unbox() { - assert_eq!(second, 20); - - if let ChronoChain::Link((third, next)) = next.unbox() { - assert_eq!(third, 30); - - if let ChronoChain::Link(_) = next.unbox() { - panic!("Expected 4th elements to be ChronoChain::End"); - } - } - } - } -} - -#[test] -fn test_sum_chain() { - let chrono_chain = build_chrono_chain(array![10, 20, 30]); - let total_sum = sum_chain(@chrono_chain.unbox()); - assert_eq!(total_sum, 60); // 10 + 20 + 30 = 60 -} - -#[test] -fn test_empty_chain() { - // Empty chain should sum to 0 - let empty_chain = BoxTrait::new(ChronoChain::End); - let total_sum = sum_chain(@empty_chain.unbox()); - assert_eq!(total_sum, 0); -} -