diff --git a/concepts/smart-pointers/.meta/config.json b/concepts/smart-pointers/.meta/config.json new file mode 100644 index 00000000..52914445 --- /dev/null +++ b/concepts/smart-pointers/.meta/config.json @@ -0,0 +1,7 @@ +{ + "blurb": "", + "authors": [ + "misicnenad" + ], + "contributors": [] +} diff --git a/concepts/smart-pointers/about.md b/concepts/smart-pointers/about.md new file mode 100644 index 00000000..bf8e8d62 --- /dev/null +++ b/concepts/smart-pointers/about.md @@ -0,0 +1 @@ +# Smart Pointers diff --git a/concepts/smart-pointers/introduction.md b/concepts/smart-pointers/introduction.md new file mode 100644 index 00000000..e10b99d0 --- /dev/null +++ b/concepts/smart-pointers/introduction.md @@ -0,0 +1 @@ +# Introduction diff --git a/concepts/smart-pointers/links.json b/concepts/smart-pointers/links.json new file mode 100644 index 00000000..fe51488c --- /dev/null +++ b/concepts/smart-pointers/links.json @@ -0,0 +1 @@ +[] diff --git a/config.json b/config.json index 0c490ade..e9abe682 100644 --- a/config.json +++ b/config.json @@ -207,6 +207,16 @@ ], "prerequisites": [], "difficulty": 3 + }, + { + "slug": "simple-linked-list", + "name": "Simple Linked List", + "uuid": "cc9a6bf9-9027-42c4-a71d-082ce48f7869", + "practices": [ + "smart-pointers" + ], + "prerequisites": [], + "difficulty": 5 } ], "foregone": [ @@ -303,7 +313,12 @@ { "uuid": "8a4a6525-c1e4-44f5-ab6b-cf5d8ce6701e", "slug": "mutability", - "name": "M`utability" + "name": "Mutability" + }, + { + "uuid": "7e322172-04ba-43f8-aba9-8ae999372b90", + "slug": "smart-pointers", + "name": "Smart Pointers" } ], "key_features": [ diff --git a/exercises/practice/beer-song/.meta/config.json b/exercises/practice/beer-song/.meta/config.json index 5bb008be..1d16d956 100644 --- a/exercises/practice/beer-song/.meta/config.json +++ b/exercises/practice/beer-song/.meta/config.json @@ -1,5 +1,7 @@ { - "authors": [], + "authors": [ + "misicnenad" + ], "files": { "solution": [ "src/lib.cairo", diff --git a/exercises/practice/binary-search/.meta/config.json b/exercises/practice/binary-search/.meta/config.json index fcf1366b..842ed376 100644 --- a/exercises/practice/binary-search/.meta/config.json +++ b/exercises/practice/binary-search/.meta/config.json @@ -1,5 +1,7 @@ { - "authors": [], + "authors": [ + "misicnenad" + ], "files": { "solution": [ "src/lib.cairo", diff --git a/exercises/practice/rational-numbers/.meta/config.json b/exercises/practice/rational-numbers/.meta/config.json index a78c8d78..a21bccaf 100644 --- a/exercises/practice/rational-numbers/.meta/config.json +++ b/exercises/practice/rational-numbers/.meta/config.json @@ -1,5 +1,7 @@ { - "authors": [], + "authors": [ + "misicnenad" + ], "files": { "solution": [ "src/lib.cairo", diff --git a/exercises/practice/simple-linked-list/.docs/instructions.md b/exercises/practice/simple-linked-list/.docs/instructions.md new file mode 100644 index 00000000..04640b1f --- /dev/null +++ b/exercises/practice/simple-linked-list/.docs/instructions.md @@ -0,0 +1,19 @@ +# Instructions + +Write a prototype of the music player application. + +For the prototype, each song will simply be represented by a number. +Given a range of numbers (the song IDs), create a singly linked list. + +Given a singly linked list, you should be able to reverse the list to play the songs in the opposite order. + +~~~~exercism/note +The linked list is a fundamental data structure in computer science, often used in the implementation of other data structures. + +The simplest kind of linked list is a **singly** linked list. +That means that each element (or "node") contains data, along with something that points to the next node in the list. + +If you want to dig deeper into linked lists, check out [this article][intro-linked-list] that explains it using nice drawings. + +[intro-linked-list]: https://medium.com/basecs/whats-a-linked-list-anyway-part-1-d8b7e6508b9d +~~~~ diff --git a/exercises/practice/simple-linked-list/.docs/introduction.md b/exercises/practice/simple-linked-list/.docs/introduction.md new file mode 100644 index 00000000..0e1df72f --- /dev/null +++ b/exercises/practice/simple-linked-list/.docs/introduction.md @@ -0,0 +1,5 @@ +# Introduction + +You work for a music streaming company. + +You've been tasked with creating a playlist feature for your music player application. diff --git a/exercises/practice/simple-linked-list/.meta/config.json b/exercises/practice/simple-linked-list/.meta/config.json new file mode 100644 index 00000000..d25bdbfd --- /dev/null +++ b/exercises/practice/simple-linked-list/.meta/config.json @@ -0,0 +1,20 @@ +{ + "authors": [ + "misicnenad" + ], + "files": { + "solution": [ + "src/lib.cairo", + "Scarb.toml" + ], + "test": [ + "src/tests.cairo" + ], + "example": [ + ".meta/example.cairo" + ] + }, + "blurb": "Write a simple linked list implementation that uses Elements and a List.", + "source": "Inspired by 'Data Structures and Algorithms with Object-Oriented Design Patterns in Ruby', singly linked-lists.", + "source_url": "https://web.archive.org/web/20160731005714/http://brpreiss.com/books/opus8/html/page96.html" +} diff --git a/exercises/practice/simple-linked-list/.meta/example.cairo b/exercises/practice/simple-linked-list/.meta/example.cairo new file mode 100644 index 00000000..62f025de --- /dev/null +++ b/exercises/practice/simple-linked-list/.meta/example.cairo @@ -0,0 +1,97 @@ +#[derive(Drop, Copy)] +struct SimpleLinkedList { + head: List, + len: usize, +} + +type List = Option>>; + +#[derive(Drop, Copy)] +struct Node { + data: T, + next: List, +} + +#[generate_trait] +impl SimpleLinkedListImpl, +Copy> of SimpleLinkedListTrait { + fn new() -> SimpleLinkedList { + SimpleLinkedList { head: Option::None, len: 0 } + } + + fn is_empty(self: @SimpleLinkedList) -> bool { + *self.len == 0 + } + + fn len(self: @SimpleLinkedList) -> usize { + *self.len + } + + fn push(ref self: SimpleLinkedList, element: T) { + let node = BoxTrait::new(NodeTrait::new(element, self.head)); + self.head = Option::Some(node); + self.len += 1; + } + + fn pop(ref self: SimpleLinkedList) -> Option { + match self.head { + Option::None => Option::None, + Option::Some(node) => { + self.len -= 1; + let node = node.unbox(); + self.head = node.next; + Option::Some(node.data) + } + } + } + + fn peek(self: @SimpleLinkedList) -> Option<@T> { + match *self.head { + Option::None => Option::None, + Option::Some(node) => Option::Some(@node.unbox().data) + } + } + + #[must_use] + fn rev(self: SimpleLinkedList) -> SimpleLinkedList { + let mut self = self; + let mut rev_list = SimpleLinkedListTrait::new(); + while let Option::Some(data) = self.pop() { + rev_list.push(data); + }; + rev_list + } +} + +impl ArrayIntoSimpleLinkedList, +Copy> of Into, SimpleLinkedList> { + #[must_use] + fn into(self: Array) -> SimpleLinkedList { + let mut self = self; + let mut list = SimpleLinkedListTrait::new(); + while let Option::Some(data) = self.pop_front() { + list.push(data); + }; + list + } +} + +impl SimpleLinkedListIntoArray, +Copy> of Into, Array> { + #[must_use] + fn into(self: SimpleLinkedList) -> Array { + let mut reversed = self.rev(); + let mut arr: Array = array![]; + while let Option::Some(data) = reversed.pop() { + arr.append(data); + }; + arr + } +} + +#[generate_trait] +impl NodeImpl of NodeTrait { + fn new(element: T, next: List) -> Node { + Node { data: element, next, } + } +} + +#[cfg(test)] +mod tests; diff --git a/exercises/practice/simple-linked-list/Scarb.toml b/exercises/practice/simple-linked-list/Scarb.toml new file mode 100644 index 00000000..6d571939 --- /dev/null +++ b/exercises/practice/simple-linked-list/Scarb.toml @@ -0,0 +1,4 @@ +[package] +name = "simple_linked_list" +version = "0.1.0" +edition = "2023_11" diff --git a/exercises/practice/simple-linked-list/src/lib.cairo b/exercises/practice/simple-linked-list/src/lib.cairo new file mode 100644 index 00000000..1db9b775 --- /dev/null +++ b/exercises/practice/simple-linked-list/src/lib.cairo @@ -0,0 +1,51 @@ +#[derive(Drop, Copy)] +struct SimpleLinkedList {} + +#[generate_trait] +impl SimpleLinkedListImpl, +Copy> of SimpleLinkedListTrait { + fn new() -> SimpleLinkedList { + panic!() + } + + fn is_empty(self: @SimpleLinkedList) -> bool { + panic!() + } + + fn len(self: @SimpleLinkedList) -> usize { + panic!() + } + + fn push(ref self: SimpleLinkedList, element: T) { + panic!() + } + + fn pop(ref self: SimpleLinkedList) -> Option { + panic!() + } + + fn peek(self: @SimpleLinkedList) -> Option<@T> { + panic!() + } + + #[must_use] + fn rev(self: SimpleLinkedList) -> SimpleLinkedList { + panic!() + } +} + +impl ArrayIntoSimpleLinkedList, +Copy> of Into, SimpleLinkedList> { + #[must_use] + fn into(self: Array) -> SimpleLinkedList { + panic!() + } +} + +impl SimpleLinkedListIntoArray, +Copy> of Into, Array> { + #[must_use] + fn into(self: SimpleLinkedList) -> Array { + panic!() + } +} + +#[cfg(test)] +mod tests; diff --git a/exercises/practice/simple-linked-list/src/tests.cairo b/exercises/practice/simple-linked-list/src/tests.cairo new file mode 100644 index 00000000..240db557 --- /dev/null +++ b/exercises/practice/simple-linked-list/src/tests.cairo @@ -0,0 +1,114 @@ +use simple_linked_list::{SimpleLinkedListTrait, SimpleLinkedList}; + +#[test] +fn new_list_is_empty() { + let list = SimpleLinkedListTrait::::new(); + assert_eq!(list.len(), 0, "list's length must be 0"); +} + +#[test] +fn push_increments_length() { + let mut list = SimpleLinkedListTrait::::new(); + list.push(1); + assert_eq!(list.len(), 1, "list's length must be 1"); + list.push(2); + assert_eq!(list.len(), 2, "list's length must be 2"); +} + +#[test] +fn pop_decrements_length() { + let mut list = SimpleLinkedListTrait::::new(); + list.push(1); + list.push(2); + list.pop().unwrap(); + assert_eq!(list.len(), 1, "list's length must be 1"); + list.pop().unwrap(); + assert_eq!(list.len(), 0, "list's length must be 0"); +} + +#[test] +fn pop_returns_head_element_and_removes_it() { + let mut list = SimpleLinkedListTrait::::new(); + list.push(1); + list.push(2); + assert_eq!(list.pop(), Option::Some(2), "Element must be 2"); + assert_eq!(list.pop(), Option::Some(1), "Element must be 1"); + let none: Option = Option::None; + assert_eq!(list.pop(), none, "No element should be contained in list"); +} + +#[test] +fn peek_returns_reference_to_head_element_but_does_not_remove_it() { + let mut list = SimpleLinkedListTrait::::new(); + let none: Option<@u32> = Option::None; + assert_eq!(list.peek(), none, "No element should be contained in list"); + list.push(2); + assert_eq!(list.peek(), Option::Some(@2), "Element must be 2"); + assert_eq!(list.peek(), Option::Some(@2), "Element must be still 2"); + list.push(3); + assert_eq!(list.peek(), Option::Some(@3), "Head element is now 3"); + assert_eq!(list.pop(), Option::Some(3), "Element must be 3"); + assert_eq!(list.peek(), Option::Some(@2), "Head element is now 2"); + assert_eq!(list.pop(), Option::Some(2), "Element must be 2"); + assert_eq!(list.peek(), none, "No element should be contained in list"); +} + +#[test] +fn reverse() { + let mut list = SimpleLinkedListTrait::::new(); + list.push(1); + list.push(2); + list.push(3); + let mut rev_list = list.rev(); + assert_eq!(rev_list.pop(), Option::Some(1)); + assert_eq!(rev_list.pop(), Option::Some(2)); + assert_eq!(rev_list.pop(), Option::Some(3)); + let none: Option = Option::None; + assert_eq!(rev_list.pop(), none); +} + +#[test] +fn reverse_empty_list() { + let mut list = SimpleLinkedListTrait::::new(); + let mut rev_list = list.rev(); + let none: Option = Option::None; + assert_eq!(rev_list.pop(), none); + assert_eq!(rev_list.len(), 0); +} + +#[test] +fn from_array() { + let mut array: Array = array![1, 2, 3, 4]; + let mut list: SimpleLinkedList = array.into(); + assert_eq!(list.pop(), Option::Some(4)); + assert_eq!(list.pop(), Option::Some(3)); + assert_eq!(list.pop(), Option::Some(2)); + assert_eq!(list.pop(), Option::Some(1)); +} + +#[test] +fn from_empty_array_is_empty_list() { + let mut array: Array = array![]; + let mut list: SimpleLinkedList = array.into(); + let none: Option = Option::None; + assert_eq!(list.pop(), none); + assert_eq!(list.len(), 0); +} + +#[test] +fn into_array() { + let mut list = SimpleLinkedListTrait::::new(); + list.push(1); + list.push(2); + list.push(3); + list.push(4); + let list_as_arr: Array = list.into(); + assert_eq!(array![1, 2, 3, 4], list_as_arr); +} + +#[test] +fn empty_list_into_empty_array() { + let mut list = SimpleLinkedListTrait::::new(); + let list_as_arr: Array = list.into(); + assert_eq!(array![], list_as_arr); +}