Skip to content

Commit

Permalink
Add Custom set exercise (#18)
Browse files Browse the repository at this point in the history
* Add init custom-set

* Implement the rest of funcs and tests

* Fix funcs 'new' and 'difference'

* refactor

* Add missing lib placeholder
  • Loading branch information
Nenad Misić committed Jun 24, 2024
1 parent 27cafba commit cf88075
Show file tree
Hide file tree
Showing 17 changed files with 742 additions and 1 deletion.
1 change: 1 addition & 0 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
scarb 2.6.5
7 changes: 7 additions & 0 deletions concepts/operator-overload/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"blurb": "<todo>",
"authors": [
"misicnenad"
],
"contributors": []
}
1 change: 1 addition & 0 deletions concepts/operator-overload/about.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Operator Overload
1 change: 1 addition & 0 deletions concepts/operator-overload/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Introduction
1 change: 1 addition & 0 deletions concepts/operator-overload/links.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[]
7 changes: 7 additions & 0 deletions concepts/structs/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"blurb": "<todo>",
"authors": [
"misicnenad"
],
"contributors": []
}
1 change: 1 addition & 0 deletions concepts/structs/about.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Structs
1 change: 1 addition & 0 deletions concepts/structs/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Introduction
1 change: 1 addition & 0 deletions concepts/structs/links.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[]
30 changes: 29 additions & 1 deletion config.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,28 @@
"slug": "low-power-embedded-game",
"name": "low-power-embedded-game",
"uuid": "f3b7ce44-1667-42b4-b792-401d36aee2f1",
"practices": ["tuples", "traits", "control-flow"],
"practices": [
"tuples",
"traits"
],
"prerequisites": [],
"difficulty": 2
},
{
"slug": "custom-set",
"name": "Custom Set",
"uuid": "aad80498-750c-4a7d-b82a-f52f90c54e11",
"practices": [
"structs",
"traits",
"operator-overload"
],
"prerequisites": [],
"difficulty": 4
}
],
"foregone": [
"hangman"
]
},
"concepts": [
Expand Down Expand Up @@ -164,6 +182,16 @@
"uuid": "fe83c9a6-cf50-47b1-9993-21ddd1e895ee",
"slug": "traits",
"name": "Traits"
},
{
"uuid": "4e1f6433-3125-4428-837d-47b0c10fddea",
"slug": "structs",
"name": "Structs"
},
{
"uuid": "0b069f59-f8b4-4979-935a-c3172538f4c9",
"slug": "operator-overload",
"name": "Operator Overload"
}
],
"key_features": [
Expand Down
7 changes: 7 additions & 0 deletions exercises/practice/custom-set/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Instructions

Create a custom set type.

Sometimes it is necessary to define a custom data structure of some type, like a set.
In this exercise you will define your own set.
How it works internally doesn't matter, as long as it behaves like a set of unique elements.
18 changes: 18 additions & 0 deletions exercises/practice/custom-set/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"authors": [
"misicnenad"
],
"files": {
"solution": [
"src/lib.cairo",
"Scarb.toml"
],
"test": [
"src/tests.cairo"
],
"example": [
".meta/example.cairo"
]
},
"blurb": "Create a custom set type."
}
175 changes: 175 additions & 0 deletions exercises/practice/custom-set/.meta/example.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
use core::clone::Clone;
use core::array::ArrayTrait;
use core::box::BoxTrait;

#[derive(Drop, Debug)]
pub struct CustomSet<T> {
pub collection: Array<T>,
}

pub impl CustomSetEq<
T, +Copy<T>, +Drop<T>, +PartialEq<T>, +core::fmt::Display<T>
> of PartialEq<CustomSet<T>> {
fn eq(lhs: @CustomSet<T>, rhs: @CustomSet<T>) -> bool {
if lhs.collection.len() != rhs.collection.len() {
return false;
}
lhs.is_subset(rhs) && rhs.is_subset(lhs)
}

fn ne(lhs: @CustomSet<T>, rhs: @CustomSet<T>) -> bool {
!(lhs == rhs)
}
}

#[generate_trait]
pub impl CustomSetImpl<
T, +Copy<T>, +Drop<T>, +core::fmt::Display<T>, +PartialEq<T>
> of CustomSetTrait<T> {
fn new(inputs: @Array<T>) -> CustomSet<T> {
let mut set = CustomSet::<T> { collection: array![], };
let mut i = 0;
while let Option::Some(val) = inputs
.get(i) {
let unboxed = val.unbox();
set.add(unboxed.clone());
i += 1;
};
set
}

fn add(ref self: CustomSet<T>, element: T) {
if !self.contains(@element) {
self.collection.append(element)
}
}

fn contains(self: @CustomSet<T>, other: @T) -> bool {
let mut is_contained = false;
let mut i = 0;
while let Option::Some(boxed) = self
.collection
.get(i) {
let val = boxed.unbox();
if val == other {
is_contained = true;
break;
}
i += 1;
};
is_contained
}

fn is_empty(self: @CustomSet<T>) -> bool {
self.collection.is_empty()
}

fn is_subset(self: @CustomSet<T>, other: @CustomSet<T>) -> bool {
if self.collection.len() > other.collection.len() {
return false;
}
let mut result = true;
let mut i = 0;
while let Option::Some(val) = self
.collection
.get(i) {
if !other.contains(val.unbox()) {
result = false;
break;
}
i += 1;
};
result
}

fn is_disjoint(self: @CustomSet<T>, other: @CustomSet<T>) -> bool {
let mut are_disjoint = true;

// a more efficient way is to iterate the smaller set
let mut to_iterate = self;
let mut to_compare = other;
if to_iterate.collection.len() > to_compare.collection.len() {
to_iterate = other;
to_compare = self;
};

let mut i = 0;
while let Option::Some(val) = to_iterate
.collection
.get(i) {
if to_compare.contains(val.unbox()) {
are_disjoint = false;
break;
}
i += 1;
};

are_disjoint
}

#[must_use]
fn intersection(self: @CustomSet<T>, other: @CustomSet<T>) -> CustomSet<T> {
let mut collection: Array<T> = array![];

// a more efficient way is to iterate the smaller set
let mut to_iterate = self;
let mut to_compare = other;
if to_iterate.collection.len() > to_compare.collection.len() {
to_iterate = other;
to_compare = self;
};

let mut i = 0;
while let Option::Some(val) = to_iterate
.collection
.get(i) {
let unboxed = val.unbox();
if to_compare.contains(unboxed) {
collection.append(*unboxed);
}
i += 1;
};

CustomSetImpl::<T>::new(@collection)
}

#[must_use]
fn union(self: @CustomSet<T>, other: @CustomSet<T>) -> CustomSet<T> {
let mut collection: Array<T> = array![];
let mut i = 0;
while let Option::Some(val) = self
.collection
.get(i) {
collection.append(*val.unbox());
i += 1;
};
i = 0;
while let Option::Some(val) = other
.collection
.get(i) {
collection.append(*val.unbox());
i += 1;
};
CustomSetImpl::<T>::new(@collection)
}

#[must_use]
fn difference(self: @CustomSet<T>, other: @CustomSet<T>) -> CustomSet<T> {
let mut collection: Array<T> = array![];
let mut i = 0;
while let Option::Some(val) = self
.collection
.get(i) {
let unboxed = val.unbox();
if !other.contains(unboxed) {
collection.append(unboxed.clone());
}
i += 1;
};
CustomSetImpl::<T>::new(@collection)
}
}


#[cfg(test)]
mod tests;
Loading

0 comments on commit cf88075

Please sign in to comment.