From 91d8a54f45814e8d76fec9ecdfce766c2d0b0529 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Wed, 10 Jul 2024 01:32:34 +0100 Subject: [PATCH 01/63] Added introduction for strings --- concepts/strings/.meta/config.json | 8 ++---- concepts/strings/about.md | 46 ++++++++++++++++++++++++++++++ concepts/strings/links.json | 28 ++++++++++-------- 3 files changed, 65 insertions(+), 17 deletions(-) diff --git a/concepts/strings/.meta/config.json b/concepts/strings/.meta/config.json index 52914445..f534eb7a 100644 --- a/concepts/strings/.meta/config.json +++ b/concepts/strings/.meta/config.json @@ -1,7 +1,5 @@ { - "blurb": "", - "authors": [ - "misicnenad" - ], - "contributors": [] + "blurb": "", + "authors": ["misicnenad", "Ephraim-nonso"], + "contributors": [] } diff --git a/concepts/strings/about.md b/concepts/strings/about.md index 0690082b..3a2e68f4 100644 --- a/concepts/strings/about.md +++ b/concepts/strings/about.md @@ -1 +1,47 @@ # String Types + +## String Type + +Cairo do not have a native data type for strings. However, there are two ways to form a string type: short strings and ByteArray. + +### Short strings + +A short string is formed with a single quote where each character that makes up the string is encoded on one byte - [see ASCII table](https://www.asciitable.com/). + +As a ASCII string, for instance, 'abc' will be: + +- 'a' results to 0x61 +- 'b' results to 0x62 +- 'c' results to 0x63 +- 'abc' results to 0x616263 + +The felt252 data type can hold short strings type in Cairo. A felt252 short string is limited to 31 characters due to the size of felt252 being 251 bits. + +Examples of short strings declarations: + +```rust + let my_first_char = 'D'; + let my_first_char_in_hex = 0x44; + + let my_first_string = 'Hello world'; + let my_first_string_in_hex = 0x48656C6C6F20776F726C64; +``` + +### ByteArray + +The ByteArray struct was introduced in Cairo 2.4.0. The ByteArray strings are written in double quotes as follows: + +```Rust + let long_string: ByteArray = "this is a string which has more than 31 characters"; +``` + +Technically, the update also introduced the `bytes31` which holds 31 bytes and which fits into a felt. The ByteArray struct is made of an array of 31 byte, a single felt and length for the remainder. + +```Rust +#[derive(Drop, Clone, PartialEq, Serde, Default)] +struct ByteArray { + data: Array, + pending_word: felt252, + pending_word_len: usize, +} +``` diff --git a/concepts/strings/links.json b/concepts/strings/links.json index fe904e3b..846abe8a 100644 --- a/concepts/strings/links.json +++ b/concepts/strings/links.json @@ -1,14 +1,18 @@ [ - { - "url": "https://book.cairo-lang.org/ch02-02-data-types.html#string-types", - "description": "String types in the Cairo book" - }, - { - "url": "https://starknet-by-example.voyager.online/getting-started/basics/bytearrays-strings.html", - "description": "Starknet by Example section on Strings and ByteArrays" - }, - { - "url": "https://docs.starknet.io/architecture-and-concepts/smart-contracts/serialization-of-cairo-types/#serialization_of_byte_arrays", - "description": "Starknet docs explaining how ByteArray is implemented and how it's serialized" - } + { + "url": "https://book.cairo-lang.org/ch02-02-data-types.html#string-types", + "description": "String types in the Cairo book" + }, + { + "url": "https://starknet-by-example.voyager.online/getting-started/basics/bytearrays-strings.html", + "description": "Starknet by Example section on Strings and ByteArrays" + }, + { + "url": "https://docs.starknet.io/architecture-and-concepts/smart-contracts/serialization-of-cairo-types/#serialization_of_byte_arrays", + "description": "Starknet docs explaining how ByteArray is implemented and how it's serialized" + }, + { + "url": "https://community.starknet.io/t/cairo-v2-4-0-is-out/109275", + "description": "Cairo v2.4.0 is out" + } ] From e90852c4d3ae9292ff680e5adc67d887ebae03f1 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Wed, 10 Jul 2024 01:35:30 +0100 Subject: [PATCH 02/63] Added blurb for strings --- concepts/strings/.meta/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/strings/.meta/config.json b/concepts/strings/.meta/config.json index f534eb7a..63cce187 100644 --- a/concepts/strings/.meta/config.json +++ b/concepts/strings/.meta/config.json @@ -1,5 +1,5 @@ { - "blurb": "", + "blurb": "Cairo do not have a native data type for strings. However, there are two ways to form a string type: short strings and ByteArray.", "authors": ["misicnenad", "Ephraim-nonso"], "contributors": [] } From ac52fe15686af39b6861c5e47c52574389901d0a Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Wed, 10 Jul 2024 13:53:15 +0100 Subject: [PATCH 03/63] Changed to review --- concepts/strings/.meta/config.json | 4 ++-- concepts/strings/about.md | 24 +++++++++++------------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/concepts/strings/.meta/config.json b/concepts/strings/.meta/config.json index 63cce187..110d810e 100644 --- a/concepts/strings/.meta/config.json +++ b/concepts/strings/.meta/config.json @@ -1,5 +1,5 @@ { - "blurb": "Cairo do not have a native data type for strings. However, there are two ways to form a string type: short strings and ByteArray.", - "authors": ["misicnenad", "Ephraim-nonso"], + "blurb": "Cairo does not have a native data type for strings. However, there are two ways to represent a string type: short strings using felts and ByteArray.", + "authors": ["Ephraim-nonso"], "contributors": [] } diff --git a/concepts/strings/about.md b/concepts/strings/about.md index 3a2e68f4..995f2c32 100644 --- a/concepts/strings/about.md +++ b/concepts/strings/about.md @@ -1,23 +1,21 @@ # String Types -## String Type +Cairo does not have a native data type for strings. However, there are two ways to represent a string type: short strings using a single `felt252` and arbitrary length using `ByteArray`. -Cairo do not have a native data type for strings. However, there are two ways to form a string type: short strings and ByteArray. +## Short strings -### Short strings +A short string is formed with single quotes where each character that makes up the string is encoded on one byte following the [ASCII standard](https://www.asciitable.com/). -A short string is formed with a single quote where each character that makes up the string is encoded on one byte - [see ASCII table](https://www.asciitable.com/). +As an ASCII string, for instance, `'abc'` will be: -As a ASCII string, for instance, 'abc' will be: +- `'a'` results to `0x61` +- `'b'` results to `0x62` +- `'c'` results to `0x63` +- `'abc'` results to `0x616263` -- 'a' results to 0x61 -- 'b' results to 0x62 -- 'c' results to 0x63 -- 'abc' results to 0x616263 +The `felt252` data type holds short strings type in Cairo. As `felt252` contains 251 bits, a short string is limited to 31 characters (31 \* 8 = 248 bits, which is the maximum multiple of 8 that fits in 251 bits). -The felt252 data type can hold short strings type in Cairo. A felt252 short string is limited to 31 characters due to the size of felt252 being 251 bits. - -Examples of short strings declarations: +Examples of short string declarations: ```rust let my_first_char = 'D'; @@ -35,7 +33,7 @@ The ByteArray struct was introduced in Cairo 2.4.0. The ByteArray strings are wr let long_string: ByteArray = "this is a string which has more than 31 characters"; ``` -Technically, the update also introduced the `bytes31` which holds 31 bytes and which fits into a felt. The ByteArray struct is made of an array of 31 byte, a single felt and length for the remainder. +Technically, the update also introduced the `bytes31` type which holds 31 bytes and which fits into a felt. The `ByteArray` struct basically represents long string using an array of `bytes31` that hold the "whole words" (i.e. words that fill the whole felt) and a single felt field that holds an "incomplete word" (the number of bytes within are specified in separate length field). ```Rust #[derive(Drop, Clone, PartialEq, Serde, Default)] From e865f05804f24e6bc984f3575c7bbcabe79de5d4 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Wed, 10 Jul 2024 14:22:50 +0100 Subject: [PATCH 04/63] One change --- concepts/strings/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/strings/about.md b/concepts/strings/about.md index 995f2c32..165c8d12 100644 --- a/concepts/strings/about.md +++ b/concepts/strings/about.md @@ -1,6 +1,6 @@ # String Types -Cairo does not have a native data type for strings. However, there are two ways to represent a string type: short strings using a single `felt252` and arbitrary length using `ByteArray`. +Cairo does not have a native data type for strings. However, there are two ways to represent a string type: short strings using a single `felt252` and arbitrary length strings using `ByteArray`. ## Short strings From 96d9bca0f7286447c8a36e913cd6a51245bc429f Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Wed, 10 Jul 2024 14:27:19 +0100 Subject: [PATCH 05/63] Change wordings for clarity --- concepts/strings/about.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/concepts/strings/about.md b/concepts/strings/about.md index 165c8d12..7b4117c1 100644 --- a/concepts/strings/about.md +++ b/concepts/strings/about.md @@ -8,10 +8,10 @@ A short string is formed with single quotes where each character that makes up t As an ASCII string, for instance, `'abc'` will be: -- `'a'` results to `0x61` -- `'b'` results to `0x62` -- `'c'` results to `0x63` -- `'abc'` results to `0x616263` +- `'a'` is equivalent to `0x61` +- `'b'` is equivalent to `0x62` +- `'c'` is equivalent to `0x63` +- `'abc'` is equivalent to `0x616263` The `felt252` data type holds short strings type in Cairo. As `felt252` contains 251 bits, a short string is limited to 31 characters (31 \* 8 = 248 bits, which is the maximum multiple of 8 that fits in 251 bits). From 52de5af2ed37c5b775854624f19bd8d7d055b922 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Sun, 14 Jul 2024 10:55:55 +0100 Subject: [PATCH 06/63] Enums Data Type --- concepts/enums/.meta/config.json | 8 +- concepts/enums/about.md | 135 +++++++++++++++++++++++++++++++ concepts/enums/introduction.md | 2 + concepts/enums/links.json | 11 ++- 4 files changed, 150 insertions(+), 6 deletions(-) diff --git a/concepts/enums/.meta/config.json b/concepts/enums/.meta/config.json index 52914445..f9683ed1 100644 --- a/concepts/enums/.meta/config.json +++ b/concepts/enums/.meta/config.json @@ -1,7 +1,5 @@ { - "blurb": "", - "authors": [ - "misicnenad" - ], - "contributors": [] + "blurb": "Enums are cairo data type used to define a set of predefined variants for the purpose of code readability and safety.", + "authors": ["Ephraim-nonso"], + "contributors": [] } diff --git a/concepts/enums/about.md b/concepts/enums/about.md index ece8d08a..409128c4 100644 --- a/concepts/enums/about.md +++ b/concepts/enums/about.md @@ -1 +1,136 @@ # Enums + +Enums are cairo data type used to define a set of predefined variants for the purpose of code readability and safety. In Cairo, `enum` variants can be declared to hold different data types (uint, struct, tuples, arrays, dictionaries, core default library, other enums). + +The code snippet below shows how enums could be defined: + +### Simple example of an enum with no associated value + +```Rust + #[derive(Drop)] + enum Direction { + North, + East, + South, + West, + } +``` + +The `Direction` enum declared above is a simple enum with four variants: `North`, `East`, `South`, and `West`. Notice that the variants are declared in PascalCase, being the recommended naming convention. Each variant represents a distinct value of the `Direction` enum type. Each variant in this particular enum example has no associated value and be instantiated using this syntax: + +```Rust + let direction = Direction::North; +``` + +### Simple example of an enum with associated value + +```Rust + #[derive(Drop)] + enum Direction { + North: u128, + East: u128, + South: u128, + West: u128, + } +``` + +It is evident from the second example that each variant in the `Direction` enum has an associated value of `u128`. This kind of enum is instantiated as follows: + +```Rust + let direction = Direction::North(10); +``` + +### Complex example of an enum with combined custom types + +```Rust + #[derive(Drop, Serde, Copy, starknet::Store)] + struct Move { + up: u32, + down: u32, + right: u32, + left: u32, + } + + #[derive(Drop, Serde, Copy, starknet::Store)] + enum UserCommand { + Login, + UpdateProfile, + Logout, + } + + #[derive(Drop, Serde, Copy, starknet::Store)] + enum Action { + Quit, + Direction: Move, + SendMessage: felt252, + ChangeAvatarColor: (u8, u8, u8), + ProfileState: UserCommand + } +``` + +An enum can be declared with a combination of custom data types as its variants. In the example above, the `Action` is the complex enum that as a collection of `Quit` (variant with no associated value), `Direction` (variant with the `Move` struct associated value), `SendMessage` (a single felt252 variant), `ChangeAvatar` (variant with the tuple of three associated value), and `ProfileState` (variant with an enum associated value). + +You can declare an enum inside and outside of a contract. If declared outside, then it should be imported inside a contract with the `use` keyword. + +## Trait Implementations for Enums + +In Cairo, traits could be defined and implemented on custom enums. This allows for you to define methods and attributes associated with the enum. We will implement a `Processing` trait on a `Message` enum. + +```Rust + #[derive(Drop)] + enum Message { + Quit, + Echo: felt252, + Move: (u128, u128), + } +``` + +The `Message` enum is made up of: + +~ `Quit` has no associated value. + +~ `Echo` is a single felt252 value. + +~ `Move` is a tuple of two u128 values. + +```Rust +trait Processing { + fn process(self: Message); +} + +impl ProcessingImpl of Processing { + fn process(self: Message) { + match self { + Message::Quit => { println!("quitting") }, + Message::Echo(value) => { println!("echoing {}", value) }, + Message::Move((x, y)) => { println!("moving from {} to {}", x, y) }, + } + } +} +``` + +In many situations, enums can come in handy especially when used with the `match` flow as used above in the traits implementation. + +Here is how it could be used to process a Quit message: + +```Rust + let msg: Message = Message::Quit; + msg.process(); +``` + +Running this code would print `quitting`. + +## The `Option` Enum and its Advantages + +The `Option` enum is a standard Cairo enum that represents the concept of an optional value. It has two variants: `Some: T` and `None`. `Some` variant has an associated value of type `T`, while `None` represents the absence of an associated value. + +```Rust +enum Option { + Some: T, + None, +} +``` + +The Option enum is helpful because it allows you to explicitly represent the possibility of a value being absent, making your code more expressive and easier to reason about. Using Option can also help prevent bugs caused by using uninitialized or unexpected null values. + +Other native enums such as `Result` enum, allows for thorough error handling. The Result enum is will explained in details in the `Error Handling` chapter. diff --git a/concepts/enums/introduction.md b/concepts/enums/introduction.md index e10b99d0..9370b8f5 100644 --- a/concepts/enums/introduction.md +++ b/concepts/enums/introduction.md @@ -1 +1,3 @@ # Introduction + +Similar to other programming languages, enums, short for `enumerations`, are used in cairo to define custom data type that holds a collection of fixed set of named values called variants. Each variant that makes up an enum is distinct and has a specific meaning. diff --git a/concepts/enums/links.json b/concepts/enums/links.json index fe51488c..4bb78629 100644 --- a/concepts/enums/links.json +++ b/concepts/enums/links.json @@ -1 +1,10 @@ -[] +[ + { + "url": "https://book.cairo-lang.org/ch06-01-enums.html?highlight=En#enums", + "description": "String types in the Cairo book" + }, + { + "url": "https://starknet-by-example.voyager.online/getting-started/cairo_cheatsheet/enums.html?highlight=enum#enums", + "description": "Starknet by Example section on Enums" + } +] From c96e3f48b275416e5ae64ab78fb3e431f8da388a Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Tue, 16 Jul 2024 04:56:36 +0100 Subject: [PATCH 07/63] Update:Changes on Enums Data Type --- concepts/enums/.meta/config.json | 2 +- concepts/enums/about.md | 97 +++++++++++++++++--------------- concepts/enums/introduction.md | 2 +- concepts/enums/links.json | 6 +- 4 files changed, 58 insertions(+), 49 deletions(-) diff --git a/concepts/enums/.meta/config.json b/concepts/enums/.meta/config.json index f9683ed1..5fee2aa3 100644 --- a/concepts/enums/.meta/config.json +++ b/concepts/enums/.meta/config.json @@ -1,5 +1,5 @@ { - "blurb": "Enums are cairo data type used to define a set of predefined variants for the purpose of code readability and safety.", + "blurb": "Enums are Cairo data type used to define a set of predefined variants for the purpose of code readability and safety.", "authors": ["Ephraim-nonso"], "contributors": [] } diff --git a/concepts/enums/about.md b/concepts/enums/about.md index 409128c4..41fcda2d 100644 --- a/concepts/enums/about.md +++ b/concepts/enums/about.md @@ -1,11 +1,9 @@ # Enums -Enums are cairo data type used to define a set of predefined variants for the purpose of code readability and safety. In Cairo, `enum` variants can be declared to hold different data types (uint, struct, tuples, arrays, dictionaries, core default library, other enums). +Enums are cairo data type used to define a set of predefined variants for the purpose of code readability and safety. In Cairo, `enum` variants can be declared to hold different data types (integers, structs, tuples, other enums, etc.). The code snippet below shows how enums could be defined: -### Simple example of an enum with no associated value - ```Rust #[derive(Drop)] enum Direction { @@ -16,13 +14,13 @@ The code snippet below shows how enums could be defined: } ``` -The `Direction` enum declared above is a simple enum with four variants: `North`, `East`, `South`, and `West`. Notice that the variants are declared in PascalCase, being the recommended naming convention. Each variant represents a distinct value of the `Direction` enum type. Each variant in this particular enum example has no associated value and be instantiated using this syntax: +The `Direction` enum declared above is a simple enum with four variants: `North`, `East`, `South`, and `West`. The naming convention is to use PascalCase for enum variants. Each variant represents a distinct value of the `Direction` enum type. Each variant in this particular enum example has no associated value and can be instantiated using this syntax: ```Rust let direction = Direction::North; ``` -### Simple example of an enum with associated value +### Enum Variants and Values ```Rust #[derive(Drop)] @@ -34,16 +32,18 @@ The `Direction` enum declared above is a simple enum with four variants: `North` } ``` -It is evident from the second example that each variant in the `Direction` enum has an associated value of `u128`. This kind of enum is instantiated as follows: +It is evident from this example that each variant in the `Direction` enum has an associated value of `u128`. This kind of enum is instantiated as follows: ```Rust let direction = Direction::North(10); ``` -### Complex example of an enum with combined custom types +## Complex example of an enum combined with custom types + +An enum can be declared with a combination of custom data types as its variants. In the example below, `Action` is the complex enum that as a collection of `Quit`, `Direction`, `SendMessage`, `ChangeAvatar`, and `ProfileState`. ```Rust - #[derive(Drop, Serde, Copy, starknet::Store)] + #[derive(Drop)] struct Move { up: u32, down: u32, @@ -51,30 +51,28 @@ It is evident from the second example that each variant in the `Direction` enum left: u32, } - #[derive(Drop, Serde, Copy, starknet::Store)] + #[derive(Drop)] enum UserCommand { Login, UpdateProfile, Logout, } - #[derive(Drop, Serde, Copy, starknet::Store)] + #[derive(Drop)] enum Action { - Quit, - Direction: Move, - SendMessage: felt252, - ChangeAvatarColor: (u8, u8, u8), - ProfileState: UserCommand + Quit, // variant with no associated value + Direction: Move, // variant with the `Move` struct associated value + SendMessage: felt252, // a single felt252 variant + ChangeAvatarColor: (u8, u8, u8), // variant with the tuple of three associated value + ProfileState: UserCommand // variant with an enum associated value } ``` -An enum can be declared with a combination of custom data types as its variants. In the example above, the `Action` is the complex enum that as a collection of `Quit` (variant with no associated value), `Direction` (variant with the `Move` struct associated value), `SendMessage` (a single felt252 variant), `ChangeAvatar` (variant with the tuple of three associated value), and `ProfileState` (variant with an enum associated value). - -You can declare an enum inside and outside of a contract. If declared outside, then it should be imported inside a contract with the `use` keyword. +You can declare an enum inside and outside of a Cairo file. If declared outside, then it should be imported inside the base file with the `use` keyword. ## Trait Implementations for Enums -In Cairo, traits could be defined and implemented on custom enums. This allows for you to define methods and attributes associated with the enum. We will implement a `Processing` trait on a `Message` enum. +In Cairo, traits can be defined and implemented on custom enums. This allows for you to define methods and attributes associated with an enum. We will first define a `Message` enum and implement a `Processing` trait for it: ```Rust #[derive(Drop)] @@ -83,35 +81,25 @@ In Cairo, traits could be defined and implemented on custom enums. This allows f Echo: felt252, Move: (u128, u128), } -``` - -The `Message` enum is made up of: - -~ `Quit` has no associated value. - -~ `Echo` is a single felt252 value. - -~ `Move` is a tuple of two u128 values. -```Rust -trait Processing { - fn process(self: Message); -} + trait Processing { + fn process(self: Message); + } -impl ProcessingImpl of Processing { - fn process(self: Message) { - match self { - Message::Quit => { println!("quitting") }, - Message::Echo(value) => { println!("echoing {}", value) }, - Message::Move((x, y)) => { println!("moving from {} to {}", x, y) }, + impl ProcessingImpl of Processing { + fn process(self: Message) { + match self { + Message::Quit => { println!("quitting") }, + Message::Echo(value) => { println!("echoing {}", value) }, + Message::Move((x, y)) => { println!("moving from {} to {}", x, y) }, + } } } -} ``` -In many situations, enums can come in handy especially when used with the `match` flow as used above in the traits implementation. +In many situations, enums can come in handy especially when used with the `match` flow as used above in the traits implementation. There is a chapter that explains in detail the `match` flow. -Here is how it could be used to process a Quit message: +Here is how it could be used to process a `Quit` message: ```Rust let msg: Message = Message::Quit; @@ -120,7 +108,7 @@ Here is how it could be used to process a Quit message: Running this code would print `quitting`. -## The `Option` Enum and its Advantages +## The `Option` Enum and Its Advantages The `Option` enum is a standard Cairo enum that represents the concept of an optional value. It has two variants: `Some: T` and `None`. `Some` variant has an associated value of type `T`, while `None` represents the absence of an associated value. @@ -131,6 +119,27 @@ enum Option { } ``` -The Option enum is helpful because it allows you to explicitly represent the possibility of a value being absent, making your code more expressive and easier to reason about. Using Option can also help prevent bugs caused by using uninitialized or unexpected null values. +The `Option` enum is helpful because it allows you to explicitly represent the possibility of a value being absent, making your code more expressive and easier to reason about. Using `Option` can also help prevent bugs caused by using uninitialized or unexpected `null` values. + +The function below shows how the `Option` enum is used to return the first elements of an array with a given value, or return `None` if the element is absent. + +```Rust +fn find_value_iterative(mut arr: Span, value: felt252) -> Option { + let mut result = Option::None; + let mut index = 0; + + while let Option::Some(array_value) = arr + .pop_front() { + if (*array_value == value) { + result = Option::Some(index); + break; + }; + + index += 1; + }; + + result +} +``` -Other native enums such as `Result` enum, allows for thorough error handling. The Result enum is will explained in details in the `Error Handling` chapter. +There are other native enums, one of which is the `Result` enum, which allows for graceful error handling. The `Result` enum will be explained in detail in the `Error Handling` chapter. diff --git a/concepts/enums/introduction.md b/concepts/enums/introduction.md index 9370b8f5..291ad528 100644 --- a/concepts/enums/introduction.md +++ b/concepts/enums/introduction.md @@ -1,3 +1,3 @@ # Introduction -Similar to other programming languages, enums, short for `enumerations`, are used in cairo to define custom data type that holds a collection of fixed set of named values called variants. Each variant that makes up an enum is distinct and has a specific meaning. +Similar to other programming languages, enums, short for `enumerations`, are used in cairo to define custom data types that hold a collection of fixed set of named values called _variants_. Each variant that makes up an enum is distinct and has a specific meaning. diff --git a/concepts/enums/links.json b/concepts/enums/links.json index 4bb78629..c66e0047 100644 --- a/concepts/enums/links.json +++ b/concepts/enums/links.json @@ -1,10 +1,10 @@ [ { - "url": "https://book.cairo-lang.org/ch06-01-enums.html?highlight=En#enums", - "description": "String types in the Cairo book" + "url": "https://book.cairo-lang.org/ch06-01-enums.html", + "description": "Enum types in the Cairo book" }, { - "url": "https://starknet-by-example.voyager.online/getting-started/cairo_cheatsheet/enums.html?highlight=enum#enums", + "url": "https://starknet-by-example.voyager.online/getting-started/cairo_cheatsheet/enums.html", "description": "Starknet by Example section on Enums" } ] From 8a8a8cf6b72c4dc0d9e3d8b799213caf47370ba5 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Tue, 16 Jul 2024 05:04:24 +0100 Subject: [PATCH 08/63] Update:Changes on Enums Data Type --- concepts/enums/about.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/concepts/enums/about.md b/concepts/enums/about.md index 41fcda2d..35f67937 100644 --- a/concepts/enums/about.md +++ b/concepts/enums/about.md @@ -40,7 +40,7 @@ It is evident from this example that each variant in the `Direction` enum has an ## Complex example of an enum combined with custom types -An enum can be declared with a combination of custom data types as its variants. In the example below, `Action` is the complex enum that as a collection of `Quit`, `Direction`, `SendMessage`, `ChangeAvatar`, and `ProfileState`. +An enum can be declared with a combination of custom data types as its variants. In the example below, `Action` is the complex enum that as a collection of `Quit`, `Direction`, `SendMessage`, `ChangeAvatar`, and `ProfileState` as variants. ```Rust #[derive(Drop)] @@ -121,7 +121,7 @@ enum Option { The `Option` enum is helpful because it allows you to explicitly represent the possibility of a value being absent, making your code more expressive and easier to reason about. Using `Option` can also help prevent bugs caused by using uninitialized or unexpected `null` values. -The function below shows how the `Option` enum is used to return the first elements of an array with a given value, or return `None` if the element is absent. +The function below shows how the `Option` enum is used to return the first element of an array with a given value, or return `None` if the element is absent. ```Rust fn find_value_iterative(mut arr: Span, value: felt252) -> Option { From 978ac07cb718355171bf60a3787c6f3495eef357 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Tue, 16 Jul 2024 11:54:44 +0100 Subject: [PATCH 09/63] New:Changes on Enums Data Type --- concepts/enums/about.md | 128 ++++++++++++++++----------------- concepts/enums/introduction.md | 2 +- 2 files changed, 64 insertions(+), 66 deletions(-) diff --git a/concepts/enums/about.md b/concepts/enums/about.md index 35f67937..d4b90457 100644 --- a/concepts/enums/about.md +++ b/concepts/enums/about.md @@ -1,109 +1,107 @@ # Enums -Enums are cairo data type used to define a set of predefined variants for the purpose of code readability and safety. In Cairo, `enum` variants can be declared to hold different data types (integers, structs, tuples, other enums, etc.). +Enums are Cairo data type used to define a set of predefined variants for the purpose of code readability and safety. In Cairo, `enum` variants can be declared to hold different data types (integers, structs, tuples, other enums, etc.). The code snippet below shows how enums could be defined: ```Rust - #[derive(Drop)] - enum Direction { - North, - East, - South, - West, - } +#[derive(Drop)] +enum Direction { + North, + East, + South, + West, +} ``` The `Direction` enum declared above is a simple enum with four variants: `North`, `East`, `South`, and `West`. The naming convention is to use PascalCase for enum variants. Each variant represents a distinct value of the `Direction` enum type. Each variant in this particular enum example has no associated value and can be instantiated using this syntax: ```Rust - let direction = Direction::North; +let direction = Direction::North; ``` -### Enum Variants and Values +Below is the same `Direction` enum, but with variants that have associated values, that store the exact degree of the direction: ```Rust - #[derive(Drop)] - enum Direction { - North: u128, - East: u128, - South: u128, - West: u128, - } +#[derive(Drop)] +enum Direction { + North: u128, + East: u128, + South: u128, + West: u128, +} ``` -It is evident from this example that each variant in the `Direction` enum has an associated value of `u128`. This kind of enum is instantiated as follows: +It is evident from this example that each variant in the `Direction` enum has an associated value of `u128`. This kind of enum can be instantiated as follows: ```Rust - let direction = Direction::North(10); +let direction = Direction::North(10); ``` ## Complex example of an enum combined with custom types -An enum can be declared with a combination of custom data types as its variants. In the example below, `Action` is the complex enum that as a collection of `Quit`, `Direction`, `SendMessage`, `ChangeAvatar`, and `ProfileState` as variants. +An enum can be declared with a combination of different data types as its variants. In the example below, `Action` is a complex enum that as a collection of `Quit`, `Direction`, `SendMessage`, `ChangeAvatar`, and `ProfileState` as variants. ```Rust - #[derive(Drop)] - struct Move { - up: u32, - down: u32, - right: u32, - left: u32, - } +#[derive(Drop)] +struct Move { + up: u32, + down: u32, + right: u32, + left: u32, +} - #[derive(Drop)] - enum UserCommand { - Login, - UpdateProfile, - Logout, - } +#[derive(Drop)] +enum UserCommand { + Login, + UpdateProfile, + Logout, +} - #[derive(Drop)] - enum Action { - Quit, // variant with no associated value - Direction: Move, // variant with the `Move` struct associated value - SendMessage: felt252, // a single felt252 variant - ChangeAvatarColor: (u8, u8, u8), // variant with the tuple of three associated value - ProfileState: UserCommand // variant with an enum associated value - } +#[derive(Drop)] +enum Action { + Quit, // variant with no associated value + Direction: Move, // variant with the `Move` struct associated value + SendMessage: felt252, // a single felt252 variant + ChangeAvatarColor: (u8, u8, u8), // variant with the tuple of three associated values + ProfileState: UserCommand // variant with an enum associated value +} ``` -You can declare an enum inside and outside of a Cairo file. If declared outside, then it should be imported inside the base file with the `use` keyword. - ## Trait Implementations for Enums In Cairo, traits can be defined and implemented on custom enums. This allows for you to define methods and attributes associated with an enum. We will first define a `Message` enum and implement a `Processing` trait for it: ```Rust - #[derive(Drop)] - enum Message { - Quit, - Echo: felt252, - Move: (u128, u128), - } +#[derive(Drop)] +enum Message { + Quit, + Echo: felt252, + Move: (u128, u128), +} - trait Processing { - fn process(self: Message); - } +trait Processing { + fn process(self: Message); +} - impl ProcessingImpl of Processing { - fn process(self: Message) { - match self { - Message::Quit => { println!("quitting") }, - Message::Echo(value) => { println!("echoing {}", value) }, - Message::Move((x, y)) => { println!("moving from {} to {}", x, y) }, - } +impl ProcessingImpl of Processing { + fn process(self: Message) { + match self { + Message::Quit => { println!("quitting") }, + Message::Echo(value) => { println!("echoing {}", value) }, + Message::Move((x, y)) => { println!("moving from {} to {}", x, y) }, } } +} ``` -In many situations, enums can come in handy especially when used with the `match` flow as used above in the traits implementation. There is a chapter that explains in detail the `match` flow. +In many situations, enums can come in handy especially when used with the `match` flow as used above in the traits implementation. Read more about the `match` flow in [The Cairo Book](https://book.cairo-lang.org/ch06-02-the-match-control-flow-construct.html). Here is how it could be used to process a `Quit` message: ```Rust - let msg: Message = Message::Quit; - msg.process(); +let msg: Message = Message::Quit; +msg.process(); ``` Running this code would print `quitting`. @@ -121,10 +119,10 @@ enum Option { The `Option` enum is helpful because it allows you to explicitly represent the possibility of a value being absent, making your code more expressive and easier to reason about. Using `Option` can also help prevent bugs caused by using uninitialized or unexpected `null` values. -The function below shows how the `Option` enum is used to return the first element of an array with a given value, or return `None` if the element is absent. +The function below shows how the `Option` enum is used to return the index of the first element of an array with a given value, or return `None` if the element is absent. ```Rust -fn find_value_iterative(mut arr: Span, value: felt252) -> Option { +fn find_value(mut arr: Span, value: felt252) -> Option { let mut result = Option::None; let mut index = 0; @@ -142,4 +140,4 @@ fn find_value_iterative(mut arr: Span, value: felt252) -> Option } ``` -There are other native enums, one of which is the `Result` enum, which allows for graceful error handling. The `Result` enum will be explained in detail in the `Error Handling` chapter. +There are other native enums, one of which is the `Result` enum, which allows for graceful error handling. Read more about the `Result` enum in [The Cairo Book](https://book.cairo-lang.org/ch09-02-recoverable-errors.html#the-result-enum). diff --git a/concepts/enums/introduction.md b/concepts/enums/introduction.md index 291ad528..1cbb72b0 100644 --- a/concepts/enums/introduction.md +++ b/concepts/enums/introduction.md @@ -1,3 +1,3 @@ # Introduction -Similar to other programming languages, enums, short for `enumerations`, are used in cairo to define custom data types that hold a collection of fixed set of named values called _variants_. Each variant that makes up an enum is distinct and has a specific meaning. +Similar to other programming languages, enums, short for `enumerations`, are used in Cairo to define custom data types that hold a collection of fixed set of named values called _variants_. Each variant that makes up an enum is distinct and has a specific meaning. From 8a4a4e763cc31fd72b7209a710d8e0cef3d4a1b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nenad=20Misi=C4=87?= Date: Tue, 16 Jul 2024 13:17:28 +0200 Subject: [PATCH 10/63] Reorder sentences in Enum Traits section --- concepts/enums/about.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/concepts/enums/about.md b/concepts/enums/about.md index d4b90457..ab137ef0 100644 --- a/concepts/enums/about.md +++ b/concepts/enums/about.md @@ -70,7 +70,7 @@ enum Action { ## Trait Implementations for Enums -In Cairo, traits can be defined and implemented on custom enums. This allows for you to define methods and attributes associated with an enum. We will first define a `Message` enum and implement a `Processing` trait for it: +In Cairo, traits can be defined and implemented on custom enums. This allows for you to define methods and attributes associated with an enum. Below is an example of this where we define a `Message` enum and implement a `Processing` trait for it: ```Rust #[derive(Drop)] @@ -95,16 +95,14 @@ impl ProcessingImpl of Processing { } ``` -In many situations, enums can come in handy especially when used with the `match` flow as used above in the traits implementation. Read more about the `match` flow in [The Cairo Book](https://book.cairo-lang.org/ch06-02-the-match-control-flow-construct.html). - -Here is how it could be used to process a `Quit` message: +Here is how the trait could be used to process a `Quit` message: ```Rust let msg: Message = Message::Quit; -msg.process(); +msg.process(); // prints "quitting" ``` -Running this code would print `quitting`. +In many situations, enums can come in handy especially when used with the `match` flow as used above in the traits implementation. Read more about the `match` flow in [The Cairo Book](https://book.cairo-lang.org/ch06-02-the-match-control-flow-construct.html). ## The `Option` Enum and Its Advantages From e3544cbd4f62af9614338fcae3895fc244f2c176 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Tue, 30 Jul 2024 01:31:05 +0100 Subject: [PATCH 11/63] Match basics concept --- concepts/match-basics/.meta/config.json | 8 +- concepts/match-basics/about.md | 120 ++++++++++++++++++++++++ concepts/match-basics/introduction.md | 2 + concepts/match-basics/links.json | 15 ++- 4 files changed, 139 insertions(+), 6 deletions(-) diff --git a/concepts/match-basics/.meta/config.json b/concepts/match-basics/.meta/config.json index 52914445..3c65ee35 100644 --- a/concepts/match-basics/.meta/config.json +++ b/concepts/match-basics/.meta/config.json @@ -1,7 +1,5 @@ { - "blurb": "", - "authors": [ - "misicnenad" - ], - "contributors": [] + "blurb": "The `match` expression allows for easy comparison of a value against a series of patterns and afterwards run the code based on which pattern matches.", + "authors": ["Ephraim-nonso"], + "contributors": [] } diff --git a/concepts/match-basics/about.md b/concepts/match-basics/about.md index 3b42f2c2..d650a9c6 100644 --- a/concepts/match-basics/about.md +++ b/concepts/match-basics/about.md @@ -1 +1,121 @@ # Match Basics + +The `match` expression allows for easy comparison of a value against a series of patterns and afterwards run the code based on which pattern matches. Literal values, variable names, wildcards, and many other things are what makes up a pattern. + +The examples below show the `match` syntax: + +```rust +match enum_var { + variant_0(a, b, c) => {/* code */} + variant_1(_) => {/* code */} + ... + variant_k(a, c) => {/* code */} +} + +match felt_var { + 0 => { /* code */ } + _ => { /* code */ } +} +``` + +The `variant_0`, `variant_1`, `...`, and `variant_k` are all variants of an enum data type. Where `enum_var` could be any instance of the enum, after matching, executes the code in the curly braces. While the second example is the usage of the match patterning with a `felt_var` felt252 with arm patterns of value `0` and wildcard, `_`. + +Following the format above, we can write a function that takes in an unknown color parameter and return its true color. + +```rust +enum Color { + Red, + Yellow, + Green, +} + +fn return_color_type(color: Color) -> felt252 { + match color { + Color:Red => println!("The color is Red"),` + Color:Yellow => println!("The color is Yellow"), + Color:Green => println!("The color is Green"), + } +} +``` + +The `return_color_type` function prints the color of whichever unknown parameter was provided. Given the unknown `color` value, it would have several patterns that involves each of the variants to match. The arm of code to execute for each pattern is a one liner `println!("The color is ${color}")` of whatever the value match. To handle mutiple lines of code, the arm of code should be wrapped into a curly braces `{}`. + +## Matching the `Option` enum type + +The built-in `Option` enum can as well be handled with the `match` patterning to help get the inner `T` value out of the `Some` variant and other cases. There are no difference in how the match patterning are formed for the `Option` enum, only that the variants make up the arms. + +Let's design a function that takes in an `Option` parameter. If there is a value from the provided parameter, add one to this value else the function should return the `None` value with no operation. + +```rust +fn add_one(x: Option) -> Option { + match x { + Option::Some(val) => Option::Some(val + 1), + Option::None => Option::None, + } +} + +fn main() { + let three: Option = Option::Some(3); + let four: Option = plus_one(three); + let none = plus_one(Option::None); +} +``` + +## Matches cover all possible cases + +One benefit of using the `match` control flow is due to its exhaustive nature. In Cairo, especially in the case of `Option`, it expects that every possible pattern must be exhaustively handled else it will revert at compile time. + +```rust +fn add_one(x: Option) -> Option { + match x { + Option::Some(val) => Option::Some(val + 1), + } +} +``` + +This kind of bug is easier for the compiler to spot because in this case, the possibility that the `x` value could be a null value was not handled. The revert error looks like this error: + +```sh +$ scarb cairo-run + Compiling missing_match_arm v0.1.0 (home/Scarb.toml) +error: Missing match arm: `None` not covered. + --> home/src/lib.cairo:5:5 + match x { + ^*******^ + +error: could not compile `missing_match_arm` due to previous error +error: `scarb metadata` exited with error + +``` + +The error shows that Cairo is aware of other uncovered possible cases that x could be. This error spells out the possibility of the `x` value being null and protect us from assuming that `x` will never be null. + +## Catch-all pattern with `_` wildcard + +Understanding how the `_` wildcard works is essential in order to effectively handle all cases. This is most times added as the last arm of a `match` expression. This is a special pattern whose arm of code is executed only after the critical patterns. + +The allow_red function receives a parameter and return true if red and false for any other color instance. + +```rust +fn allow_red(color: Color) -> bool { + match color { + Color::Red => true, + _ => false, + } +} +``` + +## Match patterning with the `or` (`|`) Operator + +The Cairo `match` control flow construct allows for matching a value against multiple patterns handled by the `or` operator (`|`). With the use of the `or` operator in a match patterning, it helps achieve code simplicity. + +For example, using the `Color` enum above, we want to write a function that returns true for `Red` or `Green` colors and false for other colors. + +```rust +fn allow_red_and_green(color: Color) -> bool { + match color { + Color::Red | Color::Green => true, + _ => false, + } +} +``` diff --git a/concepts/match-basics/introduction.md b/concepts/match-basics/introduction.md index e10b99d0..f2422110 100644 --- a/concepts/match-basics/introduction.md +++ b/concepts/match-basics/introduction.md @@ -1 +1,3 @@ # Introduction + +In Cairo, the `match` expression is one essential control flow construct used to compare a value against a set of patterns and then execute the code based off pattern that matches. diff --git a/concepts/match-basics/links.json b/concepts/match-basics/links.json index fe51488c..5064b996 100644 --- a/concepts/match-basics/links.json +++ b/concepts/match-basics/links.json @@ -1 +1,14 @@ -[] +[ + { + "url": "https://book.cairo-lang.org/ch06-02-the-match-control-flow-construct.html", + "description": "The Match Control Flow Construct" + }, + { + "url": "https://starknet-by-example.voyager.online/getting-started/cairo_cheatsheet/match.html", + "description": "Match" + }, + { + "url": "hhttps://docs.cairo-lang.org/language_constructs/match-expressions.html", + "description": "Match expressions" + } +] From 321923ee921e347978abb80760658cefb5eb740a Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Tue, 30 Jul 2024 15:29:24 +0100 Subject: [PATCH 12/63] reorder enum & match basics --- concepts/enums/.meta/config.json | 2 +- concepts/enums/about.md | 20 ++-- concepts/match-basics/.meta/config.json | 4 +- concepts/match-basics/about.md | 137 ++++++++++++++---------- concepts/match-basics/introduction.md | 2 +- concepts/match-basics/links.json | 8 -- 6 files changed, 96 insertions(+), 77 deletions(-) diff --git a/concepts/enums/.meta/config.json b/concepts/enums/.meta/config.json index 5fee2aa3..71f45188 100644 --- a/concepts/enums/.meta/config.json +++ b/concepts/enums/.meta/config.json @@ -1,5 +1,5 @@ { "blurb": "Enums are Cairo data type used to define a set of predefined variants for the purpose of code readability and safety.", "authors": ["Ephraim-nonso"], - "contributors": [] + "contributors": ["misicnenad"] } diff --git a/concepts/enums/about.md b/concepts/enums/about.md index ab137ef0..27dd7bac 100644 --- a/concepts/enums/about.md +++ b/concepts/enums/about.md @@ -4,7 +4,7 @@ Enums are Cairo data type used to define a set of predefined variants for the pu The code snippet below shows how enums could be defined: -```Rust +```rust #[derive(Drop)] enum Direction { North, @@ -16,13 +16,13 @@ enum Direction { The `Direction` enum declared above is a simple enum with four variants: `North`, `East`, `South`, and `West`. The naming convention is to use PascalCase for enum variants. Each variant represents a distinct value of the `Direction` enum type. Each variant in this particular enum example has no associated value and can be instantiated using this syntax: -```Rust +```rust let direction = Direction::North; ``` Below is the same `Direction` enum, but with variants that have associated values, that store the exact degree of the direction: -```Rust +```rust #[derive(Drop)] enum Direction { North: u128, @@ -34,15 +34,15 @@ enum Direction { It is evident from this example that each variant in the `Direction` enum has an associated value of `u128`. This kind of enum can be instantiated as follows: -```Rust +```rust let direction = Direction::North(10); ``` -## Complex example of an enum combined with custom types +## Complex Enum Example with Custom Types An enum can be declared with a combination of different data types as its variants. In the example below, `Action` is a complex enum that as a collection of `Quit`, `Direction`, `SendMessage`, `ChangeAvatar`, and `ProfileState` as variants. -```Rust +```rust #[derive(Drop)] struct Move { up: u32, @@ -72,7 +72,7 @@ enum Action { In Cairo, traits can be defined and implemented on custom enums. This allows for you to define methods and attributes associated with an enum. Below is an example of this where we define a `Message` enum and implement a `Processing` trait for it: -```Rust +```rust #[derive(Drop)] enum Message { Quit, @@ -97,7 +97,7 @@ impl ProcessingImpl of Processing { Here is how the trait could be used to process a `Quit` message: -```Rust +```rust let msg: Message = Message::Quit; msg.process(); // prints "quitting" ``` @@ -108,7 +108,7 @@ In many situations, enums can come in handy especially when used with the `match The `Option` enum is a standard Cairo enum that represents the concept of an optional value. It has two variants: `Some: T` and `None`. `Some` variant has an associated value of type `T`, while `None` represents the absence of an associated value. -```Rust +```rust enum Option { Some: T, None, @@ -119,7 +119,7 @@ The `Option` enum is helpful because it allows you to explicitly represent the p The function below shows how the `Option` enum is used to return the index of the first element of an array with a given value, or return `None` if the element is absent. -```Rust +```rust fn find_value(mut arr: Span, value: felt252) -> Option { let mut result = Option::None; let mut index = 0; diff --git a/concepts/match-basics/.meta/config.json b/concepts/match-basics/.meta/config.json index 3c65ee35..675b1b8f 100644 --- a/concepts/match-basics/.meta/config.json +++ b/concepts/match-basics/.meta/config.json @@ -1,5 +1,5 @@ { - "blurb": "The `match` expression allows for easy comparison of a value against a series of patterns and afterwards run the code based on which pattern matches.", + "blurb": "The `match` expression enables pattern matching and running code based on the matched pattern.", "authors": ["Ephraim-nonso"], - "contributors": [] + "contributors": ["misicnenad"] } diff --git a/concepts/match-basics/about.md b/concepts/match-basics/about.md index d650a9c6..ab7ea466 100644 --- a/concepts/match-basics/about.md +++ b/concepts/match-basics/about.md @@ -1,26 +1,6 @@ # Match Basics -The `match` expression allows for easy comparison of a value against a series of patterns and afterwards run the code based on which pattern matches. Literal values, variable names, wildcards, and many other things are what makes up a pattern. - -The examples below show the `match` syntax: - -```rust -match enum_var { - variant_0(a, b, c) => {/* code */} - variant_1(_) => {/* code */} - ... - variant_k(a, c) => {/* code */} -} - -match felt_var { - 0 => { /* code */ } - _ => { /* code */ } -} -``` - -The `variant_0`, `variant_1`, `...`, and `variant_k` are all variants of an enum data type. Where `enum_var` could be any instance of the enum, after matching, executes the code in the curly braces. While the second example is the usage of the match patterning with a `felt_var` felt252 with arm patterns of value `0` and wildcard, `_`. - -Following the format above, we can write a function that takes in an unknown color parameter and return its true color. +The `match` expression allows for easy comparison of a value against a series of patterns and afterwards running the code based on the matched pattern. Literal values, variable names, wildcards, and many other things are what makes up a pattern. ```rust enum Color { @@ -29,18 +9,46 @@ enum Color { Green, } -fn return_color_type(color: Color) -> felt252 { +fn print_color_type(color: Color) { match color { - Color:Red => println!("The color is Red"),` - Color:Yellow => println!("The color is Yellow"), - Color:Green => println!("The color is Green"), + Color::Red => println!("The color is Red"), + Color::Yellow => println!("The color is Yellow"), + Color::Green => println!("The color is Green"), } } -``` -The `return_color_type` function prints the color of whichever unknown parameter was provided. Given the unknown `color` value, it would have several patterns that involves each of the variants to match. The arm of code to execute for each pattern is a one liner `println!("The color is ${color}")` of whatever the value match. To handle mutiple lines of code, the arm of code should be wrapped into a curly braces `{}`. +// To handle multiple lines of code, the `match` arm of code should be wrapped in curly braces `{}`: + +fn print_color_name(color: Color) -> felt252 { + match color { + Color::Red => { + println!("The color is Red"); + 5 + }, + Color::Yellow => { + println!("The color is Yellow"); + 2 + }, + Color::Green => { + println!("The color is Green"); + 9 + }, + } +} + +fn main() { + +let color = Color::Yellow; +print_color_type(color); + +let color = Color::Green; +let value: felt252 = print_color_name(color); // prints "The color is Green" + +println!("{}", value); // prints 9 +} +``` -## Matching the `Option` enum type +## Matching the `Option` Enum Type The built-in `Option` enum can as well be handled with the `match` patterning to help get the inner `T` value out of the `Some` variant and other cases. There are no difference in how the match patterning are formed for the `Option` enum, only that the variants make up the arms. @@ -56,48 +64,38 @@ fn add_one(x: Option) -> Option { fn main() { let three: Option = Option::Some(3); - let four: Option = plus_one(three); - let none = plus_one(Option::None); + let four: Option = add_one(three); + let none = add_one(Option::None); + + println!("{three:?}"); // prints "Option::Some(3)" + println!("{four:?}"); // prints "Option::Some(4)" + println!("{none:?}"); // prints "Option::None(())" } ``` -## Matches cover all possible cases +> Note: `{:?}` is a special formatting syntax that allows to print a debug form of the parameter passed to the `println!` macro. You can find more information about it in [The Cairo Book](https://book.cairo-lang.org/appendix-03-derivable-traits.html#debug-for-printing-and-debugging). -One benefit of using the `match` control flow is due to its exhaustive nature. In Cairo, especially in the case of `Option`, it expects that every possible pattern must be exhaustively handled else it will revert at compile time. +One benefit of using the `match` control flow is its exhaustive nature: the arms’ patterns must cover _all_ possibilities. Consider the version of the previous example that does not handle the `None` case: ```rust fn add_one(x: Option) -> Option { match x { Option::Some(val) => Option::Some(val + 1), } + // this code does not compile, as we forgot to handle the `None` case } ``` -This kind of bug is easier for the compiler to spot because in this case, the possibility that the `x` value could be a null value was not handled. The revert error looks like this error: - -```sh -$ scarb cairo-run - Compiling missing_match_arm v0.1.0 (home/Scarb.toml) -error: Missing match arm: `None` not covered. - --> home/src/lib.cairo:5:5 - match x { - ^*******^ - -error: could not compile `missing_match_arm` due to previous error -error: `scarb metadata` exited with error - -``` - The error shows that Cairo is aware of other uncovered possible cases that x could be. This error spells out the possibility of the `x` value being null and protect us from assuming that `x` will never be null. -## Catch-all pattern with `_` wildcard +## Catch-all Pattern with `_` Wildcard -Understanding how the `_` wildcard works is essential in order to effectively handle all cases. This is most times added as the last arm of a `match` expression. This is a special pattern whose arm of code is executed only after the critical patterns. +Using enums, we can also take special actions for a few particular values, but for all other values perform one default action by adding a new arm with `_` as the pattern for the last arm of the match expression. The `_` pattern is a special pattern that matches any value and does not bind to that value. -The allow_red function receives a parameter and return true if red and false for any other color instance. +The `is_red` function receives a parameter and return `true` if the color is `Red` and `false` for any other color: ```rust -fn allow_red(color: Color) -> bool { +fn is_red(color: Color) -> bool { match color { Color::Red => true, _ => false, @@ -105,17 +103,46 @@ fn allow_red(color: Color) -> bool { } ``` -## Match patterning with the `or` (`|`) Operator +## Pattern Matching with the `|` Operator -The Cairo `match` control flow construct allows for matching a value against multiple patterns handled by the `or` operator (`|`). With the use of the `or` operator in a match patterning, it helps achieve code simplicity. +The Cairo `match` control flow construct allows for matching a value against multiple patterns using the `|` (_or_) operator. This helps simplify the code. -For example, using the `Color` enum above, we want to write a function that returns true for `Red` or `Green` colors and false for other colors. +For example, using the `Color` enum, we want to write a function that returns `true` for `Red` or `Green` colors and `false` for other colors: ```rust -fn allow_red_and_green(color: Color) -> bool { +fn is_red_or_green(color: Color) -> bool { match color { Color::Red | Color::Green => true, _ => false, } } ``` + +## Pattern Matching with `felt252` and Integer Variables + +It is possible to match `felt252` and integer variables against a set of values. However, there are some constraints; + +- Only support integers that fit into a single `felt252` (i.e `u256` is not supported). +- 0 must be the first arm. +- Each arm must follow a sequential segment, contiguously with other arms. + +Let's implement a six-sided die tossing game. When this die is tossed, we get a number between 0 and 5. For a toss that yields 0, 1 or 2, you win. You roll again if you have 3. You loss for other values: + +```rust +fn toss(value: u8) { + match value { + 0 | 1 | 2 => println!("you won!"), + 3 => println!("you can roll again!"), + _ => println!("you lost...") + } +} + +fn main() { +let x: u8 = 2; +let y: u8 = 3; +let z: u8 = 5; +toss(x); // prints "you won!". +toss(y); // prints "you can roll again!". +toss(z); // prints "you lost...". +} +``` diff --git a/concepts/match-basics/introduction.md b/concepts/match-basics/introduction.md index f2422110..203a6e5a 100644 --- a/concepts/match-basics/introduction.md +++ b/concepts/match-basics/introduction.md @@ -1,3 +1,3 @@ # Introduction -In Cairo, the `match` expression is one essential control flow construct used to compare a value against a set of patterns and then execute the code based off pattern that matches. +In Cairo, the `match` expression is an essential control flow construct used to compare a value against a set of patterns and then execute code based on the pattern that matches. diff --git a/concepts/match-basics/links.json b/concepts/match-basics/links.json index 5064b996..80ac0bcc 100644 --- a/concepts/match-basics/links.json +++ b/concepts/match-basics/links.json @@ -2,13 +2,5 @@ { "url": "https://book.cairo-lang.org/ch06-02-the-match-control-flow-construct.html", "description": "The Match Control Flow Construct" - }, - { - "url": "https://starknet-by-example.voyager.online/getting-started/cairo_cheatsheet/match.html", - "description": "Match" - }, - { - "url": "hhttps://docs.cairo-lang.org/language_constructs/match-expressions.html", - "description": "Match expressions" } ] From d031586828823d289c31c839c9df4be8e9fc0be2 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Thu, 1 Aug 2024 13:36:57 +0100 Subject: [PATCH 13/63] amend to requested changes --- concepts/match-basics/about.md | 95 ++++++++++++++++++++++++++++------ 1 file changed, 79 insertions(+), 16 deletions(-) diff --git a/concepts/match-basics/about.md b/concepts/match-basics/about.md index ab7ea466..66f6f6a7 100644 --- a/concepts/match-basics/about.md +++ b/concepts/match-basics/about.md @@ -3,13 +3,14 @@ The `match` expression allows for easy comparison of a value against a series of patterns and afterwards running the code based on the matched pattern. Literal values, variable names, wildcards, and many other things are what makes up a pattern. ```rust +#[derive(Drop)] enum Color { Red, Yellow, Green, } -fn print_color_type(color: Color) { +fn specified_color(color: Color) { match color { Color::Red => println!("The color is Red"), Color::Yellow => println!("The color is Yellow"), @@ -17,9 +18,16 @@ fn print_color_type(color: Color) { } } -// To handle multiple lines of code, the `match` arm of code should be wrapped in curly braces `{}`: +fn main() { + let color = Color::Yellow; + specified_color(color); +} +``` -fn print_color_name(color: Color) -> felt252 { +To handle multiple lines of code, the `match` arm of code should be wrapped in curly braces `{}`: + +```rust +fn specified_color(color: Color) -> felt252 { match color { Color::Red => { println!("The color is Red"); @@ -37,17 +45,49 @@ fn print_color_name(color: Color) -> felt252 { } fn main() { - -let color = Color::Yellow; -print_color_type(color); - let color = Color::Green; -let value: felt252 = print_color_name(color); // prints "The color is Green" +let value: felt252 = specified_color(color); // prints "The color is Green" println!("{}", value); // prints 9 } ``` +The `match` expression also possesses the feature of binding to values that match the pattern. This makes it possible to extract the associated value of an enum variant. + +```rust +#[derive(Drop, Debug)] +enum ColorType { + Light, + Dark, +} + +#[derive(Drop)] +enum Color { + Red: ColorType, + Yellow, + Green, +} + +fn specified_color(color: Color) { + match color { + Color::Red(state) => { + println!("The color is Red"); + println!("The Color Type is {:?}", state); + }, + Color::Yellow => println!("The color is Yellow"), + Color::Green => println!("The color is Green"), + } +} + +fn main() { + let color = Color::Red(ColorType:: Dark); + specified_color(color); + +} +``` + +Extending the `Red` variant of the `Color` enum to have an associated enum. With the help of the `match` expression, we could extract the associated value; `state`. This is simply a variable name which could be used afterwards in the code arm. + ## Matching the `Option` Enum Type The built-in `Option` enum can as well be handled with the `match` patterning to help get the inner `T` value out of the `Some` variant and other cases. There are no difference in how the match patterning are formed for the `Option` enum, only that the variants make up the arms. @@ -86,8 +126,6 @@ fn add_one(x: Option) -> Option { } ``` -The error shows that Cairo is aware of other uncovered possible cases that x could be. This error spells out the possibility of the `x` value being null and protect us from assuming that `x` will never be null. - ## Catch-all Pattern with `_` Wildcard Using enums, we can also take special actions for a few particular values, but for all other values perform one default action by adding a new arm with `_` as the pattern for the last arm of the match expression. The `_` pattern is a special pattern that matches any value and does not bind to that value. @@ -138,11 +176,36 @@ fn toss(value: u8) { } fn main() { -let x: u8 = 2; -let y: u8 = 3; -let z: u8 = 5; -toss(x); // prints "you won!". -toss(y); // prints "you can roll again!". -toss(z); // prints "you lost...". + let x: u8 = 2; + let y: u8 = 3; + let z: u8 = 5; + + toss(x); // prints "you won!". + toss(y); // prints "you can roll again!". + toss(z); // prints "you lost...". } ``` + +## Matching Tuples + +Tuples can also be matched against a set of patterns. These patterns are designed similarly as a tuple. + +```rust +... +#[derive(Drop)] +enum DayType { + Week, + Weekend, + Holiday +} + +fn vending_machine_accept(c: (DayType, Color)) -> bool { + match c { + (DayType::Week, _) => true, // accepts all colors during week day + (_, Color::Red) | (_, Color::Green) => true, // accepts only Red or Green color for all specified days + (_, _) => false, // returns false for other instances + } +} +``` + +Using `(_, _)` is unnecessary as it performs the same functionality as using a single wildcard: `_ =>` syntax. From d77ac92725b0287f2b7269b223d264d0e6fcdf51 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Fri, 2 Aug 2024 11:15:01 +0100 Subject: [PATCH 14/63] minor changes --- concepts/match-basics/about.md | 47 ++++++++++++++------------------ concepts/match-basics/links.json | 4 +++ 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/concepts/match-basics/about.md b/concepts/match-basics/about.md index 66f6f6a7..1ad2f5ab 100644 --- a/concepts/match-basics/about.md +++ b/concepts/match-basics/about.md @@ -10,7 +10,7 @@ enum Color { Green, } -fn specified_color(color: Color) { +fn print_color_type(color: Color) { match color { Color::Red => println!("The color is Red"), Color::Yellow => println!("The color is Yellow"), @@ -28,27 +28,20 @@ To handle multiple lines of code, the `match` arm of code should be wrapped in c ```rust fn specified_color(color: Color) -> felt252 { + let mut response: felt252 = ''; + match color { Color::Red => { - println!("The color is Red"); - 5 + response = 'You passed in Red'; }, Color::Yellow => { - println!("The color is Yellow"); - 2 + response = 'You passed in Yellow'; }, Color::Green => { - println!("The color is Green"); - 9 + response = 'You passed in Green'; }, } -} - -fn main() { -let color = Color::Green; -let value: felt252 = specified_color(color); // prints "The color is Green" - -println!("{}", value); // prints 9 + response } ``` @@ -176,13 +169,9 @@ fn toss(value: u8) { } fn main() { - let x: u8 = 2; - let y: u8 = 3; - let z: u8 = 5; - - toss(x); // prints "you won!". - toss(y); // prints "you can roll again!". - toss(z); // prints "you lost...". + toss(2); // prints "you won!". + toss(3); // prints "you can roll again!". + toss(5); // prints "you lost...". } ``` @@ -191,7 +180,6 @@ fn main() { Tuples can also be matched against a set of patterns. These patterns are designed similarly as a tuple. ```rust -... #[derive(Drop)] enum DayType { Week, @@ -199,13 +187,20 @@ enum DayType { Holiday } -fn vending_machine_accept(c: (DayType, Color)) -> bool { +enum Coin { + Penny, + Nickel, + Dime, + Quarter, +} + +fn vending_machine_accept(c: (DayType, Coin)) -> bool { match c { - (DayType::Week, _) => true, // accepts all colors during week day - (_, Color::Red) | (_, Color::Green) => true, // accepts only Red or Green color for all specified days + (DayType::Week, _) => true, // accepts all coins during week day + (_, Coin::Dime) | (_, Coin::Quarter) => true, // accepts only Dime or Quarter coin for all specified days (_, _) => false, // returns false for other instances } } ``` -Using `(_, _)` is unnecessary as it performs the same functionality as using a single wildcard: `_ =>` syntax. +In the last match arm, it doesn't matter if we use `(_, _)` or just `_` wildcard to match any day and color combination, because they're functionally the same. diff --git a/concepts/match-basics/links.json b/concepts/match-basics/links.json index 80ac0bcc..5106fc8d 100644 --- a/concepts/match-basics/links.json +++ b/concepts/match-basics/links.json @@ -2,5 +2,9 @@ { "url": "https://book.cairo-lang.org/ch06-02-the-match-control-flow-construct.html", "description": "The Match Control Flow Construct" + }, + { + "url": "https://starknet-by-example.voyager.online/getting-started/cairo_cheatsheet/match.html", + "description": "Match" } ] From 98ddc2c8df4fda0f30fa432cf3a5f8ac5a2226b6 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Tue, 6 Aug 2024 10:33:27 +0100 Subject: [PATCH 15/63] nit: code update --- concepts/match-basics/about.md | 8 ++++---- concepts/match-basics/links.json | 4 ---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/concepts/match-basics/about.md b/concepts/match-basics/about.md index 1ad2f5ab..09ddb693 100644 --- a/concepts/match-basics/about.md +++ b/concepts/match-basics/about.md @@ -41,6 +41,7 @@ fn specified_color(color: Color) -> felt252 { response = 'You passed in Green'; }, } + response } ``` @@ -61,7 +62,7 @@ enum Color { Green, } -fn specified_color(color: Color) { +fn print_color_type(color: Color) { match color { Color::Red(state) => { println!("The color is Red"); @@ -73,9 +74,8 @@ fn specified_color(color: Color) { } fn main() { - let color = Color::Red(ColorType:: Dark); - specified_color(color); - + let color = Color::Red(ColorType::Dark); + print_color_type(color); } ``` diff --git a/concepts/match-basics/links.json b/concepts/match-basics/links.json index 5106fc8d..80ac0bcc 100644 --- a/concepts/match-basics/links.json +++ b/concepts/match-basics/links.json @@ -2,9 +2,5 @@ { "url": "https://book.cairo-lang.org/ch06-02-the-match-control-flow-construct.html", "description": "The Match Control Flow Construct" - }, - { - "url": "https://starknet-by-example.voyager.online/getting-started/cairo_cheatsheet/match.html", - "description": "Match" } ] From ecdd0b6367eb001439c1f03a00ee37d439280496 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nenad=20Misi=C4=87?= Date: Wed, 7 Aug 2024 18:36:29 +0200 Subject: [PATCH 16/63] Apply suggestions from code review --- concepts/match-basics/about.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/concepts/match-basics/about.md b/concepts/match-basics/about.md index 09ddb693..d845d719 100644 --- a/concepts/match-basics/about.md +++ b/concepts/match-basics/about.md @@ -20,7 +20,7 @@ fn print_color_type(color: Color) { fn main() { let color = Color::Yellow; - specified_color(color); + print_color_type(color); // prints "The color is Yellow" } ``` @@ -83,7 +83,7 @@ Extending the `Red` variant of the `Color` enum to have an associated enum. With ## Matching the `Option` Enum Type -The built-in `Option` enum can as well be handled with the `match` patterning to help get the inner `T` value out of the `Some` variant and other cases. There are no difference in how the match patterning are formed for the `Option` enum, only that the variants make up the arms. +The built-in `Option` enum can also be handled with the `match` expression. Let's design a function that takes in an `Option` parameter. If there is a value from the provided parameter, add one to this value else the function should return the `None` value with no operation. From b8adcdead91de07191833731c88e45fec6221ac9 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Mon, 26 Aug 2024 07:21:57 +0100 Subject: [PATCH 17/63] traits concept --- concepts/traits/about.md | 314 ++++++++++++++++++++++++++++++++ concepts/traits/introduction.md | 2 + concepts/traits/links.json | 7 +- 3 files changed, 322 insertions(+), 1 deletion(-) diff --git a/concepts/traits/about.md b/concepts/traits/about.md index 445d444b..1af8ac56 100644 --- a/concepts/traits/about.md +++ b/concepts/traits/about.md @@ -1 +1,315 @@ # Traits + +A trait specifies a set of methods that a type can implement. Traits are useful for defining methods that should be shared between types. When traits are used with generic types, the defined methods can be called on particular type but also possible to call them on other data type. In an abstract manner, with the use of _trait bounds_, we can specify that the generic type must share certain behavior. + +> **Note:** Traits share similar feature to what is known as interfaces in other programming languages with some differences. + +## Trait definition + +Defining a trait helps identify the function signature that would make up the set of behaviors a type can implement in order to achieve a result. These methods form the behavior of a type. If we can call the same methods on different types, this implies that the involved types have same behavior. + +Let's define a `Summary` trait with the `summarize` method in order to form the behavior for a `NewsArticle` type, considering that `NewsArticle` is a struct holding the news story of a location. + +```rust +// A trait for NewsArticle struct type +pub trait Summary { + fn summarize(self: @NewsArticle) -> ByteArray; +} +``` + +Going by the `Summary` trait definition above, the `summarize` method is a behavior that can only be called by the NewsArticle struct type. If invoked on other type instances, it throws a compilation error. Declaring the trait with the `pub` keyword exposes this create to other creates that intend to make use of the trait too. Notice also, how in traits after declaring the method signature, it ends with a semicolon. + +```rust +// A trait for a generic type +pub trait Summary { + fn summarize(self: @T) -> ByteArray; +} +``` + +> **Note:** In Cairo, `ByteArray` type is used to represent strings. + +A trait can have more than one method in its body; each declared method signature is a one liner that ends with a semicolon. + +## Trait implementation on a Type + +After defining the function signatures that make up a trait, the compiler will enforce that an implementation is as well defined for types that adopt the trait. We have written a media _`aggregator`_ library create below that summarizes some data from instances of `NewsArticle` and `Tweet`. For the `NewsArticle` struct, we would use the headline, the author, and the location types to return the value for the `summarize` method from the `Summary` trait, while for the `Tweet` struct, we would use the username and the content, assuming that the tweet content has a 280 characters limitation. + +```rust +mod aggregator { + pub trait Summary { + fn summarize(self: @T) -> ByteArray; + } + + #[derive(Drop)] + pub struct NewsArticle { + pub headline: ByteArray, + pub location: ByteArray, + pub author: ByteArray, + pub content: ByteArray, + } + + impl NewsArticleSummary of Summary { + fn summarize(self: @NewsArticle) -> ByteArray { + format!("{} by {} ({})", self.headline, self.author, self.location) + } + } + + #[derive(Drop)] + pub struct Tweet { + pub username: ByteArray, + pub content: ByteArray, + pub reply: bool, + pub retweet: bool, + } + + impl TweetSummary of Summary { + fn summarize(self: @Tweet) -> ByteArray { + format!("{}: {}", self.username, self.content) + } + } +} + +use aggregator::{Summary, NewsArticle, Tweet}; + +fn main() { + let news = NewsArticle { + headline: "Cairo has become the most popular language for developers", + location: "Worldwide", + author: "Cairo Digger", + content: "Cairo is a new programming language for zero-knowledge proofs", + }; + + let tweet = Tweet { + username: "EliBenSasson", + content: "Crypto is full of short-term maximizing projects. \n @Starknet and @StarkWareLtd are about long-term vision maximization.", + reply: false, + retweet: false + }; // Tweet instantiation + + println!("New article available! {}", news.summarize()); + println!("New tweet! {}", tweet.summarize()); +} +``` + +Trait implementation appears similar as a regular function declaration however, the difference is that the former implements the code for the method signature defined in a trait. To declare the trait implementation, we use the `impl` keyword, the name of the implementation, then the `of` keyword that recognizes which trait to implement for. If this is a trait for a generic type, we put the generic type in the angle bracket close to the trait name. + +Since this is aimed at declaring the logic for the trait method signatures, these methods will no longer be a one liner ending with a semicolon but rather a curly braces with the function logic within. These methods can afterwards be invoked like any other function call on a data type. + +It is important to note that for a trait to be accessible, the implementation must be visible within the scope where the method is invoked. You will witness the compiler error if the trait is `pub` and the implementation is not visible within the scope where a trait method is called. + +## Default Implementations + +Sometimes, a trait can be defined with a default implementation for some or all of the methods that makes up the trait. This is to avoid requiring an implementation of all methods on every type and better code readability. If any particular type requires a special implementation of a trait's method, the default implementation could be override. + +```rust +mod aggregator { + pub trait Summary { + fn summarize(self: @T) -> ByteArray { + "(Read more...)" + } + } + + #[derive(Drop)] + pub struct NewsArticle { + pub headline: ByteArray, + pub location: ByteArray, + pub author: ByteArray, + pub content: ByteArray, + } + + impl NewsArticleSummary of Summary {} + + #[derive(Drop)] + pub struct Tweet { + pub username: ByteArray, + pub content: ByteArray, + pub reply: bool, + pub retweet: bool, + } + + impl TweetSummary of Summary { + fn summarize(self: @Tweet) -> ByteArray { + format!("{}: {}", self.username, self.content) + } + } +} + +use aggregator::{Summary, NewsArticle}; + +fn main() { + let news = NewsArticle { + headline: "Cairo has become the most popular language for developers", + location: "Worldwide", + author: "Cairo Digger", + content: "Cairo is a new programming language for zero-knowledge proofs", + }; + + println!("New article available! {}", news.summarize()); +} +``` + +The default implementation returns `"(Read more...)"` ByteArray when this trait is implemented on any type. To use this default, you declare the impl block with an empty block. + +```rust +impl NewsArticleSummary of Summary {} +``` + +When the `summarize` method is called on the `NewsArticle` struct, this prints `New article available! (Read more...)`. + +This will be a different case for the `Twitter` struct since the implementation was changed. To override, the syntax is very much the same as defining an implementation with unique code blocks for the data types. + +## How to Use and Manage External Trait + +Traits and implementations can be defined in an external module and used across other modules supposing it is appropriately imported. We have a `ShapeGeometry` trait with the `boundary` method that must be implemented for both the `Circle` and `Rectangle` structs. This is how the traits and implementation is imported, managed and used across modules. + +```rust +// Here T is an alias type which will be provided during implementation +pub trait ShapeGeometry { + fn boundary(self: T) -> u64; + fn area(self: T) -> u64; +} + +mod rectangle { + // Importing ShapeGeometry is required to implement this trait for Rectangle + use super::ShapeGeometry; + + #[derive(Copy, Drop)] + pub struct Rectangle { + pub height: u64, + pub width: u64, + } + + // Implementation RectangleGeometry passes in + // to implement the trait for that type + impl RectangleGeometry of ShapeGeometry { + fn boundary(self: Rectangle) -> u64 { + 2 * (self.height + self.width) + } + fn area(self: Rectangle) -> u64 { + self.height * self.width + } + } +} + +mod circle { + // Importing ShapeGeometry is required to implement this trait for Circle + use super::ShapeGeometry; + + #[derive(Copy, Drop)] + pub struct Circle { + pub radius: u64 + } + + // Implementation CircleGeometry passes in + // to implement the imported trait for that type + impl CircleGeometry of ShapeGeometry { + fn boundary(self: Circle) -> u64 { + (2 * 314 * self.radius) / 100 + } + fn area(self: Circle) -> u64 { + (314 * self.radius * self.radius) / 100 + } + } +} + +use rectangle::Rectangle; +use circle::Circle; + +fn main() { + let rect = Rectangle { height: 5, width: 7 }; + println!("Rectangle area: {}", ShapeGeometry::area(rect)); //35 + println!("Rectangle boundary: {}", ShapeGeometry::boundary(rect)); //24 + + let circ = Circle { radius: 5 }; + println!("Circle area: {}", ShapeGeometry::area(circ)); //78 + println!("Circle boundary: {}", ShapeGeometry::boundary(circ)); //31 +} +``` + +The implementation visibility for both the `CircleGeometry` and `RectangleGeometry` does not need to be public since the `ShapeGeometry` trait is made public and should be easily found by the compiler. + +## Impl Aliases + +Implementation, when imported, can be labeled as `impl` as an alternative name. This helps when instantiating a generic implementation for concrete types. Let's define a trivial `Two` implementation for all types that implement the `One` trait by simply adding twice the value of one and returning the summation. We can afterwards make available for use an implementation that works for u8 and u128 types. + +```rust +trait Two { + fn two() -> T; +} + +mod one_based { + pub impl TwoImpl< + T, +Copy, +Drop, +Add, impl One: core::num::traits::One + > of super::Two { + fn two() -> T { + One::one() + One::one() + } + } +} + +pub impl U8Two = one_based::TwoImpl; +pub impl U128Two = one_based::TwoImpl; +``` + +The generic implementation can be written in a private module and with the use of impl alias, we can instantiate the generic implementation of these two concrete types. The benefit of using a private and unexposed generic implementation is that it prevents code duplication across files. This as well keeps the public API simple and clean. + +## Negative Implementation + +Negative implementation is a technique used to identify when a type does not implement a specific trait while defining a trait implementation for a generic type. Negative impls states the scope for which an implementation is applicable when another implementation does not fall within the existing scope. This is otherwise referred to as `negative trait` or `negative bound`. + +Supposing we have a Producer and Consumer traits. We intend to create a generic behavior that expects all types to implement the Consumer trait by default, considering that no one type must implement both Producer and Consumer traits. With the negative impl feature, we can do an explicit restriction. + +> **Note:** Being an experimental feature, to use this, you have to add `experimental-features = ["negative_impls"]` in your package Scarb.toml file. + +```rust +#[derive(Drop)] +struct ProducerType {} + +#[derive(Drop, Debug)] +struct AnotherType {} + +#[derive(Drop, Debug)] +struct AThirdType {} + +trait Producer { + fn produce(self: T) -> u32; +} + +trait Consumer { + fn consume(self: T, input: u32); +} + +impl ProducerImpl of Producer { + fn produce(self: ProducerType) -> u32 { + 42 + } +} + +impl TConsumerImpl, +Drop, -Producer> of Consumer { + fn consume(self: T, input: u32) { + println!("{:?} consumed value: {}", self, input); + } +} + +fn main() { + let producer = ProducerType {}; + let another_type = AnotherType {}; + let third_type = AThirdType {}; + let production = producer.produce(); + + producer.consume(production); //Invalid: ProducerType does not implement Consumer + another_type.consume(production); + third_type.consume(production); +} +``` + +On inspecting the `main` function, noticed how we created instances of `producer`, `another_type` and `third_type`. Afterwards, we invoked the `produce` function on the `producer` instance and and pass the result - `production` - to the `consume` function called on the `another_type` and `third_type` instances. The commented part of the code will cause a compile-time error because the `ProducerType` instance does not define the `Consumer` trait. + +If you run the code without following what was pointed out at the `note` section, your compiler will throw this error: + +```bash +error: Negative impls are not enabled in the current crate. + --> lib.cairo:24:55 +impl TConsumerImpl, +Drop, -Producer> of Consumer { + ^**********^ +``` diff --git a/concepts/traits/introduction.md b/concepts/traits/introduction.md index e10b99d0..883a9cfa 100644 --- a/concepts/traits/introduction.md +++ b/concepts/traits/introduction.md @@ -1 +1,3 @@ # Introduction + +In Cairo, a trait is a series of methods that can be implemented by a data type. When a trait is implemented for a type, the methods defined in that trait can be called on instances of that type. A trait is not limited to only a singular type but when combined with generic type, the functionality defined in the trait can be invoked on a particular type and can share these methods with other data types. diff --git a/concepts/traits/links.json b/concepts/traits/links.json index fe51488c..e20673c8 100644 --- a/concepts/traits/links.json +++ b/concepts/traits/links.json @@ -1 +1,6 @@ -[] +[ + { + "url": "https://book.cairo-lang.org/ch08-02-traits-in-cairo.html", + "description": "Traits in Cairo" + } +] From 066787ce52690be261abae53cb39a2cb8971a023 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Mon, 16 Sep 2024 18:45:30 +0100 Subject: [PATCH 18/63] correction to traits concept --- concepts/traits/.meta/config.json | 8 +-- concepts/traits/about.md | 112 +++++++----------------------- concepts/traits/introduction.md | 2 +- 3 files changed, 29 insertions(+), 93 deletions(-) diff --git a/concepts/traits/.meta/config.json b/concepts/traits/.meta/config.json index 25336151..d82a21b0 100644 --- a/concepts/traits/.meta/config.json +++ b/concepts/traits/.meta/config.json @@ -1,7 +1,5 @@ { - "blurb": "", - "authors": [ - "0xNeshi" - ], - "contributors": [] + "blurb": "A trait specifies a set of methods that a type can implement. Traits are useful for defining methods that should be shared between types.", + "authors": ["Ephraim-nonso"], + "contributors": ["0xNeshi"] } diff --git a/concepts/traits/about.md b/concepts/traits/about.md index 1af8ac56..63ffc050 100644 --- a/concepts/traits/about.md +++ b/concepts/traits/about.md @@ -8,16 +8,24 @@ A trait specifies a set of methods that a type can implement. Traits are useful Defining a trait helps identify the function signature that would make up the set of behaviors a type can implement in order to achieve a result. These methods form the behavior of a type. If we can call the same methods on different types, this implies that the involved types have same behavior. -Let's define a `Summary` trait with the `summarize` method in order to form the behavior for a `NewsArticle` type, considering that `NewsArticle` is a struct holding the news story of a location. - ```rust +#[derive(Drop)] + pub struct NewsArticle { + pub headline: ByteArray, + pub location: ByteArray, + pub author: ByteArray, + pub content: ByteArray, + } + // A trait for NewsArticle struct type pub trait Summary { fn summarize(self: @NewsArticle) -> ByteArray; } ``` -Going by the `Summary` trait definition above, the `summarize` method is a behavior that can only be called by the NewsArticle struct type. If invoked on other type instances, it throws a compilation error. Declaring the trait with the `pub` keyword exposes this create to other creates that intend to make use of the trait too. Notice also, how in traits after declaring the method signature, it ends with a semicolon. +Going by the `Summary` trait definition above, the `summarize` method is a behavior that can only be called by the `NewsArticle` struct type. If invoked on other type instances, it throws a compilation error. Declaring the trait with the `pub` keyword exposes the trait in this crate to other crates that intend to make use of the trait too. Notice also that we use a semicolon after declaring method signatures in traits. + +A trait could be defined with a generic argument which allows for a function to take in argument of any data type. This introduces a mode of flexibility to function signature to allow them handle varieties of data type. In the case of the `Summary` trait below, this has been redesigned to work for any data type so that when `summarize` method is invoked on them, it returns a ByteArray. ```rust // A trait for a generic type @@ -26,13 +34,11 @@ pub trait Summary { } ``` -> **Note:** In Cairo, `ByteArray` type is used to represent strings. - A trait can have more than one method in its body; each declared method signature is a one liner that ends with a semicolon. ## Trait implementation on a Type -After defining the function signatures that make up a trait, the compiler will enforce that an implementation is as well defined for types that adopt the trait. We have written a media _`aggregator`_ library create below that summarizes some data from instances of `NewsArticle` and `Tweet`. For the `NewsArticle` struct, we would use the headline, the author, and the location types to return the value for the `summarize` method from the `Summary` trait, while for the `Tweet` struct, we would use the username and the content, assuming that the tweet content has a 280 characters limitation. +After defining the function signatures that make up a trait, the compiler will enforce that an implementation is as well defined for types that adopt the trait. We have written a media `aggregator` library crate below that summarizes some data from instances of `NewsArticle` and `Tweet`. For the `NewsArticle` struct, we would use the headline, the author, and the location types to return the value for the `summarize` method from the `Summary` trait, while for the `Tweet` struct, we would use the username and the content, assuming that the tweet content has a 280 characters limitation. ```rust mod aggregator { @@ -91,15 +97,9 @@ fn main() { } ``` -Trait implementation appears similar as a regular function declaration however, the difference is that the former implements the code for the method signature defined in a trait. To declare the trait implementation, we use the `impl` keyword, the name of the implementation, then the `of` keyword that recognizes which trait to implement for. If this is a trait for a generic type, we put the generic type in the angle bracket close to the trait name. - -Since this is aimed at declaring the logic for the trait method signatures, these methods will no longer be a one liner ending with a semicolon but rather a curly braces with the function logic within. These methods can afterwards be invoked like any other function call on a data type. - -It is important to note that for a trait to be accessible, the implementation must be visible within the scope where the method is invoked. You will witness the compiler error if the trait is `pub` and the implementation is not visible within the scope where a trait method is called. - ## Default Implementations -Sometimes, a trait can be defined with a default implementation for some or all of the methods that makes up the trait. This is to avoid requiring an implementation of all methods on every type and better code readability. If any particular type requires a special implementation of a trait's method, the default implementation could be override. +Sometimes, a trait can be defined with a default implementation for some or all of the methods that makes up the trait. This is to avoid requiring an implementation of all methods on every type and better code readability. If any particular type requires a special implementation of a trait's method, it can override the default implementation. ```rust mod aggregator { @@ -144,23 +144,22 @@ fn main() { content: "Cairo is a new programming language for zero-knowledge proofs", }; - println!("New article available! {}", news.summarize()); -} -``` + println!("New article available! {}", news.summarize()); // prints "New article available! (Read more...)" -The default implementation returns `"(Read more...)"` ByteArray when this trait is implemented on any type. To use this default, you declare the impl block with an empty block. -```rust -impl NewsArticleSummary of Summary {} + let tweet = Tweet { + username: "Alice", + content: "Cairo is fun and engaging.", + reply: true, + retweet: true, + } + println!("New tweet from {}", tweet.summarize()); // prints "New tweet from Alice: Cairo is fun and engaging." +} ``` -When the `summarize` method is called on the `NewsArticle` struct, this prints `New article available! (Read more...)`. - -This will be a different case for the `Twitter` struct since the implementation was changed. To override, the syntax is very much the same as defining an implementation with unique code blocks for the data types. +## How to Use and Manage External Traits -## How to Use and Manage External Trait - -Traits and implementations can be defined in an external module and used across other modules supposing it is appropriately imported. We have a `ShapeGeometry` trait with the `boundary` method that must be implemented for both the `Circle` and `Rectangle` structs. This is how the traits and implementation is imported, managed and used across modules. +Traits and implementations can be defined in an external module and used in other modules, as long as they are properly imported. Let's say we have a `ShapeGeometry` trait with the `boundary` method that must be implemented for both the `Circle` and `Rectangle` structs. Below is an example of how the trait and implementation is imported, managed and used across modules. ```rust // Here T is an alias type which will be provided during implementation @@ -230,7 +229,7 @@ The implementation visibility for both the `CircleGeometry` and `RectangleGeomet ## Impl Aliases -Implementation, when imported, can be labeled as `impl` as an alternative name. This helps when instantiating a generic implementation for concrete types. Let's define a trivial `Two` implementation for all types that implement the `One` trait by simply adding twice the value of one and returning the summation. We can afterwards make available for use an implementation that works for u8 and u128 types. +Implementations can be aliased when imported, using the `impl` keyword. This helps when instantiating a generic implementation for concrete types. Let's define a trivial implementation of trait `Two` for all types that implement the `One` trait by simply adding twice the value of `One` and returning the summation. We can afterwards expose the `Two` implementation that works only for `u8` and `u128` types. ```rust trait Two { @@ -252,64 +251,3 @@ pub impl U128Two = one_based::TwoImpl; ``` The generic implementation can be written in a private module and with the use of impl alias, we can instantiate the generic implementation of these two concrete types. The benefit of using a private and unexposed generic implementation is that it prevents code duplication across files. This as well keeps the public API simple and clean. - -## Negative Implementation - -Negative implementation is a technique used to identify when a type does not implement a specific trait while defining a trait implementation for a generic type. Negative impls states the scope for which an implementation is applicable when another implementation does not fall within the existing scope. This is otherwise referred to as `negative trait` or `negative bound`. - -Supposing we have a Producer and Consumer traits. We intend to create a generic behavior that expects all types to implement the Consumer trait by default, considering that no one type must implement both Producer and Consumer traits. With the negative impl feature, we can do an explicit restriction. - -> **Note:** Being an experimental feature, to use this, you have to add `experimental-features = ["negative_impls"]` in your package Scarb.toml file. - -```rust -#[derive(Drop)] -struct ProducerType {} - -#[derive(Drop, Debug)] -struct AnotherType {} - -#[derive(Drop, Debug)] -struct AThirdType {} - -trait Producer { - fn produce(self: T) -> u32; -} - -trait Consumer { - fn consume(self: T, input: u32); -} - -impl ProducerImpl of Producer { - fn produce(self: ProducerType) -> u32 { - 42 - } -} - -impl TConsumerImpl, +Drop, -Producer> of Consumer { - fn consume(self: T, input: u32) { - println!("{:?} consumed value: {}", self, input); - } -} - -fn main() { - let producer = ProducerType {}; - let another_type = AnotherType {}; - let third_type = AThirdType {}; - let production = producer.produce(); - - producer.consume(production); //Invalid: ProducerType does not implement Consumer - another_type.consume(production); - third_type.consume(production); -} -``` - -On inspecting the `main` function, noticed how we created instances of `producer`, `another_type` and `third_type`. Afterwards, we invoked the `produce` function on the `producer` instance and and pass the result - `production` - to the `consume` function called on the `another_type` and `third_type` instances. The commented part of the code will cause a compile-time error because the `ProducerType` instance does not define the `Consumer` trait. - -If you run the code without following what was pointed out at the `note` section, your compiler will throw this error: - -```bash -error: Negative impls are not enabled in the current crate. - --> lib.cairo:24:55 -impl TConsumerImpl, +Drop, -Producer> of Consumer { - ^**********^ -``` diff --git a/concepts/traits/introduction.md b/concepts/traits/introduction.md index 883a9cfa..bfcc4e7e 100644 --- a/concepts/traits/introduction.md +++ b/concepts/traits/introduction.md @@ -1,3 +1,3 @@ # Introduction -In Cairo, a trait is a series of methods that can be implemented by a data type. When a trait is implemented for a type, the methods defined in that trait can be called on instances of that type. A trait is not limited to only a singular type but when combined with generic type, the functionality defined in the trait can be invoked on a particular type and can share these methods with other data types. +In Cairo, a trait is a series of methods that can be implemented by a data type. When a trait is implemented for a type, the methods defined in that trait can be called on instances of that type. A trait can be defined with generic types, defining behavior shared by multiple data types. \ No newline at end of file From 0727ecc8127f4e6800244da37340a4a4fc749fd1 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Tue, 17 Sep 2024 04:18:01 +0100 Subject: [PATCH 19/63] MD047 lint: fixed --- concepts/traits/introduction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/traits/introduction.md b/concepts/traits/introduction.md index bfcc4e7e..6ab84303 100644 --- a/concepts/traits/introduction.md +++ b/concepts/traits/introduction.md @@ -1,3 +1,3 @@ # Introduction -In Cairo, a trait is a series of methods that can be implemented by a data type. When a trait is implemented for a type, the methods defined in that trait can be called on instances of that type. A trait can be defined with generic types, defining behavior shared by multiple data types. \ No newline at end of file +In Cairo, a trait is a series of methods that can be implemented by a data type. When a trait is implemented for a type, the methods defined in that trait can be called on instances of that type. A trait can be defined with generic types, defining behavior shared by multiple data types. From 69dab2fb47d236352e2a5586c9f4e55759af2819 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Fri, 20 Sep 2024 21:24:13 +0100 Subject: [PATCH 20/63] few correction on traits --- concepts/traits/about.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/concepts/traits/about.md b/concepts/traits/about.md index 63ffc050..ed1434c1 100644 --- a/concepts/traits/about.md +++ b/concepts/traits/about.md @@ -10,12 +10,12 @@ Defining a trait helps identify the function signature that would make up the se ```rust #[derive(Drop)] - pub struct NewsArticle { - pub headline: ByteArray, - pub location: ByteArray, - pub author: ByteArray, - pub content: ByteArray, - } +pub struct NewsArticle { + pub headline: ByteArray, + pub location: ByteArray, + pub author: ByteArray, + pub content: ByteArray, +} // A trait for NewsArticle struct type pub trait Summary { @@ -90,7 +90,7 @@ fn main() { content: "Crypto is full of short-term maximizing projects. \n @Starknet and @StarkWareLtd are about long-term vision maximization.", reply: false, retweet: false - }; // Tweet instantiation + }; println!("New article available! {}", news.summarize()); println!("New tweet! {}", tweet.summarize()); @@ -134,7 +134,7 @@ mod aggregator { } } -use aggregator::{Summary, NewsArticle}; +use aggregator::{Summary, NewsArticle, Tweet}; fn main() { let news = NewsArticle { @@ -152,7 +152,7 @@ fn main() { content: "Cairo is fun and engaging.", reply: true, retweet: true, - } + }; println!("New tweet from {}", tweet.summarize()); // prints "New tweet from Alice: Cairo is fun and engaging." } ``` From eca178d2163783bbfced9fbcdecb89e44828960f Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Mon, 14 Oct 2024 01:42:43 +0100 Subject: [PATCH 21/63] wordy exercise --- config.json | 8 + .../practice/wordy/.docs/instructions.md | 59 +++++ exercises/practice/wordy/.meta/config.json | 20 ++ exercises/practice/wordy/.meta/example.cairo | 203 ++++++++++++++++++ exercises/practice/wordy/.meta/tests.toml | 79 +++++++ exercises/practice/wordy/Scarb.toml | 7 + exercises/practice/wordy/src/lib.cairo | 3 + exercises/practice/wordy/tests/wordy.cairo | 203 ++++++++++++++++++ 8 files changed, 582 insertions(+) create mode 100644 exercises/practice/wordy/.docs/instructions.md create mode 100644 exercises/practice/wordy/.meta/config.json create mode 100644 exercises/practice/wordy/.meta/example.cairo create mode 100644 exercises/practice/wordy/.meta/tests.toml create mode 100644 exercises/practice/wordy/Scarb.toml create mode 100644 exercises/practice/wordy/src/lib.cairo create mode 100644 exercises/practice/wordy/tests/wordy.cairo diff --git a/config.json b/config.json index 4d811b22..46d2fd5b 100644 --- a/config.json +++ b/config.json @@ -547,6 +547,14 @@ "practices": [], "prerequisites": [], "difficulty": 2 + }, + { + "slug": "wordy", + "name": "Wordy", + "uuid": "78d31713-0d88-4821-a586-4b36c46eaa44", + "practices": [], + "prerequisites": [], + "difficulty": 1 } ], "foregone": [ diff --git a/exercises/practice/wordy/.docs/instructions.md b/exercises/practice/wordy/.docs/instructions.md new file mode 100644 index 00000000..aafb9ee5 --- /dev/null +++ b/exercises/practice/wordy/.docs/instructions.md @@ -0,0 +1,59 @@ +# Instructions + +Parse and evaluate simple math word problems returning the answer as an integer. + +## Iteration 0 — Numbers + +Problems with no operations simply evaluate to the number given. + +> What is 5? + +Evaluates to 5. + +## Iteration 1 — Addition + +Add two numbers together. + +> What is 5 plus 13? + +Evaluates to 18. + +Handle large numbers and negative numbers. + +## Iteration 2 — Subtraction, Multiplication and Division + +Now, perform the other three operations. + +> What is 7 minus 5? + +2 + +> What is 6 multiplied by 4? + +24 + +> What is 25 divided by 5? + +5 + +## Iteration 3 — Multiple Operations + +Handle a set of operations, in sequence. + +Since these are verbal word problems, evaluate the expression from left-to-right, _ignoring the typical order of operations._ + +> What is 5 plus 13 plus 6? + +24 + +> What is 3 plus 2 multiplied by 3? + +15 (i.e. not 9) + +## Iteration 4 — Errors + +The parser should reject: + +- Unsupported operations ("What is 52 cubed?") +- Non-math questions ("Who is the President of the United States") +- Word problems with invalid syntax ("What is 1 plus plus 2?") diff --git a/exercises/practice/wordy/.meta/config.json b/exercises/practice/wordy/.meta/config.json new file mode 100644 index 00000000..a7481a7f --- /dev/null +++ b/exercises/practice/wordy/.meta/config.json @@ -0,0 +1,20 @@ +{ + "authors": ["Ephraim-nonso"], + "files": { + "solution": [ + "src/lib.cairo" + ], + "test": [ + "tests/wordy.cairo" + ], + "example": [ + ".meta/example.cairo" + ], + "invalidator": [ + "Scarb.toml" + ] + }, + "blurb": "Parse and evaluate simple math word problems returning the answer as an integer.", + "source": "Inspired by one of the generated questions in the Extreme Startup game.", + "source_url": "https://github.com/rchatley/extreme_startup" +} diff --git a/exercises/practice/wordy/.meta/example.cairo b/exercises/practice/wordy/.meta/example.cairo new file mode 100644 index 00000000..99fe6af9 --- /dev/null +++ b/exercises/practice/wordy/.meta/example.cairo @@ -0,0 +1,203 @@ +#[derive(Drop, PartialEq)] +enum Operator { + Plus, + Minus, + Multiply, + Divide, + Invalid, +} + +pub fn answer(word: ByteArray) -> (i32, bool) { + let words: Array = split_string_into_words(word); + if words.len() < 3 { + return (0, false); + } + + if words[0] != @"What" || words[1] != @"is" { + return (0, false); + } + + let mut result: i32 = match words.get(2) { + Option::Some(s) => { + match convert_ByteArray_to_int(s.unbox()) { + Option::Some(s) => s, + Option::None => { return (0, false); } + } + }, + Option::None => { return (0, false); }, + }; + + let mut i = 3; + while i < words.len() { + let op = parse_operator(words.at(i)); + i += 1; + + if op == Operator::Multiply || op == Operator::Divide { + if i >= words.len() || words[i] != @"by" { + result = 0; + break; + } + i += 1; + } + + let num: i32 = match words.get(i) { + Option::Some(s) => { + match convert_ByteArray_to_int(s.unbox()) { + Option::Some(s) => s, + Option::None => { + result = 0; + break; + } + } + }, + Option::None => { + result = 0; + break; + }, + }; + + result = match op { + Operator::Plus => result + num, + Operator::Minus => result - num, + Operator::Multiply => result * num, + Operator::Divide => { + if num == 0 { + result = 0; + break; + } + result / num + }, + Operator::Invalid => { + result = 0; + break; + }, + }; + + i += 1; + }; + + if (result == 0) { + (result, false) + } else { + (result, true) + } +} + + +fn split_string_into_words(long_string: ByteArray) -> Array { + let mut words: Array = ArrayTrait::new(); + let mut current_word = ""; + + let mut i = 0; + while i < long_string.len() { + let byte = long_string[i]; + if byte == 32 { + if current_word.len() > 0 { + words.append(current_word); + current_word = ""; + } + } else if (byte == 63) { + break; + } else { + current_word.append_byte(byte); + } + i += 1; + }; + + if current_word.len() > 0 { + words.append(current_word); + } + + words +} + + +fn convert_ByteArray_to_int(num: @ByteArray) -> Option { + let mut result: Option = Option::Some(0); + let mut size = num.len(); + let mut i = 0; + let mut base = 0; + + let mut isSigned = false; + if num.at(i).unwrap() == 45 { + isSigned = true; + size -= 1; + } + let num: ByteArray = num.rev(); + + while i < size { + let mut args = ""; + args.append_byte(num.at(i).unwrap()); + let re = get_number(args); + match re { + Option::Some(v) => { base += v * pow(i); }, + Option::None => { + result = Option::None; + break; + } + } + i += 1; + }; + + if result != Option::None { + if (isSigned) { + base *= -1; + } + return Option::Some(base); + } else { + return result; + } +} + + +fn pow(mut power: u32) -> i32 { + let base: i32 = 10; + let mut result = 1_i32; + while power != 0 { + result *= base; + power -= 1; + }; + + result.try_into().expect('too large to fit output type') +} + +fn parse_operator(word: @ByteArray) -> Operator { + if (word == @"plus") { + return Operator::Plus; + } else if (word == @"minus") { + return Operator::Minus; + } else if (word == @"multiplied") { + return Operator::Multiply; + } else if (word == @"divided") { + return Operator::Divide; + } else { + return Operator::Invalid; + } +} + + +fn get_number(c: ByteArray) -> Option { + if c == "1" { + Option::Some(1) + } else if c == "2" { + Option::Some(2) + } else if c == "3" { + Option::Some(3) + } else if c == "4" { + Option::Some(4) + } else if c == "5" { + Option::Some(5) + } else if c == "6" { + Option::Some(6) + } else if c == "7" { + Option::Some(7) + } else if c == "8" { + Option::Some(8) + } else if c == "9" { + Option::Some(9) + } else if c == "0" { + Option::Some(0) + } else { + Option::None + } +} diff --git a/exercises/practice/wordy/.meta/tests.toml b/exercises/practice/wordy/.meta/tests.toml new file mode 100644 index 00000000..f812dfa9 --- /dev/null +++ b/exercises/practice/wordy/.meta/tests.toml @@ -0,0 +1,79 @@ +# 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. + +[88bf4b28-0de3-4883-93c7-db1b14aa806e] +description = "just a number" + +[bb8c655c-cf42-4dfc-90e0-152fcfd8d4e0] +description = "addition" + +[79e49e06-c5ae-40aa-a352-7a3a01f70015] +description = "more addition" + +[b345dbe0-f733-44e1-863c-5ae3568f3803] +description = "addition with negative numbers" + +[cd070f39-c4cc-45c4-97fb-1be5e5846f87] +description = "large addition" + +[0d86474a-cd93-4649-a4fa-f6109a011191] +description = "subtraction" + +[30bc8395-5500-4712-a0cf-1d788a529be5] +description = "multiplication" + +[34c36b08-8605-4217-bb57-9a01472c427f] +description = "division" + +[da6d2ce4-fb94-4d26-8f5f-b078adad0596] +description = "multiple additions" + +[7fd74c50-9911-4597-be09-8de7f2fea2bb] +description = "addition and subtraction" + +[b120ffd5-bad6-4e22-81c8-5512e8faf905] +description = "multiple subtraction" + +[4f4a5749-ef0c-4f60-841f-abcfaf05d2ae] +description = "subtraction then addition" + +[312d908c-f68f-42c9-aa75-961623cc033f] +description = "multiple multiplication" + +[38e33587-8940-4cc1-bc28-bfd7e3966276] +description = "addition and multiplication" + +[3c854f97-9311-46e8-b574-92b60d17d394] +description = "multiple division" + +[3ad3e433-8af7-41ec-aa9b-97b42ab49357] +description = "unknown operation" + +[8a7e85a8-9e7b-4d46-868f-6d759f4648f8] +description = "Non math question" + +[42d78b5f-dbd7-4cdb-8b30-00f794bb24cf] +description = "reject problem missing an operand" + +[c2c3cbfc-1a72-42f2-b597-246e617e66f5] +description = "reject problem with no operands or operators" + +[4b3df66d-6ed5-4c95-a0a1-d38891fbdab6] +description = "reject two operations in a row" + +[6abd7a50-75b4-4665-aa33-2030fd08bab1] +description = "reject two numbers in a row" + +[10a56c22-e0aa-405f-b1d2-c642d9c4c9de] +description = "reject postfix notation" + +[0035bc63-ac43-4bb5-ad6d-e8651b7d954e] +description = "reject prefix notation" diff --git a/exercises/practice/wordy/Scarb.toml b/exercises/practice/wordy/Scarb.toml new file mode 100644 index 00000000..983459d0 --- /dev/null +++ b/exercises/practice/wordy/Scarb.toml @@ -0,0 +1,7 @@ +[package] +name = "wordy" +version = "0.1.0" +edition = "2024_07" + +[dev-dependencies] +cairo_test = "2.8.2" diff --git a/exercises/practice/wordy/src/lib.cairo b/exercises/practice/wordy/src/lib.cairo new file mode 100644 index 00000000..5ffe6d84 --- /dev/null +++ b/exercises/practice/wordy/src/lib.cairo @@ -0,0 +1,3 @@ +pub fn answer(word: ByteArray) -> (i32, bool) { + panic!("implement `answer`") +} diff --git a/exercises/practice/wordy/tests/wordy.cairo b/exercises/practice/wordy/tests/wordy.cairo new file mode 100644 index 00000000..4569d6b7 --- /dev/null +++ b/exercises/practice/wordy/tests/wordy.cairo @@ -0,0 +1,203 @@ +use wordy::answer; + + #[test] + fn just_a_number() { + let input = "What is 5?"; + let output = answer(input); + let expected = (5, true); + + assert_eq!(output, expected); + } + + #[test] + fn addition() { + let input = "What is 1 plus 1?"; + let output = answer(input); + let expected = (2, true); + + assert_eq!(output, expected); + } + + #[test] + fn more_addition() { + let input = "What is 53 plus 2?"; + let output = answer(input); + let expected = (55, true); + + assert_eq!(output, expected); + } + + #[test] + fn addition_with_negative_numbers() { + let input = "What is -1 plus -10?"; + let output = answer(input); + + let expected = (-11, true); + + assert_eq!(output, expected); + } + + #[test] + fn large_addition() { + let input = "What is 123 plus 45678?"; + let output = answer(input); + + let expected = (45801, true); + + assert_eq!(output, expected); + } + + #[test] + fn subtraction() { + let input = "What is 4 minus -12?"; + let output = answer(input); + + let expected = (16, true); + + assert_eq!(output, expected); + } + + #[test] + fn multiplication() { + let input = "What is -3 multiplied by 25?"; + let output = answer(input); + let expected = (-75, true); + + assert_eq!(output, expected); + } + + #[test] + fn division() { + let input = "What is 33 divided by -3?"; + let output = answer(input); + + let expected = (-11, true); + assert_eq!(output, expected); + } + + #[test] + fn multiple_additions() { + let input = "What is 1 plus 1 plus 1?"; + let output = answer(input); + + let expected = (3, true); + assert_eq!(output, expected); + } + + #[test] + fn addition_and_subtraction() { + let input = "What is 1 plus 5 minus -2?"; + let output = answer(input); + + let expected = (8, true); + assert_eq!(output, expected); + } + + #[test] + fn multiple_subtraction() { + let input = "What is 20 minus 4 minus 13?"; + let output = answer(input); + + let expected = (3, true); + assert_eq!(output, expected); + } + + #[test] + fn subtraction_then_addition() { + let input = "What is 17 minus 6 plus 3?"; + let output = answer(input); + + let expected = (14, true); + assert_eq!(output, expected); + } + + #[test] + fn multiple_multiplication() { + let input = "What is 2 multiplied by -2 multiplied by 3?"; + let output = answer(input); + let expected = (-12, true); + assert_eq!(output, expected); + } + + #[test] + fn addition_and_multiplication() { + let input = "What is -3 plus 7 multiplied by -2?"; + let output = answer(input); + + let expected = (-8, true); + assert_eq!(output, expected); + } + + #[test] + fn multiple_division() { + let input = "What is -12 divided by 2 divided by -3?"; + let output = answer(input); + + let expected = (2, true); + assert_eq!(output, expected); + } + + #[test] + fn unknown_operation() { + let input = "What is 52 cubed?"; + let output = answer(input); + + let expected = (0, false); + assert_eq!(output, expected); + } + + #[test] + fn non_math_question() { + let input = "Who is the President of the United States?"; + let output = answer(input); + let expected = (0, false); + assert_eq!(output, expected); + } + + #[test] + fn reject_problem_missing_an_operand() { + let input = "What is 1 plus?"; + let output = answer(input); + let expected = (0, false); + assert_eq!(output, expected); + } + + #[test] + fn reject_problem_with_no_operands_or_operators() { + let input = "What is?"; + let output = answer(input); + let expected = (0, false); + assert_eq!(output, expected); + } + + #[test] + fn reject_two_operations_in_a_row() { + let input = "What is 1 plus plus 2?"; + let output = answer(input); + let expected = (0, false); + assert_eq!(output, expected); + } + + #[test] + fn reject_two_numbers_in_a_row() { + let input = "What is 1 plus 2 1?"; + let output = answer(input); + let expected = (0, false); + assert_eq!(output, expected); + } + + #[test] + fn reject_postfix_notation() { + let input = "What is 1 2 plus?"; + let output = answer(input); + let expected = (0, false); + assert_eq!(output, expected); + } + + #[test] + fn reject_prefix_notation() { + let input = "What is plus 1 2?"; + let output = answer(input); + let expected = (0, false); + assert_eq!(output, expected); + } From 35e9e181530715ebb29368e2a172e00bdbba5922 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Mon, 14 Oct 2024 01:49:45 +0100 Subject: [PATCH 22/63] pass checks --- exercises/practice/wordy/tests/wordy.cairo | 424 +++++++++++---------- 1 file changed, 223 insertions(+), 201 deletions(-) diff --git a/exercises/practice/wordy/tests/wordy.cairo b/exercises/practice/wordy/tests/wordy.cairo index 4569d6b7..0db0d1e0 100644 --- a/exercises/practice/wordy/tests/wordy.cairo +++ b/exercises/practice/wordy/tests/wordy.cairo @@ -1,203 +1,225 @@ use wordy::answer; - #[test] - fn just_a_number() { - let input = "What is 5?"; - let output = answer(input); - let expected = (5, true); - - assert_eq!(output, expected); - } - - #[test] - fn addition() { - let input = "What is 1 plus 1?"; - let output = answer(input); - let expected = (2, true); - - assert_eq!(output, expected); - } - - #[test] - fn more_addition() { - let input = "What is 53 plus 2?"; - let output = answer(input); - let expected = (55, true); - - assert_eq!(output, expected); - } - - #[test] - fn addition_with_negative_numbers() { - let input = "What is -1 plus -10?"; - let output = answer(input); - - let expected = (-11, true); - - assert_eq!(output, expected); - } - - #[test] - fn large_addition() { - let input = "What is 123 plus 45678?"; - let output = answer(input); - - let expected = (45801, true); - - assert_eq!(output, expected); - } - - #[test] - fn subtraction() { - let input = "What is 4 minus -12?"; - let output = answer(input); - - let expected = (16, true); - - assert_eq!(output, expected); - } - - #[test] - fn multiplication() { - let input = "What is -3 multiplied by 25?"; - let output = answer(input); - let expected = (-75, true); - - assert_eq!(output, expected); - } - - #[test] - fn division() { - let input = "What is 33 divided by -3?"; - let output = answer(input); - - let expected = (-11, true); - assert_eq!(output, expected); - } - - #[test] - fn multiple_additions() { - let input = "What is 1 plus 1 plus 1?"; - let output = answer(input); - - let expected = (3, true); - assert_eq!(output, expected); - } - - #[test] - fn addition_and_subtraction() { - let input = "What is 1 plus 5 minus -2?"; - let output = answer(input); - - let expected = (8, true); - assert_eq!(output, expected); - } - - #[test] - fn multiple_subtraction() { - let input = "What is 20 minus 4 minus 13?"; - let output = answer(input); - - let expected = (3, true); - assert_eq!(output, expected); - } - - #[test] - fn subtraction_then_addition() { - let input = "What is 17 minus 6 plus 3?"; - let output = answer(input); - - let expected = (14, true); - assert_eq!(output, expected); - } - - #[test] - fn multiple_multiplication() { - let input = "What is 2 multiplied by -2 multiplied by 3?"; - let output = answer(input); - let expected = (-12, true); - assert_eq!(output, expected); - } - - #[test] - fn addition_and_multiplication() { - let input = "What is -3 plus 7 multiplied by -2?"; - let output = answer(input); - - let expected = (-8, true); - assert_eq!(output, expected); - } - - #[test] - fn multiple_division() { - let input = "What is -12 divided by 2 divided by -3?"; - let output = answer(input); - - let expected = (2, true); - assert_eq!(output, expected); - } - - #[test] - fn unknown_operation() { - let input = "What is 52 cubed?"; - let output = answer(input); - - let expected = (0, false); - assert_eq!(output, expected); - } - - #[test] - fn non_math_question() { - let input = "Who is the President of the United States?"; - let output = answer(input); - let expected = (0, false); - assert_eq!(output, expected); - } - - #[test] - fn reject_problem_missing_an_operand() { - let input = "What is 1 plus?"; - let output = answer(input); - let expected = (0, false); - assert_eq!(output, expected); - } - - #[test] - fn reject_problem_with_no_operands_or_operators() { - let input = "What is?"; - let output = answer(input); - let expected = (0, false); - assert_eq!(output, expected); - } - - #[test] - fn reject_two_operations_in_a_row() { - let input = "What is 1 plus plus 2?"; - let output = answer(input); - let expected = (0, false); - assert_eq!(output, expected); - } - - #[test] - fn reject_two_numbers_in_a_row() { - let input = "What is 1 plus 2 1?"; - let output = answer(input); - let expected = (0, false); - assert_eq!(output, expected); - } - - #[test] - fn reject_postfix_notation() { - let input = "What is 1 2 plus?"; - let output = answer(input); - let expected = (0, false); - assert_eq!(output, expected); - } - - #[test] - fn reject_prefix_notation() { - let input = "What is plus 1 2?"; - let output = answer(input); - let expected = (0, false); - assert_eq!(output, expected); - } +#[test] +fn just_a_number() { + let input = "What is 5?"; + let output = answer(input); + let expected = (5, true); + + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn addition() { + let input = "What is 1 plus 1?"; + let output = answer(input); + let expected = (2, true); + + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn more_addition() { + let input = "What is 53 plus 2?"; + let output = answer(input); + let expected = (55, true); + + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn addition_with_negative_numbers() { + let input = "What is -1 plus -10?"; + let output = answer(input); + + let expected = (-11, true); + + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn large_addition() { + let input = "What is 123 plus 45678?"; + let output = answer(input); + + let expected = (45801, true); + + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn subtraction() { + let input = "What is 4 minus -12?"; + let output = answer(input); + + let expected = (16, true); + + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn multiplication() { + let input = "What is -3 multiplied by 25?"; + let output = answer(input); + let expected = (-75, true); + + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn division() { + let input = "What is 33 divided by -3?"; + let output = answer(input); + + let expected = (-11, true); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn multiple_additions() { + let input = "What is 1 plus 1 plus 1?"; + let output = answer(input); + + let expected = (3, true); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn addition_and_subtraction() { + let input = "What is 1 plus 5 minus -2?"; + let output = answer(input); + + let expected = (8, true); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn multiple_subtraction() { + let input = "What is 20 minus 4 minus 13?"; + let output = answer(input); + + let expected = (3, true); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn subtraction_then_addition() { + let input = "What is 17 minus 6 plus 3?"; + let output = answer(input); + + let expected = (14, true); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn multiple_multiplication() { + let input = "What is 2 multiplied by -2 multiplied by 3?"; + let output = answer(input); + let expected = (-12, true); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn addition_and_multiplication() { + let input = "What is -3 plus 7 multiplied by -2?"; + let output = answer(input); + + let expected = (-8, true); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn multiple_division() { + let input = "What is -12 divided by 2 divided by -3?"; + let output = answer(input); + + let expected = (2, true); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn unknown_operation() { + let input = "What is 52 cubed?"; + let output = answer(input); + + let expected = (0, false); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn non_math_question() { + let input = "Who is the President of the United States?"; + let output = answer(input); + let expected = (0, false); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn reject_problem_missing_an_operand() { + let input = "What is 1 plus?"; + let output = answer(input); + let expected = (0, false); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn reject_problem_with_no_operands_or_operators() { + let input = "What is?"; + let output = answer(input); + let expected = (0, false); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn reject_two_operations_in_a_row() { + let input = "What is 1 plus plus 2?"; + let output = answer(input); + let expected = (0, false); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn reject_two_numbers_in_a_row() { + let input = "What is 1 plus 2 1?"; + let output = answer(input); + let expected = (0, false); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn reject_postfix_notation() { + let input = "What is 1 2 plus?"; + let output = answer(input); + let expected = (0, false); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn reject_prefix_notation() { + let input = "What is plus 1 2?"; + let output = answer(input); + let expected = (0, false); + assert_eq!(output, expected); +} From 26ff5d617a5971484adab11ef08266a75cb5d79b Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Thu, 17 Oct 2024 14:53:18 +0100 Subject: [PATCH 23/63] Wordy: update fmt --- config.json | 138 ++++------------ exercises/practice/wordy/.meta/example.cairo | 156 +++++++------------ exercises/practice/wordy/src/lib.cairo | 2 +- exercises/practice/wordy/tests/wordy.cairo | 68 ++++---- 4 files changed, 120 insertions(+), 244 deletions(-) diff --git a/config.json b/config.json index 46d2fd5b..1f49f496 100644 --- a/config.json +++ b/config.json @@ -19,21 +19,11 @@ "average_run_time": 5 }, "files": { - "solution": [ - "src/lib.cairo" - ], - "test": [ - "tests/%{snake_slug}.cairo" - ], - "example": [ - ".meta/example.cairo" - ], - "exemplar": [ - ".meta/exemplar.cairo" - ], - "invalidator": [ - "Scarb.toml" - ] + "solution": ["src/lib.cairo"], + "test": ["tests/%{snake_slug}.cairo"], + "example": [".meta/example.cairo"], + "exemplar": [".meta/exemplar.cairo"], + "invalidator": ["Scarb.toml"] }, "exercises": { "concept": [ @@ -41,21 +31,15 @@ "slug": "low-power-embedded-game", "name": "Low-power Embedded Game", "uuid": "f3b7ce44-1667-42b4-b792-401d36aee2f1", - "concepts": [ - "tuples" - ], - "prerequisites": [ - "traits" - ], + "concepts": ["tuples"], + "prerequisites": ["traits"], "status": "wip" }, { "slug": "lucians-luscious-lasagna", "name": "Lucian's Luscious Lasagna", "uuid": "f120ab92-f277-434c-ae38-a3bb86cb67bf", - "concepts": [ - "functions" - ], + "concepts": ["functions"], "prerequisites": [], "status": "beta" }, @@ -63,12 +47,8 @@ "slug": "annalyns-infiltration", "name": "Annalyn's Infiltration", "uuid": "da0f8d71-36ed-4c98-9e43-60a04ea5db3a", - "concepts": [ - "booleans" - ], - "prerequisites": [ - "functions" - ], + "concepts": ["booleans"], + "prerequisites": ["functions"], "status": "wip" } ], @@ -77,10 +57,7 @@ "slug": "hello-world", "name": "Hello World", "uuid": "1a0e23d9-e8f9-493a-af46-2be040173b64", - "practices": [ - "strings", - "felts" - ], + "practices": ["strings", "felts"], "prerequisites": [], "difficulty": 1 }, @@ -88,9 +65,7 @@ "slug": "reverse-string", "name": "Reverse String", "uuid": "df9f3e80-acf5-41e0-9321-d4b13b26a036", - "practices": [ - "strings" - ], + "practices": ["strings"], "prerequisites": [], "difficulty": 1 }, @@ -138,10 +113,7 @@ "slug": "leap", "name": "Leap", "uuid": "9b586e17-928c-42bf-95ed-67539daea9a8", - "practices": [ - "booleans", - "integers" - ], + "practices": ["booleans", "integers"], "prerequisites": [], "difficulty": 2 }, @@ -149,10 +121,7 @@ "slug": "semi-structured-logs", "name": "Semi Structured Logs", "uuid": "4ca5087f-0128-4845-89a8-a2fa7791ed98", - "practices": [ - "enums", - "match-basics" - ], + "practices": ["enums", "match-basics"], "prerequisites": [], "difficulty": 2 }, @@ -160,9 +129,7 @@ "slug": "darts", "name": "Darts", "uuid": "3e5fb791-59b5-4ea6-b68f-70ed851a3308", - "practices": [ - "control-flow" - ], + "practices": ["control-flow"], "prerequisites": [], "difficulty": 2 }, @@ -226,9 +193,7 @@ "slug": "raindrops", "name": "Raindrops", "uuid": "d2cc23d5-2ed1-4115-9b9a-4b62993e750c", - "practices": [ - "strings" - ], + "practices": ["strings"], "prerequisites": [], "difficulty": 2 }, @@ -276,9 +241,7 @@ "slug": "armstrong-numbers", "name": "Armstrong Numbers", "uuid": "4aaa153d-3416-4101-8143-35b068a15451", - "practices": [ - "packages-crates-modules" - ], + "practices": ["packages-crates-modules"], "prerequisites": [], "difficulty": 3 }, @@ -286,11 +249,7 @@ "slug": "sublist", "name": "Sublist", "uuid": "e62b1bb4-fb37-4dfe-ad81-e0fa5c494ba3", - "practices": [ - "arrays", - "enums", - "generics" - ], + "practices": ["arrays", "enums", "generics"], "prerequisites": [], "difficulty": 3 }, @@ -298,11 +257,7 @@ "slug": "scrabble-score", "name": "Scrabble Score", "uuid": "3ef58f8c-99d4-48be-bb15-a1a5763e5052", - "practices": [ - "dictionaries", - "strings", - "felts" - ], + "practices": ["dictionaries", "strings", "felts"], "prerequisites": [], "difficulty": 3 }, @@ -326,10 +281,7 @@ "slug": "beer-song", "name": "Beer Song", "uuid": "d96a8ba2-6e80-45ce-91d6-5b4cac391db6", - "practices": [ - "control-flow", - "strings" - ], + "practices": ["control-flow", "strings"], "prerequisites": [], "difficulty": 3 }, @@ -337,10 +289,7 @@ "slug": "clock", "name": "Clock", "uuid": "b44728f6-f2ad-4fa4-a20e-5144f9a81e3e", - "practices": [ - "traits", - "printing" - ], + "practices": ["traits", "printing"], "prerequisites": [], "difficulty": 4 }, @@ -370,12 +319,7 @@ "slug": "binary-search", "name": "Binary Search", "uuid": "46be407d-13b8-4a7f-9a9a-4cef93485ba7", - "practices": [ - "arrays", - "enums", - "control-flow", - "generics" - ], + "practices": ["arrays", "enums", "control-flow", "generics"], "prerequisites": [], "difficulty": 4 }, @@ -383,11 +327,7 @@ "slug": "largest-series-product", "name": "Largest Series Product", "uuid": "d0cae4fa-22a8-4604-9f0f-f90751245ce3", - "practices": [ - "enums", - "error-handling", - "control-flow" - ], + "practices": ["enums", "error-handling", "control-flow"], "prerequisites": [], "difficulty": 4 }, @@ -395,11 +335,7 @@ "slug": "allergies", "name": "Allergies", "uuid": "ef701095-b324-49f0-913e-2fb2e1f5f27a", - "practices": [ - "enums", - "structs", - "traits" - ], + "practices": ["enums", "structs", "traits"], "prerequisites": [], "difficulty": 4 }, @@ -442,12 +378,7 @@ "slug": "custom-set", "name": "Custom Set", "uuid": "aad80498-750c-4a7d-b82a-f52f90c54e11", - "practices": [ - "structs", - "generics", - "traits", - "operator-overloading" - ], + "practices": ["structs", "generics", "traits", "operator-overloading"], "prerequisites": [], "difficulty": 6 }, @@ -469,10 +400,7 @@ "slug": "simple-linked-list", "name": "Simple Linked List", "uuid": "cc9a6bf9-9027-42c4-a71d-082ce48f7869", - "practices": [ - "smart-pointers", - "generics" - ], + "practices": ["smart-pointers", "generics"], "prerequisites": [], "difficulty": 7 }, @@ -480,12 +408,7 @@ "slug": "protein-translation", "name": "Protein Translation", "uuid": "d42e7a29-64b9-478b-8b2a-44fd002391fa", - "practices": [ - "dictionaries", - "strings", - "felts", - "type-conversion" - ], + "practices": ["dictionaries", "strings", "felts", "type-conversion"], "prerequisites": [], "difficulty": 8 }, @@ -501,10 +424,7 @@ "slug": "linked-list", "name": "Linked List", "uuid": "1924c44e-bfa2-4dac-a7a9-779e4039ac56", - "practices": [ - "structs", - "traits" - ], + "practices": ["structs", "traits"], "prerequisites": [], "difficulty": 10 }, @@ -554,7 +474,7 @@ "uuid": "78d31713-0d88-4821-a586-4b36c46eaa44", "practices": [], "prerequisites": [], - "difficulty": 1 + "difficulty": 4 } ], "foregone": [ diff --git a/exercises/practice/wordy/.meta/example.cairo b/exercises/practice/wordy/.meta/example.cairo index 99fe6af9..20a5450f 100644 --- a/exercises/practice/wordy/.meta/example.cairo +++ b/exercises/practice/wordy/.meta/example.cairo @@ -7,24 +7,24 @@ enum Operator { Invalid, } -pub fn answer(word: ByteArray) -> (i32, bool) { - let words: Array = split_string_into_words(word); +pub fn answer(question: ByteArray) -> i32 { + let words: Array = split_question_into_words(question); if words.len() < 3 { - return (0, false); + panic!("syntax error"); } if words[0] != @"What" || words[1] != @"is" { - return (0, false); + panic!("unknown operation"); } let mut result: i32 = match words.get(2) { Option::Some(s) => { - match convert_ByteArray_to_int(s.unbox()) { + match parse_int(s.unbox()) { Option::Some(s) => s, - Option::None => { return (0, false); } + Option::None => panic!("syntax error"), } }, - Option::None => { return (0, false); }, + Option::None => panic!("syntax error"), }; let mut i = 3; @@ -34,26 +34,21 @@ pub fn answer(word: ByteArray) -> (i32, bool) { if op == Operator::Multiply || op == Operator::Divide { if i >= words.len() || words[i] != @"by" { - result = 0; - break; + panic!("unknown operation"); } i += 1; + } else if op == Operator::Invalid && parse_int(words.at(i - 1)) == Option::None { + panic!("unknown operation"); } let num: i32 = match words.get(i) { Option::Some(s) => { - match convert_ByteArray_to_int(s.unbox()) { + match parse_int(s.unbox()) { Option::Some(s) => s, - Option::None => { - result = 0; - break; - } + Option::None => panic!("syntax error"), } }, - Option::None => { - result = 0; - break; - }, + Option::None => panic!("syntax error"), }; result = match op { @@ -62,75 +57,67 @@ pub fn answer(word: ByteArray) -> (i32, bool) { Operator::Multiply => result * num, Operator::Divide => { if num == 0 { - result = 0; - break; + panic!("unknown operation"); } result / num }, - Operator::Invalid => { - result = 0; - break; - }, + Operator::Invalid => panic!("unknown operation"), }; i += 1; }; - if (result == 0) { - (result, false) - } else { - (result, true) - } + result } -fn split_string_into_words(long_string: ByteArray) -> Array { +fn split_question_into_words(question: ByteArray) -> Array { let mut words: Array = ArrayTrait::new(); let mut current_word = ""; let mut i = 0; - while i < long_string.len() { - let byte = long_string[i]; - if byte == 32 { + while i < question.len() { + let char = question[i]; + if char == ' ' { + if current_word.len() > 0 { + words.append(current_word); + current_word = ""; + } + } else if ((char == '?')) { if current_word.len() > 0 { words.append(current_word); current_word = ""; } - } else if (byte == 63) { break; } else { - current_word.append_byte(byte); + current_word.append_byte(char); } i += 1; }; - if current_word.len() > 0 { - words.append(current_word); - } - words } -fn convert_ByteArray_to_int(num: @ByteArray) -> Option { +fn parse_int(num: @ByteArray) -> Option { let mut result: Option = Option::Some(0); let mut size = num.len(); let mut i = 0; - let mut base = 0; - let mut isSigned = false; - if num.at(i).unwrap() == 45 { - isSigned = true; - size -= 1; + let mut is_signed = false; + if num.at(i).unwrap() == '-' { + is_signed = true; + i += 1; } - let num: ByteArray = num.rev(); while i < size { - let mut args = ""; - args.append_byte(num.at(i).unwrap()); - let re = get_number(args); + let re = char_to_digit(num[i]); match re { - Option::Some(v) => { base += v * pow(i); }, + Option::Some(v) => { + if let Option::Some(max) = result { + result = Option::Some(max * 10 + v.into()); + } + }, Option::None => { result = Option::None; break; @@ -139,65 +126,40 @@ fn convert_ByteArray_to_int(num: @ByteArray) -> Option { i += 1; }; - if result != Option::None { - if (isSigned) { - base *= -1; - } - return Option::Some(base); - } else { - return result; + match result { + Option::Some(val) => { if (is_signed) { + result = Option::Some(val * -1) + } }, + Option::None => { + result = Option::None + }, } -} - - -fn pow(mut power: u32) -> i32 { - let base: i32 = 10; - let mut result = 1_i32; - while power != 0 { - result *= base; - power -= 1; - }; - - result.try_into().expect('too large to fit output type') + result } fn parse_operator(word: @ByteArray) -> Operator { if (word == @"plus") { - return Operator::Plus; + Operator::Plus } else if (word == @"minus") { - return Operator::Minus; + Operator::Minus } else if (word == @"multiplied") { - return Operator::Multiply; + Operator::Multiply } else if (word == @"divided") { - return Operator::Divide; + Operator::Divide } else { - return Operator::Invalid; + Operator::Invalid } } -fn get_number(c: ByteArray) -> Option { - if c == "1" { - Option::Some(1) - } else if c == "2" { - Option::Some(2) - } else if c == "3" { - Option::Some(3) - } else if c == "4" { - Option::Some(4) - } else if c == "5" { - Option::Some(5) - } else if c == "6" { - Option::Some(6) - } else if c == "7" { - Option::Some(7) - } else if c == "8" { - Option::Some(8) - } else if c == "9" { - Option::Some(9) - } else if c == "0" { - Option::Some(0) +// Utility function to convert a char representing a digit into its numerical value (u32 equivalent) +fn char_to_digit(c: u8) -> Option { + let zero_ascii = '0'; + let nine_ascii = '9'; + + if c >= zero_ascii && c <= nine_ascii { + Option::Some(c - zero_ascii) } else { - Option::None + Option::None // Return None for invalid characters } -} +} \ No newline at end of file diff --git a/exercises/practice/wordy/src/lib.cairo b/exercises/practice/wordy/src/lib.cairo index 5ffe6d84..8122fe90 100644 --- a/exercises/practice/wordy/src/lib.cairo +++ b/exercises/practice/wordy/src/lib.cairo @@ -1,3 +1,3 @@ -pub fn answer(word: ByteArray) -> (i32, bool) { +pub fn answer(question: ByteArray) -> (i32, bool) { panic!("implement `answer`") } diff --git a/exercises/practice/wordy/tests/wordy.cairo b/exercises/practice/wordy/tests/wordy.cairo index 0db0d1e0..41a03e04 100644 --- a/exercises/practice/wordy/tests/wordy.cairo +++ b/exercises/practice/wordy/tests/wordy.cairo @@ -4,7 +4,7 @@ use wordy::answer; fn just_a_number() { let input = "What is 5?"; let output = answer(input); - let expected = (5, true); + let expected = 5; assert_eq!(output, expected); } @@ -14,7 +14,7 @@ fn just_a_number() { fn addition() { let input = "What is 1 plus 1?"; let output = answer(input); - let expected = (2, true); + let expected = 2; assert_eq!(output, expected); } @@ -24,7 +24,7 @@ fn addition() { fn more_addition() { let input = "What is 53 plus 2?"; let output = answer(input); - let expected = (55, true); + let expected = 55; assert_eq!(output, expected); } @@ -35,7 +35,7 @@ fn addition_with_negative_numbers() { let input = "What is -1 plus -10?"; let output = answer(input); - let expected = (-11, true); + let expected = -11; assert_eq!(output, expected); } @@ -46,7 +46,7 @@ fn large_addition() { let input = "What is 123 plus 45678?"; let output = answer(input); - let expected = (45801, true); + let expected = 45801; assert_eq!(output, expected); } @@ -57,7 +57,7 @@ fn subtraction() { let input = "What is 4 minus -12?"; let output = answer(input); - let expected = (16, true); + let expected = 16; assert_eq!(output, expected); } @@ -67,7 +67,7 @@ fn subtraction() { fn multiplication() { let input = "What is -3 multiplied by 25?"; let output = answer(input); - let expected = (-75, true); + let expected = -75; assert_eq!(output, expected); } @@ -78,7 +78,7 @@ fn division() { let input = "What is 33 divided by -3?"; let output = answer(input); - let expected = (-11, true); + let expected = -11; assert_eq!(output, expected); } @@ -88,7 +88,7 @@ fn multiple_additions() { let input = "What is 1 plus 1 plus 1?"; let output = answer(input); - let expected = (3, true); + let expected = 3; assert_eq!(output, expected); } @@ -98,7 +98,7 @@ fn addition_and_subtraction() { let input = "What is 1 plus 5 minus -2?"; let output = answer(input); - let expected = (8, true); + let expected = 8; assert_eq!(output, expected); } @@ -108,7 +108,7 @@ fn multiple_subtraction() { let input = "What is 20 minus 4 minus 13?"; let output = answer(input); - let expected = (3, true); + let expected = 3; assert_eq!(output, expected); } @@ -118,7 +118,7 @@ fn subtraction_then_addition() { let input = "What is 17 minus 6 plus 3?"; let output = answer(input); - let expected = (14, true); + let expected = 14; assert_eq!(output, expected); } @@ -127,7 +127,7 @@ fn subtraction_then_addition() { fn multiple_multiplication() { let input = "What is 2 multiplied by -2 multiplied by 3?"; let output = answer(input); - let expected = (-12, true); + let expected = -12; assert_eq!(output, expected); } @@ -137,7 +137,7 @@ fn addition_and_multiplication() { let input = "What is -3 plus 7 multiplied by -2?"; let output = answer(input); - let expected = (-8, true); + let expected = -8; assert_eq!(output, expected); } @@ -147,79 +147,73 @@ fn multiple_division() { let input = "What is -12 divided by 2 divided by -3?"; let output = answer(input); - let expected = (2, true); + let expected = 2; assert_eq!(output, expected); } #[test] #[ignore] +#[should_panic(expected: "unknown operation")] fn unknown_operation() { let input = "What is 52 cubed?"; let output = answer(input); - let expected = (0, false); + let expected = 0; assert_eq!(output, expected); } #[test] #[ignore] +#[should_panic(expected: "unknown operation")] fn non_math_question() { let input = "Who is the President of the United States?"; - let output = answer(input); - let expected = (0, false); - assert_eq!(output, expected); + answer(input); } #[test] #[ignore] +#[should_panic(expected: "syntax error")] fn reject_problem_missing_an_operand() { let input = "What is 1 plus?"; - let output = answer(input); - let expected = (0, false); - assert_eq!(output, expected); + answer(input); } #[test] #[ignore] +#[should_panic(expected: "syntax error")] fn reject_problem_with_no_operands_or_operators() { let input = "What is?"; - let output = answer(input); - let expected = (0, false); - assert_eq!(output, expected); + answer(input); } #[test] #[ignore] +#[should_panic(expected: "syntax error")] fn reject_two_operations_in_a_row() { let input = "What is 1 plus plus 2?"; - let output = answer(input); - let expected = (0, false); - assert_eq!(output, expected); + answer(input); } #[test] #[ignore] +#[should_panic(expected: "syntax error")] fn reject_two_numbers_in_a_row() { let input = "What is 1 plus 2 1?"; - let output = answer(input); - let expected = (0, false); - assert_eq!(output, expected); + answer(input); } #[test] #[ignore] +#[should_panic(expected: "syntax error")] fn reject_postfix_notation() { let input = "What is 1 2 plus?"; - let output = answer(input); - let expected = (0, false); - assert_eq!(output, expected); + answer(input); } #[test] #[ignore] +#[should_panic(expected: "syntax error")] fn reject_prefix_notation() { let input = "What is plus 1 2?"; - let output = answer(input); - let expected = (0, false); - assert_eq!(output, expected); + answer(input); } From 008fd0e67859fb3245d147a0de89cbac845d2fd7 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Thu, 17 Oct 2024 15:13:41 +0100 Subject: [PATCH 24/63] wordy: formatted --- config.json | 155 +++++-------------- exercises/practice/wordy/.meta/example.cairo | 6 +- 2 files changed, 37 insertions(+), 124 deletions(-) diff --git a/config.json b/config.json index 05ec8a42..accebce0 100644 --- a/config.json +++ b/config.json @@ -28,7 +28,6 @@ "exercises": { "concept": [ { -<<<<<<< HEAD "slug": "low-power-embedded-game", "name": "Low-power Embedded Game", "uuid": "f3b7ce44-1667-42b4-b792-401d36aee2f1", @@ -40,16 +39,7 @@ "slug": "lucians-luscious-lasagna", "name": "Lucian's Luscious Lasagna", "uuid": "f120ab92-f277-434c-ae38-a3bb86cb67bf", - "concepts": ["functions"], -======= - "slug": "lucians-luscious-lasagna", - "name": "Lucian's Luscious Lasagna", - "uuid": "f120ab92-f277-434c-ae38-a3bb86cb67bf", - "concepts": [ - "functions", - "mutability" - ], ->>>>>>> refs/remotes/origin/main + "concepts": ["functions", "mutability"], "prerequisites": [], "status": "beta" }, @@ -65,211 +55,136 @@ "slug": "cryptographer", "name": "Cryptographer", "uuid": "7d399f77-4b68-4fc8-9421-43fd24bd4dbe", - "concepts": [ - "felts" - ], - "prerequisites": [ - "functions" - ], + "concepts": ["felts"], + "prerequisites": ["functions"], "status": "wip" }, { "slug": "cars-assemble", "name": "Cars Assemble", "uuid": "57845c17-15e5-4c62-bbac-29ad633e9ebb", - "concepts": [ - "integers" - ], - "prerequisites": [ - "functions" - ], + "concepts": ["integers"], + "prerequisites": ["functions"], "status": "wip" }, { "slug": "welcome-to-tech-palace", "name": "Welcome To Tech Palace!", "uuid": "f8108950-9819-4540-8a3a-880d0778806c", - "concepts": [ - "strings" - ], - "prerequisites": [ - "functions" - ], + "concepts": ["strings"], + "prerequisites": ["functions"], "status": "wip" }, { "slug": "magician-in-training", "name": "Magician in Training", "uuid": "b1f29e1f-adb7-4e37-8101-a1819f1179fa", - "concepts": [ - "arrays" - ], - "prerequisites": [ - "integers" - ], + "concepts": ["arrays"], + "prerequisites": ["integers"], "status": "wip" }, { "slug": "rpn-calculator", "name": "RPN Calculator", "uuid": "536d9f09-5910-4a26-93fd-2242667b0b87", - "concepts": [ - "control-flow" - ], - "prerequisites": [ - "arrays", - "enums" - ], + "concepts": ["control-flow"], + "prerequisites": ["arrays", "enums"], "status": "wip" }, { "slug": "gross-store", "name": "Gross Store", "uuid": "e2ae76c7-379e-430d-92d6-9eaaa823acca", - "concepts": [ - "dictionaries" - ], - "prerequisites": [ - "control-flow" - ], + "concepts": ["dictionaries"], + "prerequisites": ["control-flow"], "status": "wip" }, { "slug": "election-day", "name": "Election Day", "uuid": "29bc1a4a-f295-44db-be19-d8e63dc526dc", - "concepts": [ - "ownership", - "structs", - "references-and-snapshots" - ], - "prerequisites": [ - "dictionaries" - ], + "concepts": ["ownership", "structs", "references-and-snapshots"], + "prerequisites": ["dictionaries"], "status": "wip" }, { "slug": "red-vs-blue-darwin-style", "name": "Red vs. Blue: Darwin Style", "uuid": "30761b1c-0c9a-4c91-8d16-1adf8bc4a0dd", - "concepts": [ - "packages-crates-modules" - ], - "prerequisites": [ - "structs" - ], + "concepts": ["packages-crates-modules"], + "prerequisites": ["structs"], "status": "wip" }, { "slug": "health-statistics", "name": "Health Statistics", "uuid": "69389197-e1dc-43bf-865d-d9b58d59b4e7", - "concepts": [ - "method-syntax" - ], - "prerequisites": [ - "structs", - "references-and-snapshots" - ], + "concepts": ["method-syntax"], + "prerequisites": ["structs", "references-and-snapshots"], "status": "wip" }, { "slug": "airport-robot", "name": "Airport Robot", "uuid": "f0c994d7-d183-4dfa-9048-b20be6f3bf2e", - "concepts": [ - "generics", - "traits" - ], - "prerequisites": [ - "method-syntax" - ], + "concepts": ["generics", "traits"], + "prerequisites": ["method-syntax"], "status": "wip" }, { "slug": "low-power-embedded-game", "name": "Low-power Embedded Game", "uuid": "f3b7ce44-1667-42b4-b792-401d36aee2f1", - "concepts": [ - "tuples" - ], - "prerequisites": [ - "traits" - ], + "concepts": ["tuples"], + "prerequisites": ["traits"], "status": "wip" }, { "slug": "the-realm-of-echoes", "name": "the-realm-of-echoes", "uuid": "c8fd3bd0-290e-4472-b967-9a201dfd3041", - "concepts": [ - "printing" - ], - "prerequisites": [ - "traits" - ], + "concepts": ["printing"], + "prerequisites": ["traits"], "status": "wip" }, { "slug": "role-playing-game", "name": "Role Playing Game", "uuid": "1b014752-c3a4-4250-9483-89696864461b", - "concepts": [ - "options" - ], - "prerequisites": [ - "structs", - "method-syntax" - ], + "concepts": ["options"], + "prerequisites": ["structs", "method-syntax"], "status": "wip" }, { "slug": "magical-measurements", "name": "Magical Measurements", "uuid": "590fc9b0-2b5d-4dab-81ca-b43f9987b1f5", - "concepts": [ - "type-conversion" - ], - "prerequisites": [ - "options", - "printing" - ], + "concepts": ["type-conversion"], + "prerequisites": ["options", "printing"], "status": "wip" }, { "slug": "the-farm", "name": "The Farm", "uuid": "e167e30c-84b1-44da-b21c-70bc46688f20", - "concepts": [ - "error-handling" - ], - "prerequisites": [ - "structs" - ], + "concepts": ["error-handling"], + "prerequisites": ["structs"], "status": "wip" }, { "slug": "chrono-realms", "name": "Chrono Realms", "uuid": "eb15461a-ffdc-4bdd-acc1-e95bd7a1ac91", - "concepts": [ - "operator-overloading" - ], - "prerequisites": [ - "generics" - ], + "concepts": ["operator-overloading"], + "prerequisites": ["generics"], "status": "wip" }, { "slug": "chrono-realms-time-tree", "name": "Chrono Realms Time Tree", "uuid": "a72139a1-825e-4349-a6b5-400b665fbe07", - "concepts": [ - "smart-pointers" - ], - "prerequisites": [ - "structs" - ], + "concepts": ["smart-pointers"], + "prerequisites": ["structs"], "status": "wip" } ], diff --git a/exercises/practice/wordy/.meta/example.cairo b/exercises/practice/wordy/.meta/example.cairo index 20a5450f..7b9986a1 100644 --- a/exercises/practice/wordy/.meta/example.cairo +++ b/exercises/practice/wordy/.meta/example.cairo @@ -21,7 +21,7 @@ pub fn answer(question: ByteArray) -> i32 { Option::Some(s) => { match parse_int(s.unbox()) { Option::Some(s) => s, - Option::None => panic!("syntax error"), + Option::None => panic!("syntax error"), } }, Option::None => panic!("syntax error"), @@ -130,9 +130,7 @@ fn parse_int(num: @ByteArray) -> Option { Option::Some(val) => { if (is_signed) { result = Option::Some(val * -1) } }, - Option::None => { - result = Option::None - }, + Option::None => { result = Option::None }, } result } From 281fd43777cba25d900925c42e66002df4efd5b1 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Thu, 17 Oct 2024 15:20:52 +0100 Subject: [PATCH 25/63] wordy: formatted --- config.json | 8 -------- exercises/practice/wordy/.meta/example.cairo | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/config.json b/config.json index accebce0..7dd8d8a3 100644 --- a/config.json +++ b/config.json @@ -27,14 +27,6 @@ }, "exercises": { "concept": [ - { - "slug": "low-power-embedded-game", - "name": "Low-power Embedded Game", - "uuid": "f3b7ce44-1667-42b4-b792-401d36aee2f1", - "concepts": ["tuples"], - "prerequisites": ["traits"], - "status": "wip" - }, { "slug": "lucians-luscious-lasagna", "name": "Lucian's Luscious Lasagna", diff --git a/exercises/practice/wordy/.meta/example.cairo b/exercises/practice/wordy/.meta/example.cairo index 7b9986a1..696cd323 100644 --- a/exercises/practice/wordy/.meta/example.cairo +++ b/exercises/practice/wordy/.meta/example.cairo @@ -160,4 +160,4 @@ fn char_to_digit(c: u8) -> Option { } else { Option::None // Return None for invalid characters } -} \ No newline at end of file +} From 9f03b7f447cdefa78e84cf5fa75b2db17261152b Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Thu, 17 Oct 2024 15:26:03 +0100 Subject: [PATCH 26/63] wordy: formatted --- config.json | 272 ++++++++++++++++----- exercises/practice/wordy/.meta/config.json | 4 +- 2 files changed, 215 insertions(+), 61 deletions(-) diff --git a/config.json b/config.json index 7dd8d8a3..4969f1ed 100644 --- a/config.json +++ b/config.json @@ -19,11 +19,21 @@ "average_run_time": 5 }, "files": { - "solution": ["src/lib.cairo"], - "test": ["tests/%{snake_slug}.cairo"], - "example": [".meta/example.cairo"], - "exemplar": [".meta/exemplar.cairo"], - "invalidator": ["Scarb.toml"] + "solution": [ + "src/lib.cairo" + ], + "test": [ + "tests/%{snake_slug}.cairo" + ], + "example": [ + ".meta/example.cairo" + ], + "exemplar": [ + ".meta/exemplar.cairo" + ], + "invalidator": [ + "Scarb.toml" + ] }, "exercises": { "concept": [ @@ -31,7 +41,10 @@ "slug": "lucians-luscious-lasagna", "name": "Lucian's Luscious Lasagna", "uuid": "f120ab92-f277-434c-ae38-a3bb86cb67bf", - "concepts": ["functions", "mutability"], + "concepts": [ + "functions", + "mutability" + ], "prerequisites": [], "status": "beta" }, @@ -39,144 +52,223 @@ "slug": "annalyns-infiltration", "name": "Annalyn's Infiltration", "uuid": "da0f8d71-36ed-4c98-9e43-60a04ea5db3a", - "concepts": ["booleans"], - "prerequisites": ["functions"], + "concepts": [ + "booleans" + ], + "prerequisites": [ + "functions" + ], "status": "wip" }, { "slug": "cryptographer", "name": "Cryptographer", "uuid": "7d399f77-4b68-4fc8-9421-43fd24bd4dbe", - "concepts": ["felts"], - "prerequisites": ["functions"], + "concepts": [ + "felts" + ], + "prerequisites": [ + "functions" + ], "status": "wip" }, { "slug": "cars-assemble", "name": "Cars Assemble", "uuid": "57845c17-15e5-4c62-bbac-29ad633e9ebb", - "concepts": ["integers"], - "prerequisites": ["functions"], + "concepts": [ + "integers" + ], + "prerequisites": [ + "functions" + ], "status": "wip" }, { "slug": "welcome-to-tech-palace", "name": "Welcome To Tech Palace!", "uuid": "f8108950-9819-4540-8a3a-880d0778806c", - "concepts": ["strings"], - "prerequisites": ["functions"], + "concepts": [ + "strings" + ], + "prerequisites": [ + "functions" + ], "status": "wip" }, { "slug": "magician-in-training", "name": "Magician in Training", "uuid": "b1f29e1f-adb7-4e37-8101-a1819f1179fa", - "concepts": ["arrays"], - "prerequisites": ["integers"], + "concepts": [ + "arrays" + ], + "prerequisites": [ + "integers" + ], "status": "wip" }, { "slug": "rpn-calculator", "name": "RPN Calculator", "uuid": "536d9f09-5910-4a26-93fd-2242667b0b87", - "concepts": ["control-flow"], - "prerequisites": ["arrays", "enums"], + "concepts": [ + "control-flow" + ], + "prerequisites": [ + "arrays", + "enums" + ], "status": "wip" }, { "slug": "gross-store", "name": "Gross Store", "uuid": "e2ae76c7-379e-430d-92d6-9eaaa823acca", - "concepts": ["dictionaries"], - "prerequisites": ["control-flow"], + "concepts": [ + "dictionaries" + ], + "prerequisites": [ + "control-flow" + ], "status": "wip" }, { "slug": "election-day", "name": "Election Day", "uuid": "29bc1a4a-f295-44db-be19-d8e63dc526dc", - "concepts": ["ownership", "structs", "references-and-snapshots"], - "prerequisites": ["dictionaries"], + "concepts": [ + "ownership", + "structs", + "references-and-snapshots" + ], + "prerequisites": [ + "dictionaries" + ], "status": "wip" }, { "slug": "red-vs-blue-darwin-style", "name": "Red vs. Blue: Darwin Style", "uuid": "30761b1c-0c9a-4c91-8d16-1adf8bc4a0dd", - "concepts": ["packages-crates-modules"], - "prerequisites": ["structs"], + "concepts": [ + "packages-crates-modules" + ], + "prerequisites": [ + "structs" + ], "status": "wip" }, { "slug": "health-statistics", "name": "Health Statistics", "uuid": "69389197-e1dc-43bf-865d-d9b58d59b4e7", - "concepts": ["method-syntax"], - "prerequisites": ["structs", "references-and-snapshots"], + "concepts": [ + "method-syntax" + ], + "prerequisites": [ + "structs", + "references-and-snapshots" + ], "status": "wip" }, { "slug": "airport-robot", "name": "Airport Robot", "uuid": "f0c994d7-d183-4dfa-9048-b20be6f3bf2e", - "concepts": ["generics", "traits"], - "prerequisites": ["method-syntax"], + "concepts": [ + "generics", + "traits" + ], + "prerequisites": [ + "method-syntax" + ], "status": "wip" }, { "slug": "low-power-embedded-game", "name": "Low-power Embedded Game", "uuid": "f3b7ce44-1667-42b4-b792-401d36aee2f1", - "concepts": ["tuples"], - "prerequisites": ["traits"], + "concepts": [ + "tuples" + ], + "prerequisites": [ + "traits" + ], "status": "wip" }, { "slug": "the-realm-of-echoes", "name": "the-realm-of-echoes", "uuid": "c8fd3bd0-290e-4472-b967-9a201dfd3041", - "concepts": ["printing"], - "prerequisites": ["traits"], + "concepts": [ + "printing" + ], + "prerequisites": [ + "traits" + ], "status": "wip" }, { "slug": "role-playing-game", "name": "Role Playing Game", "uuid": "1b014752-c3a4-4250-9483-89696864461b", - "concepts": ["options"], - "prerequisites": ["structs", "method-syntax"], + "concepts": [ + "options" + ], + "prerequisites": [ + "structs", + "method-syntax" + ], "status": "wip" }, { "slug": "magical-measurements", "name": "Magical Measurements", "uuid": "590fc9b0-2b5d-4dab-81ca-b43f9987b1f5", - "concepts": ["type-conversion"], - "prerequisites": ["options", "printing"], + "concepts": [ + "type-conversion" + ], + "prerequisites": [ + "options", + "printing" + ], "status": "wip" }, { "slug": "the-farm", "name": "The Farm", "uuid": "e167e30c-84b1-44da-b21c-70bc46688f20", - "concepts": ["error-handling"], - "prerequisites": ["structs"], + "concepts": [ + "error-handling" + ], + "prerequisites": [ + "structs" + ], "status": "wip" }, { "slug": "chrono-realms", "name": "Chrono Realms", "uuid": "eb15461a-ffdc-4bdd-acc1-e95bd7a1ac91", - "concepts": ["operator-overloading"], - "prerequisites": ["generics"], + "concepts": [ + "operator-overloading" + ], + "prerequisites": [ + "generics" + ], "status": "wip" }, { "slug": "chrono-realms-time-tree", "name": "Chrono Realms Time Tree", "uuid": "a72139a1-825e-4349-a6b5-400b665fbe07", - "concepts": ["smart-pointers"], - "prerequisites": ["structs"], + "concepts": [ + "smart-pointers" + ], + "prerequisites": [ + "structs" + ], "status": "wip" } ], @@ -185,7 +277,10 @@ "slug": "hello-world", "name": "Hello World", "uuid": "1a0e23d9-e8f9-493a-af46-2be040173b64", - "practices": ["strings", "felts"], + "practices": [ + "strings", + "felts" + ], "prerequisites": [], "difficulty": 1 }, @@ -193,7 +288,9 @@ "slug": "reverse-string", "name": "Reverse String", "uuid": "df9f3e80-acf5-41e0-9321-d4b13b26a036", - "practices": ["strings"], + "practices": [ + "strings" + ], "prerequisites": [], "difficulty": 1 }, @@ -241,7 +338,10 @@ "slug": "leap", "name": "Leap", "uuid": "9b586e17-928c-42bf-95ed-67539daea9a8", - "practices": ["booleans", "integers"], + "practices": [ + "booleans", + "integers" + ], "prerequisites": [], "difficulty": 2 }, @@ -249,7 +349,10 @@ "slug": "semi-structured-logs", "name": "Semi Structured Logs", "uuid": "4ca5087f-0128-4845-89a8-a2fa7791ed98", - "practices": ["enums", "match-basics"], + "practices": [ + "enums", + "match-basics" + ], "prerequisites": [], "difficulty": 2 }, @@ -257,7 +360,9 @@ "slug": "darts", "name": "Darts", "uuid": "3e5fb791-59b5-4ea6-b68f-70ed851a3308", - "practices": ["control-flow"], + "practices": [ + "control-flow" + ], "prerequisites": [], "difficulty": 2 }, @@ -321,7 +426,9 @@ "slug": "raindrops", "name": "Raindrops", "uuid": "d2cc23d5-2ed1-4115-9b9a-4b62993e750c", - "practices": ["strings"], + "practices": [ + "strings" + ], "prerequisites": [], "difficulty": 2 }, @@ -369,7 +476,9 @@ "slug": "armstrong-numbers", "name": "Armstrong Numbers", "uuid": "4aaa153d-3416-4101-8143-35b068a15451", - "practices": ["packages-crates-modules"], + "practices": [ + "packages-crates-modules" + ], "prerequisites": [], "difficulty": 3 }, @@ -377,7 +486,11 @@ "slug": "sublist", "name": "Sublist", "uuid": "e62b1bb4-fb37-4dfe-ad81-e0fa5c494ba3", - "practices": ["arrays", "enums", "generics"], + "practices": [ + "arrays", + "enums", + "generics" + ], "prerequisites": [], "difficulty": 3 }, @@ -385,7 +498,11 @@ "slug": "scrabble-score", "name": "Scrabble Score", "uuid": "3ef58f8c-99d4-48be-bb15-a1a5763e5052", - "practices": ["dictionaries", "strings", "felts"], + "practices": [ + "dictionaries", + "strings", + "felts" + ], "prerequisites": [], "difficulty": 3 }, @@ -409,7 +526,10 @@ "slug": "beer-song", "name": "Beer Song", "uuid": "d96a8ba2-6e80-45ce-91d6-5b4cac391db6", - "practices": ["control-flow", "strings"], + "practices": [ + "control-flow", + "strings" + ], "prerequisites": [], "difficulty": 3 }, @@ -417,7 +537,10 @@ "slug": "clock", "name": "Clock", "uuid": "b44728f6-f2ad-4fa4-a20e-5144f9a81e3e", - "practices": ["traits", "printing"], + "practices": [ + "traits", + "printing" + ], "prerequisites": [], "difficulty": 4 }, @@ -447,7 +570,12 @@ "slug": "binary-search", "name": "Binary Search", "uuid": "46be407d-13b8-4a7f-9a9a-4cef93485ba7", - "practices": ["arrays", "enums", "control-flow", "generics"], + "practices": [ + "arrays", + "enums", + "control-flow", + "generics" + ], "prerequisites": [], "difficulty": 4 }, @@ -455,7 +583,11 @@ "slug": "largest-series-product", "name": "Largest Series Product", "uuid": "d0cae4fa-22a8-4604-9f0f-f90751245ce3", - "practices": ["enums", "error-handling", "control-flow"], + "practices": [ + "enums", + "error-handling", + "control-flow" + ], "prerequisites": [], "difficulty": 4 }, @@ -463,7 +595,11 @@ "slug": "allergies", "name": "Allergies", "uuid": "ef701095-b324-49f0-913e-2fb2e1f5f27a", - "practices": ["enums", "structs", "traits"], + "practices": [ + "enums", + "structs", + "traits" + ], "prerequisites": [], "difficulty": 4 }, @@ -506,7 +642,12 @@ "slug": "custom-set", "name": "Custom Set", "uuid": "aad80498-750c-4a7d-b82a-f52f90c54e11", - "practices": ["structs", "generics", "traits", "operator-overloading"], + "practices": [ + "structs", + "generics", + "traits", + "operator-overloading" + ], "prerequisites": [], "difficulty": 6 }, @@ -528,7 +669,10 @@ "slug": "simple-linked-list", "name": "Simple Linked List", "uuid": "cc9a6bf9-9027-42c4-a71d-082ce48f7869", - "practices": ["smart-pointers", "generics"], + "practices": [ + "smart-pointers", + "generics" + ], "prerequisites": [], "difficulty": 7 }, @@ -536,7 +680,12 @@ "slug": "protein-translation", "name": "Protein Translation", "uuid": "d42e7a29-64b9-478b-8b2a-44fd002391fa", - "practices": ["dictionaries", "strings", "felts", "type-conversion"], + "practices": [ + "dictionaries", + "strings", + "felts", + "type-conversion" + ], "prerequisites": [], "difficulty": 8 }, @@ -552,7 +701,10 @@ "slug": "linked-list", "name": "Linked List", "uuid": "1924c44e-bfa2-4dac-a7a9-779e4039ac56", - "practices": ["structs", "traits"], + "practices": [ + "structs", + "traits" + ], "prerequisites": [], "difficulty": 10 }, diff --git a/exercises/practice/wordy/.meta/config.json b/exercises/practice/wordy/.meta/config.json index a7481a7f..426cc2ef 100644 --- a/exercises/practice/wordy/.meta/config.json +++ b/exercises/practice/wordy/.meta/config.json @@ -1,5 +1,7 @@ { - "authors": ["Ephraim-nonso"], + "authors": [ + "Ephraim-nonso" + ], "files": { "solution": [ "src/lib.cairo" From df787674297f1246e44307561a5e3f434827b2fe Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Fri, 18 Oct 2024 13:16:14 +0100 Subject: [PATCH 27/63] wordy: error handling. --- exercises/practice/wordy/.meta/example.cairo | 41 +++++++------------- 1 file changed, 13 insertions(+), 28 deletions(-) diff --git a/exercises/practice/wordy/.meta/example.cairo b/exercises/practice/wordy/.meta/example.cairo index 696cd323..df0c17b6 100644 --- a/exercises/practice/wordy/.meta/example.cairo +++ b/exercises/practice/wordy/.meta/example.cairo @@ -9,22 +9,12 @@ enum Operator { pub fn answer(question: ByteArray) -> i32 { let words: Array = split_question_into_words(question); - if words.len() < 3 { - panic!("syntax error"); - } - - if words[0] != @"What" || words[1] != @"is" { - panic!("unknown operation"); - } + assert!(words.len() >= 3, "syntax error"); + assert!(words[0] == @"What" && words[1] == @"is", "unknown operation"); - let mut result: i32 = match words.get(2) { - Option::Some(s) => { - match parse_int(s.unbox()) { - Option::Some(s) => s, - Option::None => panic!("syntax error"), - } - }, - Option::None => panic!("syntax error"), + let mut result = match parse_int(words[2]) { + Option::Some(s) => s, + Option::None => panic!("syntax error") }; let mut i = 3; @@ -33,12 +23,10 @@ pub fn answer(question: ByteArray) -> i32 { i += 1; if op == Operator::Multiply || op == Operator::Divide { - if i >= words.len() || words[i] != @"by" { - panic!("unknown operation"); - } + assert!(i < words.len() && words[i] == @"by", "unknown operation"); i += 1; - } else if op == Operator::Invalid && parse_int(words.at(i - 1)) == Option::None { - panic!("unknown operation"); + } else if op == Operator::Invalid { + assert!(parse_int(words.at(i - 1)) != Option::None, "unknown operation"); } let num: i32 = match words.get(i) { @@ -56,9 +44,7 @@ pub fn answer(question: ByteArray) -> i32 { Operator::Minus => result - num, Operator::Multiply => result * num, Operator::Divide => { - if num == 0 { - panic!("unknown operation"); - } + assert!(num != 0, "unknown operation"); result / num }, Operator::Invalid => panic!("unknown operation"), @@ -83,7 +69,7 @@ fn split_question_into_words(question: ByteArray) -> Array { words.append(current_word); current_word = ""; } - } else if ((char == '?')) { + } else if char == '?' { if current_word.len() > 0 { words.append(current_word); current_word = ""; @@ -126,11 +112,10 @@ fn parse_int(num: @ByteArray) -> Option { i += 1; }; - match result { - Option::Some(val) => { if (is_signed) { + if let Option::Some(val) = result { + if (is_signed) { result = Option::Some(val * -1) - } }, - Option::None => { result = Option::None }, + } } result } From 2470417e032f8f09f3c89aa9217507321b7a0e06 Mon Sep 17 00:00:00 2001 From: Nenad Date: Fri, 18 Oct 2024 14:44:41 +0200 Subject: [PATCH 28/63] Update exercises/practice/wordy/src/lib.cairo --- exercises/practice/wordy/src/lib.cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/wordy/src/lib.cairo b/exercises/practice/wordy/src/lib.cairo index 8122fe90..6ecb8fd4 100644 --- a/exercises/practice/wordy/src/lib.cairo +++ b/exercises/practice/wordy/src/lib.cairo @@ -1,3 +1,3 @@ -pub fn answer(question: ByteArray) -> (i32, bool) { +pub fn answer(question: ByteArray) -> i32 { panic!("implement `answer`") } From 0c7ed6b8168ae74b2e7cb99a17c0dbd8364cb356 Mon Sep 17 00:00:00 2001 From: Nenad Date: Fri, 18 Oct 2024 14:45:28 +0200 Subject: [PATCH 29/63] Update difficulty to 4 --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index 4969f1ed..1516f84d 100644 --- a/config.json +++ b/config.json @@ -754,7 +754,7 @@ "uuid": "78d31713-0d88-4821-a586-4b36c46eaa44", "practices": [], "prerequisites": [], - "difficulty": 1 + "difficulty": 4 }, { "slug": "high-scores", From 321915637506de561fef162ad936fb028d274488 Mon Sep 17 00:00:00 2001 From: Nenad Date: Fri, 18 Oct 2024 14:48:23 +0200 Subject: [PATCH 30/63] rename max->num in parse_int --- exercises/practice/wordy/.meta/example.cairo | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exercises/practice/wordy/.meta/example.cairo b/exercises/practice/wordy/.meta/example.cairo index df0c17b6..7d2cd24e 100644 --- a/exercises/practice/wordy/.meta/example.cairo +++ b/exercises/practice/wordy/.meta/example.cairo @@ -100,8 +100,8 @@ fn parse_int(num: @ByteArray) -> Option { let re = char_to_digit(num[i]); match re { Option::Some(v) => { - if let Option::Some(max) = result { - result = Option::Some(max * 10 + v.into()); + if let Option::Some(num) = result { + result = Option::Some(num * 10 + v.into()); } }, Option::None => { From 4a876f0f0366c3a86101a6c0475224607ac1d57d Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Thu, 7 Nov 2024 05:17:14 +0100 Subject: [PATCH 31/63] Exercises: Word count --- config.json | 8 + .../practice/word-count/.docs/instructions.md | 47 +++++ .../practice/word-count/.docs/introduction.md | 8 + .../practice/word-count/.meta/config.json | 21 ++ .../practice/word-count/.meta/example.cairo | 119 +++++++++++ .../practice/word-count/.meta/tests.toml | 57 ++++++ exercises/practice/word-count/Scarb.toml | 0 exercises/practice/word-count/src/lib.cairo | 3 + .../word-count/tests/word_count.cairo | 185 ++++++++++++++++++ 9 files changed, 448 insertions(+) create mode 100644 exercises/practice/word-count/.docs/instructions.md create mode 100644 exercises/practice/word-count/.docs/introduction.md create mode 100644 exercises/practice/word-count/.meta/config.json create mode 100644 exercises/practice/word-count/.meta/example.cairo create mode 100644 exercises/practice/word-count/.meta/tests.toml create mode 100644 exercises/practice/word-count/Scarb.toml create mode 100644 exercises/practice/word-count/src/lib.cairo create mode 100644 exercises/practice/word-count/tests/word_count.cairo diff --git a/config.json b/config.json index 1516f84d..2ce6e3d6 100644 --- a/config.json +++ b/config.json @@ -819,6 +819,14 @@ "practices": [], "prerequisites": [], "difficulty": 4 + }, + { + "slug": "word-count", + "name": "Word Count", + "uuid": "5fded933-439a-4faa-bfb6-18ec7b7c8469", + "practices": [], + "prerequisites": [], + "difficulty": 1 } ], "foregone": [ diff --git a/exercises/practice/word-count/.docs/instructions.md b/exercises/practice/word-count/.docs/instructions.md new file mode 100644 index 00000000..064393c8 --- /dev/null +++ b/exercises/practice/word-count/.docs/instructions.md @@ -0,0 +1,47 @@ +# Instructions + +Your task is to count how many times each word occurs in a subtitle of a drama. + +The subtitles from these dramas use only ASCII characters. + +The characters often speak in casual English, using contractions like _they're_ or _it's_. +Though these contractions come from two words (e.g. _we are_), the contraction (_we're_) is considered a single word. + +Words can be separated by any form of punctuation (e.g. ":", "!", or "?") or whitespace (e.g. "\t", "\n", or " "). +The only punctuation that does not separate words is the apostrophe in contractions. + +Numbers are considered words. +If the subtitles say _It costs 100 dollars._ then _100_ will be its own word. + +Words are case insensitive. +For example, the word _you_ occurs three times in the following sentence: + +> You come back, you hear me? DO YOU HEAR ME? + +The ordering of the word counts in the results doesn't matter. + +Here's an example that incorporates several of the elements discussed above: + +- simple words +- contractions +- numbers +- case insensitive words +- punctuation (including apostrophes) to separate words +- different forms of whitespace to separate words + +`"That's the password: 'PASSWORD 123'!", cried the Special Agent.\nSo I fled.` + +The mapping for this subtitle would be: + +```text +123: 1 +agent: 1 +cried: 1 +fled: 1 +i: 1 +password: 2 +so: 1 +special: 1 +that's: 1 +the: 2 +``` diff --git a/exercises/practice/word-count/.docs/introduction.md b/exercises/practice/word-count/.docs/introduction.md new file mode 100644 index 00000000..1654508e --- /dev/null +++ b/exercises/practice/word-count/.docs/introduction.md @@ -0,0 +1,8 @@ +# Introduction + +You teach English as a foreign language to high school students. + +You've decided to base your entire curriculum on TV shows. +You need to analyze which words are used, and how often they're repeated. + +This will let you choose the simplest shows to start with, and to gradually increase the difficulty as time passes. diff --git a/exercises/practice/word-count/.meta/config.json b/exercises/practice/word-count/.meta/config.json new file mode 100644 index 00000000..522d1d97 --- /dev/null +++ b/exercises/practice/word-count/.meta/config.json @@ -0,0 +1,21 @@ +{ + "authors": [ + "Ephraim-nonso" + ], + "files": { + "solution": [ + "src/lib.cairo" + ], + "test": [ + "tests/word_count.cairo" + ], + "example": [ + ".meta/example.cairo" + ], + "invalidator": [ + "Scarb.tom;" + ] + }, + "blurb": "Given a phrase, count the occurrences of each word in that phrase.", + "source": "This is a classic toy problem, but we were reminded of it by seeing it in the Go Tour." +} diff --git a/exercises/practice/word-count/.meta/example.cairo b/exercises/practice/word-count/.meta/example.cairo new file mode 100644 index 00000000..7cc056b0 --- /dev/null +++ b/exercises/practice/word-count/.meta/example.cairo @@ -0,0 +1,119 @@ +use core::dict::Felt252Dict; + + +// word_count returns the dictionary of frequency of words based on the input phrase. +pub fn word_count(phrase: ByteArray) -> Felt252Dict { + let mut result: Felt252Dict = Default::default(); + let words = split_phrase_into_words(phrase); + + let mut arr_to_felt: Array = ArrayTrait::new(); + + let mut i = 0; + while i < words.len() { + arr_to_felt.append(bytearray_to_felt252(words[i])); + + let frequency = result.get(*arr_to_felt[i]); + result.insert(*arr_to_felt[i], frequency + 1); + + i += 1; + }; + + result +} + +// split phrase into words +fn split_phrase_into_words(phrase: ByteArray) -> Array { + let mut words: Array = ArrayTrait::new(); + let mut current_word = ""; + + let mut i = 0; + while i < phrase.len() { + let lower_case = to_lowercase(phrase[i]); + if is_alphanumeric_or_apostrophe(lower_case) { + current_word.append_byte(lower_case); + } else if current_word.len() > 0 { + current_word = split_apostrophe_from_word(current_word); // all checks happen here + words.append(current_word); + current_word = ""; + } + + i += 1; + }; + + // Final word check after the loop + if current_word.len() > 0 { + current_word = split_apostrophe_from_word(current_word); + words.append(current_word); + }; + + words +} + +// Trim apostrophes at the start or end or both sides of the current word +fn split_apostrophe_from_word(mut current_word: ByteArray) -> ByteArray { + let mut i = 0; + let mut new_word = ""; + while i < current_word.len() { + if current_word[0] == '\'' && current_word[current_word.len() - 1] == '\'' { + if i > 0 && current_word[i] == '\'' && i < current_word.len() - 1 { + new_word.append_byte(get_value(current_word.at(i))); + } else if current_word[i] != '\'' { + new_word.append_byte(get_value(current_word.at(i))); + } + } else if current_word[0] == '\'' { + if i != current_word.len() - 1 { + new_word.append_byte(get_value(current_word.at(i + 1))); + } + } else if current_word[current_word.len() - 1] == '\'' { + if current_word[i] != '\'' { + new_word.append_byte(get_value(current_word.at(i))); + } + } else { + new_word.append_byte(get_value(current_word.at(i))); + } + + i += 1; + }; + + new_word +} + +// get u8 value from an option +fn get_value(option: Option) -> u8 { + match option { + Option::Some(value) => value, // Extracts and returns the u8 value + Option::None => { + // Handle None case appropriately; here we return a default of 0 + 0 + } + } +} + +// convert byteArray to felt252 +fn bytearray_to_felt252(words: @ByteArray) -> felt252 { + let mut result: felt252 = 0; + + let mut i = 0; + while i < words.len() { + let byte: u8 = words[i]; + + result = result * 256 + (byte.into()); + i += 1; + }; + + result +} + +fn is_alphanumeric_or_apostrophe(char: u8) -> bool { + // Check if character is alphanumeric or an apostrophe + ('0' <= char && char <= '9') || ('a' <= char && char <= 'z') || ('A' <= char && char <= 'Z') || char == '\'' +} + +fn to_lowercase(char: u8) -> u8 { + // Convert ASCII uppercase letters to lowercase + if 'A' <= char && char <= 'Z' { + char + 32 // Convert to lowercase by ASCII offset + } else { + ch + } +} diff --git a/exercises/practice/word-count/.meta/tests.toml b/exercises/practice/word-count/.meta/tests.toml new file mode 100644 index 00000000..1be425b3 --- /dev/null +++ b/exercises/practice/word-count/.meta/tests.toml @@ -0,0 +1,57 @@ +# 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. + +[61559d5f-2cad-48fb-af53-d3973a9ee9ef] +description = "count one word" + +[5abd53a3-1aed-43a4-a15a-29f88c09cbbd] +description = "count one of each word" + +[2a3091e5-952e-4099-9fac-8f85d9655c0e] +description = "multiple occurrences of a word" + +[e81877ae-d4da-4af4-931c-d923cd621ca6] +description = "handles cramped lists" + +[7349f682-9707-47c0-a9af-be56e1e7ff30] +description = "handles expanded lists" + +[a514a0f2-8589-4279-8892-887f76a14c82] +description = "ignore punctuation" + +[d2e5cee6-d2ec-497b-bdc9-3ebe092ce55e] +description = "include numbers" + +[dac6bc6a-21ae-4954-945d-d7f716392dbf] +description = "normalize case" + +[4185a902-bdb0-4074-864c-f416e42a0f19] +description = "with apostrophes" +include = false + +[4ff6c7d7-fcfc-43ef-b8e7-34ff1837a2d3] +description = "with apostrophes" +reimplements = "4185a902-bdb0-4074-864c-f416e42a0f19" + +[be72af2b-8afe-4337-b151-b297202e4a7b] +description = "with quotations" + +[8d6815fe-8a51-4a65-96f9-2fb3f6dc6ed6] +description = "substrings from the beginning" + +[c5f4ef26-f3f7-4725-b314-855c04fb4c13] +description = "multiple spaces not detected as a word" + +[50176e8a-fe8e-4f4c-b6b6-aa9cf8f20360] +description = "alternating word separators not detected as a word" + +[6d00f1db-901c-4bec-9829-d20eb3044557] +description = "quotation for word with apostrophe" diff --git a/exercises/practice/word-count/Scarb.toml b/exercises/practice/word-count/Scarb.toml new file mode 100644 index 00000000..e69de29b diff --git a/exercises/practice/word-count/src/lib.cairo b/exercises/practice/word-count/src/lib.cairo new file mode 100644 index 00000000..2d885589 --- /dev/null +++ b/exercises/practice/word-count/src/lib.cairo @@ -0,0 +1,3 @@ +pub fn word_count(phrase: ByteArray) -> Felt252Dict { + panic!("implement `word_count`") +} \ No newline at end of file diff --git a/exercises/practice/word-count/tests/word_count.cairo b/exercises/practice/word-count/tests/word_count.cairo new file mode 100644 index 00000000..c401c86a --- /dev/null +++ b/exercises/practice/word-count/tests/word_count.cairo @@ -0,0 +1,185 @@ +use super::word_count; +use super::bytearray_to_felt252; // handle bytearray for invocation from Felt252Dict + +#[test] +fn count_one_word() { + let input = "word"; + let mut output = word_count(input); + let expected_count = 1; + assert_eq!(output.get('word'), expected_count); +} + +#[test] +fn count_one_of_each_word() { + let input = "one of each"; + let mut output = word_count(input); + let expected_count_one = 1; + + assert_eq!(output.get('one'), expected_count_one); + assert_eq!(output.get('of'), expected_count_one); + assert_eq!(output.get('each'), expected_count_one); +} + +#[test] +fn multiple_occurrences_of_a_word() { + let input = "one fish two fish red fish blue fish"; + let mut output = word_count(input); + let expected_count_one = 1; + let expected_count_four = 4; + + assert_eq!(output.get('one'), expected_count_one); + assert_eq!(output.get('fish'), expected_count_four); + assert_eq!(output.get('red'), expected_count_one); + assert_eq!(output.get('blue'), expected_count_one); + assert_eq!(output.get('two'), expected_count_one); +} + +#[test] +fn handles_cramped_lists() { + let input = "one,two,three"; + let mut output = word_count(input); + + let expected_count_one = 1; + + assert_eq!(output.get('one'), expected_count_one); + assert_eq!(output.get('two'), expected_count_one); + assert_eq!(output.get('three'), expected_count_one); +} + +#[test] +fn handles_expanded_lists() { + let input = "one,\ntwo,\nthree"; + let mut output = word_count(input); + + let expected_count_one = 1; + + assert_eq!(output.get('one'), expected_count_one); + assert_eq!(output.get('two'), expected_count_one); + assert_eq!(output.get('three'), expected_count_one); +} + +#[test] +fn ignore_punctuation() { + let input = "car: carpet as java: javascript!!&@$%^&"; + let mut output = word_count(input); + + let expected_count_one = 1; + + assert_eq!(output.get('car'), expected_count_one); + assert_eq!(output.get('carpet'), expected_count_one); + assert_eq!(output.get('as'), expected_count_one); + assert_eq!(output.get('as'), expected_count_one); + assert_eq!(output.get('java'), expected_count_one); + assert_eq!(output.get('java'), expected_count_one); + assert_eq!(output.get('javascript'), expected_count_one); +} + +#[test] +fn include_numbers() { + let input = "testing, 1, 2 testing"; + let mut output = word_count(input); + + let expected_count_1 = 1; + let expected_count_2 = 2; + + assert_eq!(output.get('testing'), expected_count_2); + assert_eq!(output.get('1'), expected_count_1); + assert_eq!(output.get('2'), expected_count_1); +} + +#[test] +fn normalize_case() { + let input = "go Go GO Stop stop"; + let mut output = word_count(input); + + let expected_count_go = 3; + let expected_count_stop = 2; + + assert_eq!(output.get('go'), expected_count_go); + assert_eq!(output.get('stop'), expected_count_stop); +} + +#[test] +fn with_apostrophes() { + let input = "'First: don't laugh. Then: don't cry. You're getting it.'"; + let mut output = word_count(input); + + let expected_count_one = 1; + let expected_count_two = 2; + + assert_eq!(output.get('first'), expected_count_one); + assert_eq!(output.get(bytearray_to_felt252(@"don't")), expected_count_two); + assert_eq!(output.get('laugh'), expected_count_one); + assert_eq!(output.get('then'), expected_count_one); + assert_eq!(output.get('cry'), expected_count_one); + assert_eq!(output.get(bytearray_to_felt252(@"you're")), expected_count_one); + assert_eq!(output.get('getting'), expected_count_one); + assert_eq!(output.get('it'), expected_count_one); +} + +#[test] +fn with_quotations() { + let input = "Joe can't tell between 'large' and large."; + let mut output = word_count(input); + + let expected_count_one = 1; + let expected_count_two = 2; + + assert_eq!(output.get('joe'), expected_count_one); + assert_eq!(output.get(bytearray_to_felt252(@"can't")), expected_count_one); + assert_eq!(output.get('tell'), expected_count_one); + assert_eq!(output.get('between'), expected_count_one); + assert_eq!(output.get('large'), expected_count_two); + assert_eq!(output.get('and'), expected_count_one); +} + +#[test] +fn substrings_from_the_beginning() { + let input = "Joe can't tell between app, apple and a."; + let mut output = word_count(input); + + let expected_count_one = 1; + + assert_eq!(output.get('joe'), expected_count_one); + assert_eq!(output.get(bytearray_to_felt252(@"can't")), expected_count_one); + assert_eq!(output.get('tell'), expected_count_one); + assert_eq!(output.get('between'), expected_count_one); + assert_eq!(output.get('app'), expected_count_one); + assert_eq!(output.get('apple'), expected_count_one); + assert_eq!(output.get('and'), expected_count_one); + assert_eq!(output.get('a'), expected_count_one); +} + +#[test] +fn multiple_spaces_not_detected_as_a_word() { + let input = " multiple whitespaces"; + let mut output = word_count(input); + + let expected_count_one = 1; + + assert_eq!(output.get('multiple'), expected_count_one); + assert_eq!(output.get('whitespaces'), expected_count_one); +} + +#[test] +fn alternating_word_separators_not_detected_as_a_word() { + let input = ",\n,one,\n ,two \n 'three'"; + let mut output = word_count(input); + let expected_count_one = 1; + + assert_eq!(output.get('one'), expected_count_one); + assert_eq!(output.get('two'), expected_count_one); + assert_eq!(output.get('three'), expected_count_one); +} + +#[test] +fn quotation_for_word_with_apostrophe() { + let input = "can, can't, 'can't'"; + let mut output = word_count(input); + + let expected_count_one = 1; + let expected_count_two = 2; + + assert_eq!(output.get('can'), expected_count_one); + assert_eq!(output.get(bytearray_to_felt252(@"can't")), expected_count_two); +} From 62f50c7dee259e709cdad2208f37efc5a3c96863 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Thu, 7 Nov 2024 05:19:52 +0100 Subject: [PATCH 32/63] Exercises: Word count --- exercises/practice/word-count/.meta/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/word-count/.meta/config.json b/exercises/practice/word-count/.meta/config.json index 522d1d97..a390fa4f 100644 --- a/exercises/practice/word-count/.meta/config.json +++ b/exercises/practice/word-count/.meta/config.json @@ -13,7 +13,7 @@ ".meta/example.cairo" ], "invalidator": [ - "Scarb.tom;" + "Scarb.toml" ] }, "blurb": "Given a phrase, count the occurrences of each word in that phrase.", From deb3b7f5b4b9b87f05517918da13d6e48e74ae1e Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Mon, 11 Nov 2024 13:41:46 +0100 Subject: [PATCH 33/63] word count:changes requested --- .../practice/word-count/.meta/example.cairo | 72 ++++-- .../word-count/tests/word_count.cairo | 216 +++++++++--------- 2 files changed, 160 insertions(+), 128 deletions(-) diff --git a/exercises/practice/word-count/.meta/example.cairo b/exercises/practice/word-count/.meta/example.cairo index 7cc056b0..a161bce6 100644 --- a/exercises/practice/word-count/.meta/example.cairo +++ b/exercises/practice/word-count/.meta/example.cairo @@ -1,26 +1,64 @@ -use core::dict::Felt252Dict; - - -// word_count returns the dictionary of frequency of words based on the input phrase. -pub fn word_count(phrase: ByteArray) -> Felt252Dict { - let mut result: Felt252Dict = Default::default(); - let words = split_phrase_into_words(phrase); +#[derive(Debug, PartialEq, Clone, Drop)] +pub struct WordResult { + pub word: ByteArray, + pub count: u64, +} - let mut arr_to_felt: Array = ArrayTrait::new(); +fn count_words(phrase: ByteArray) -> Span { + let mut results: Array = ArrayTrait::new(); + let words = split_phrase_into_words(phrase); // Split the phrase into words let mut i = 0; while i < words.len() { - arr_to_felt.append(bytearray_to_felt252(words[i])); + let mut found = false; // Flag to check if word is found in results + + // Check if the word already exists in the results + let mut j = 0; + while j < results.len() { + if results[j].word == words[i] { // Compare words + // We can't mutate results[j] directly, so we need to create a new WordResult + let updated_result = WordResult { + word: results[j].word.clone(), + count: *results[j].count + 1, // Increment the count + }; + + // Remove the old result and append the updated one + results = remove_index_from_array(results, j); + results.append(updated_result); + found = true; // Word found, no need to add it + break; // Exit the inner loop + } + j += 1; + }; - let frequency = result.get(*arr_to_felt[i]); - result.insert(*arr_to_felt[i], frequency + 1); + // If the word wasn't found, add it to the results + if !found { + let word_and_count = WordResult { word: words[i].clone(), count: 1 }; + results.append(word_and_count); + } i += 1; }; - result + results.span() // Return the results as a span } +fn remove_index_from_array(arr: Array, index: u32) -> Array { + let mut new_arr: Array = ArrayTrait::new(); + + // Iterate through the original array, skipping the element at `index` + let mut i = 0; + while i < arr.len() { + if i != index { + new_arr.append(arr[i].clone()); + } + i += 1; + }; + + new_arr +} + + // split phrase into words fn split_phrase_into_words(phrase: ByteArray) -> Array { let mut words: Array = ArrayTrait::new(); @@ -104,15 +142,15 @@ fn bytearray_to_felt252(words: @ByteArray) -> felt252 { result } -fn is_alphanumeric_or_apostrophe(char: u8) -> bool { +fn is_alphanumeric_or_apostrophe(ch: u8) -> bool { // Check if character is alphanumeric or an apostrophe - ('0' <= char && char <= '9') || ('a' <= char && char <= 'z') || ('A' <= char && char <= 'Z') || char == '\'' + ('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ch == '\'' } -fn to_lowercase(char: u8) -> u8 { +fn to_lowercase(ch: u8) -> u8 { // Convert ASCII uppercase letters to lowercase - if 'A' <= char && char <= 'Z' { - char + 32 // Convert to lowercase by ASCII offset + if 'A' <= ch && ch <= 'Z' { + ch + 32 // Convert to lowercase by ASCII offset } else { ch } diff --git a/exercises/practice/word-count/tests/word_count.cairo b/exercises/practice/word-count/tests/word_count.cairo index c401c86a..e11acf6b 100644 --- a/exercises/practice/word-count/tests/word_count.cairo +++ b/exercises/practice/word-count/tests/word_count.cairo @@ -1,185 +1,179 @@ -use super::word_count; -use super::bytearray_to_felt252; // handle bytearray for invocation from Felt252Dict +use super::count_words; #[test] +#[ignore] fn count_one_word() { let input = "word"; - let mut output = word_count(input); - let expected_count = 1; - assert_eq!(output.get('word'), expected_count); + let mut output = count_words(input); + + let expected = array![WordResult { word: "word", count: 1 }].span(); + assert_eq!(output, expected); } #[test] fn count_one_of_each_word() { let input = "one of each"; - let mut output = word_count(input); - let expected_count_one = 1; - - assert_eq!(output.get('one'), expected_count_one); - assert_eq!(output.get('of'), expected_count_one); - assert_eq!(output.get('each'), expected_count_one); + let mut output = count_words(input); + + let expected = array![ + WordResult { word: "one", count: 1 }, + WordResult { word: "of", count: 1 }, + WordResult { word: "each", count: 1 } + ] + .span(); + assert_eq!(output, expected); } #[test] fn multiple_occurrences_of_a_word() { let input = "one fish two fish red fish blue fish"; - let mut output = word_count(input); - let expected_count_one = 1; - let expected_count_four = 4; - - assert_eq!(output.get('one'), expected_count_one); - assert_eq!(output.get('fish'), expected_count_four); - assert_eq!(output.get('red'), expected_count_one); - assert_eq!(output.get('blue'), expected_count_one); - assert_eq!(output.get('two'), expected_count_one); + let mut output = count_words(input); + + let expected = array![WordResult { word: "one", count: 1 }, WordResult { word: "two", count: 1 }, WordResult { word: "red", count: 1 }, WordResult { word: "blue", count: 1 }, WordResult { word: "fish", count: 4 }] + .span(); + assert_eq!(output, expected); } #[test] fn handles_cramped_lists() { let input = "one,two,three"; - let mut output = word_count(input); - - let expected_count_one = 1; - - assert_eq!(output.get('one'), expected_count_one); - assert_eq!(output.get('two'), expected_count_one); - assert_eq!(output.get('three'), expected_count_one); + let mut output = count_words(input); + + let expected = array![ + WordResult { word: "one", count: 1 }, + WordResult { word: "two", count: 1 }, + WordResult { word: "three", count: 1 } + ] + .span(); + assert_eq!(output, expected); } #[test] fn handles_expanded_lists() { let input = "one,\ntwo,\nthree"; - let mut output = word_count(input); - - let expected_count_one = 1; - - assert_eq!(output.get('one'), expected_count_one); - assert_eq!(output.get('two'), expected_count_one); - assert_eq!(output.get('three'), expected_count_one); + let mut output = count_words(input); + + let expected = array![ + WordResult { word: "one", count: 1 }, + WordResult { word: "two", count: 1 }, + WordResult { word: "three", count: 1 } + ] + .span(); + assert_eq!(output, expected); } #[test] fn ignore_punctuation() { let input = "car: carpet as java: javascript!!&@$%^&"; - let mut output = word_count(input); - - let expected_count_one = 1; - - assert_eq!(output.get('car'), expected_count_one); - assert_eq!(output.get('carpet'), expected_count_one); - assert_eq!(output.get('as'), expected_count_one); - assert_eq!(output.get('as'), expected_count_one); - assert_eq!(output.get('java'), expected_count_one); - assert_eq!(output.get('java'), expected_count_one); - assert_eq!(output.get('javascript'), expected_count_one); + let mut output = count_words(input); + + let expected = array![ + WordResult { word: "car", count: 1 }, + WordResult { word: "carpet", count: 1 }, + WordResult { word: "as", count: 1 }, + WordResult { word: "java", count: 1 }, + WordResult { word: "javascript", count: 1 } + ] + .span(); + assert_eq!(output, expected); } #[test] fn include_numbers() { let input = "testing, 1, 2 testing"; - let mut output = word_count(input); + let mut output = count_words(input); - let expected_count_1 = 1; - let expected_count_2 = 2; - - assert_eq!(output.get('testing'), expected_count_2); - assert_eq!(output.get('1'), expected_count_1); - assert_eq!(output.get('2'), expected_count_1); + let expected = array![WordResult { word: "1", count: 1 }, WordResult { word: "2", count: 1 }, WordResult { word: "testing", count: 2 }] + .span(); + assert_eq!(output, expected); } #[test] fn normalize_case() { let input = "go Go GO Stop stop"; - let mut output = word_count(input); - - let expected_count_go = 3; - let expected_count_stop = 2; + let mut output = count_words(input); - assert_eq!(output.get('go'), expected_count_go); - assert_eq!(output.get('stop'), expected_count_stop); + let expected = array![ + WordResult { word: "go", count: 3 }, WordResult { word: "stop", count: 2 } + ] + .span(); + assert_eq!(output, expected); } #[test] fn with_apostrophes() { let input = "'First: don't laugh. Then: don't cry. You're getting it.'"; - let mut output = word_count(input); - - let expected_count_one = 1; - let expected_count_two = 2; - - assert_eq!(output.get('first'), expected_count_one); - assert_eq!(output.get(bytearray_to_felt252(@"don't")), expected_count_two); - assert_eq!(output.get('laugh'), expected_count_one); - assert_eq!(output.get('then'), expected_count_one); - assert_eq!(output.get('cry'), expected_count_one); - assert_eq!(output.get(bytearray_to_felt252(@"you're")), expected_count_one); - assert_eq!(output.get('getting'), expected_count_one); - assert_eq!(output.get('it'), expected_count_one); + let mut output = count_words(input); + + let expected = array![WordResult { word: "first", count: 1 }, WordResult { word: "laugh", count: 1 }, WordResult { word: "then", count: 1 }, WordResult { word: "don't", count: 2 }, WordResult { word: "cry", count: 1 }, WordResult { word: "you're", count: 1 }, WordResult { word: "getting", count: 1 }, WordResult { word: "it", count: 1 }, WordResult { word: "", count: 1 }] + .span(); + assert_eq!(output, expected); } #[test] fn with_quotations() { let input = "Joe can't tell between 'large' and large."; - let mut output = word_count(input); - - let expected_count_one = 1; - let expected_count_two = 2; + let mut output = count_words(input); - assert_eq!(output.get('joe'), expected_count_one); - assert_eq!(output.get(bytearray_to_felt252(@"can't")), expected_count_one); - assert_eq!(output.get('tell'), expected_count_one); - assert_eq!(output.get('between'), expected_count_one); - assert_eq!(output.get('large'), expected_count_two); - assert_eq!(output.get('and'), expected_count_one); + let expected = array![WordResult { word: "joe", count: 1 }, WordResult { word: "can't", count: 1 }, WordResult { word: "tell", count: 1 }, WordResult { word: "between", count: 1 }, WordResult { word: "and", count: 1 }, WordResult { word: "large", count: 2 }] + .span(); + assert_eq!(output, expected); } #[test] fn substrings_from_the_beginning() { let input = "Joe can't tell between app, apple and a."; - let mut output = word_count(input); - - let expected_count_one = 1; - - assert_eq!(output.get('joe'), expected_count_one); - assert_eq!(output.get(bytearray_to_felt252(@"can't")), expected_count_one); - assert_eq!(output.get('tell'), expected_count_one); - assert_eq!(output.get('between'), expected_count_one); - assert_eq!(output.get('app'), expected_count_one); - assert_eq!(output.get('apple'), expected_count_one); - assert_eq!(output.get('and'), expected_count_one); - assert_eq!(output.get('a'), expected_count_one); + let mut output = count_words(input); + + let expected = array![ + WordResult { word: "joe", count: 1 }, + WordResult { word: "can't", count: 1 }, + WordResult { word: "tell", count: 1 }, + WordResult { word: "between", count: 1 }, + WordResult { word: "app", count: 1 }, + WordResult { word: "apple", count: 1 }, + WordResult { word: "and", count: 1 }, + WordResult { word: "a", count: 1 } + ] + .span(); + assert_eq!(output, expected); } #[test] fn multiple_spaces_not_detected_as_a_word() { let input = " multiple whitespaces"; - let mut output = word_count(input); - - let expected_count_one = 1; - - assert_eq!(output.get('multiple'), expected_count_one); - assert_eq!(output.get('whitespaces'), expected_count_one); + let mut output = count_words(input); + + let expected = array![ + WordResult { word: "multiple", count: 1 }, + WordResult { word: "whitespaces", count: 1 } + ] + .span(); + assert_eq!(output, expected); } #[test] fn alternating_word_separators_not_detected_as_a_word() { let input = ",\n,one,\n ,two \n 'three'"; - let mut output = word_count(input); - let expected_count_one = 1; - - assert_eq!(output.get('one'), expected_count_one); - assert_eq!(output.get('two'), expected_count_one); - assert_eq!(output.get('three'), expected_count_one); + let mut output = count_words(input); + + let expected = array![ + WordResult { word: "one", count: 1 }, + WordResult { word: "two", count: 1 }, + WordResult { word: "three", count: 1 } + ] + .span(); + assert_eq!(output, expected); } #[test] fn quotation_for_word_with_apostrophe() { let input = "can, can't, 'can't'"; - let mut output = word_count(input); - - let expected_count_one = 1; - let expected_count_two = 2; + let mut output = count_words(input); - assert_eq!(output.get('can'), expected_count_one); - assert_eq!(output.get(bytearray_to_felt252(@"can't")), expected_count_two); + let expected = array![ + WordResult { word: "can", count: 1 }, WordResult { word: "can't", count: 2 } + ] + .span(); + assert_eq!(output, expected); } From 7abdaab4c2ed8a9f82b148fe99696d3812aebde4 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Mon, 11 Nov 2024 15:51:07 +0100 Subject: [PATCH 34/63] word-count: new changes --- .../practice/word-count/.meta/example.cairo | 63 ++++--------------- exercises/practice/word-count/Scarb.toml | 7 +++ exercises/practice/word-count/src/lib.cairo | 6 +- .../word-count/tests/word_count.cairo | 52 ++++++++++++--- 4 files changed, 68 insertions(+), 60 deletions(-) diff --git a/exercises/practice/word-count/.meta/example.cairo b/exercises/practice/word-count/.meta/example.cairo index a161bce6..00dac420 100644 --- a/exercises/practice/word-count/.meta/example.cairo +++ b/exercises/practice/word-count/.meta/example.cairo @@ -6,32 +6,27 @@ pub struct WordResult { fn count_words(phrase: ByteArray) -> Span { let mut results: Array = ArrayTrait::new(); - let words = split_phrase_into_words(phrase); // Split the phrase into words + let words = split_phrase_into_words(phrase); let mut i = 0; while i < words.len() { - let mut found = false; // Flag to check if word is found in results + let mut found = false; - // Check if the word already exists in the results let mut j = 0; while j < results.len() { - if results[j].word == words[i] { // Compare words - // We can't mutate results[j] directly, so we need to create a new WordResult + if results[j].word == words[i] { let updated_result = WordResult { - word: results[j].word.clone(), - count: *results[j].count + 1, // Increment the count + word: results[j].word.clone(), count: *results[j].count + 1, }; - // Remove the old result and append the updated one results = remove_index_from_array(results, j); results.append(updated_result); - found = true; // Word found, no need to add it - break; // Exit the inner loop + found = true; + break; } j += 1; }; - // If the word wasn't found, add it to the results if !found { let word_and_count = WordResult { word: words[i].clone(), count: 1 }; results.append(word_and_count); @@ -40,13 +35,12 @@ fn count_words(phrase: ByteArray) -> Span { i += 1; }; - results.span() // Return the results as a span + results.span() } fn remove_index_from_array(arr: Array, index: u32) -> Array { let mut new_arr: Array = ArrayTrait::new(); - // Iterate through the original array, skipping the element at `index` let mut i = 0; while i < arr.len() { if i != index { @@ -58,8 +52,6 @@ fn remove_index_from_array(arr: Array, index: u32) -> Array Array { let mut words: Array = ArrayTrait::new(); let mut current_word = ""; @@ -70,7 +62,7 @@ fn split_phrase_into_words(phrase: ByteArray) -> Array { if is_alphanumeric_or_apostrophe(lower_case) { current_word.append_byte(lower_case); } else if current_word.len() > 0 { - current_word = split_apostrophe_from_word(current_word); // all checks happen here + current_word = split_apostrophe_from_word(current_word); words.append(current_word); current_word = ""; } @@ -78,7 +70,6 @@ fn split_phrase_into_words(phrase: ByteArray) -> Array { i += 1; }; - // Final word check after the loop if current_word.len() > 0 { current_word = split_apostrophe_from_word(current_word); words.append(current_word); @@ -87,27 +78,26 @@ fn split_phrase_into_words(phrase: ByteArray) -> Array { words } -// Trim apostrophes at the start or end or both sides of the current word fn split_apostrophe_from_word(mut current_word: ByteArray) -> ByteArray { let mut i = 0; let mut new_word = ""; while i < current_word.len() { if current_word[0] == '\'' && current_word[current_word.len() - 1] == '\'' { if i > 0 && current_word[i] == '\'' && i < current_word.len() - 1 { - new_word.append_byte(get_value(current_word.at(i))); + new_word.append_byte(current_word.at(i).unwrap_or(0)); } else if current_word[i] != '\'' { - new_word.append_byte(get_value(current_word.at(i))); + new_word.append_byte(current_word.at(i).unwrap_or(0)); } } else if current_word[0] == '\'' { if i != current_word.len() - 1 { - new_word.append_byte(get_value(current_word.at(i + 1))); + new_word.append_byte(current_word.at(i + 1).unwrap_or(0)); } } else if current_word[current_word.len() - 1] == '\'' { if current_word[i] != '\'' { - new_word.append_byte(get_value(current_word.at(i))); + new_word.append_byte(current_word.at(i).unwrap_or(0)); } } else { - new_word.append_byte(get_value(current_word.at(i))); + new_word.append_byte(current_word.at(i).unwrap_or(0)); } i += 1; @@ -116,34 +106,7 @@ fn split_apostrophe_from_word(mut current_word: ByteArray) -> ByteArray { new_word } -// get u8 value from an option -fn get_value(option: Option) -> u8 { - match option { - Option::Some(value) => value, // Extracts and returns the u8 value - Option::None => { - // Handle None case appropriately; here we return a default of 0 - 0 - } - } -} - -// convert byteArray to felt252 -fn bytearray_to_felt252(words: @ByteArray) -> felt252 { - let mut result: felt252 = 0; - - let mut i = 0; - while i < words.len() { - let byte: u8 = words[i]; - - result = result * 256 + (byte.into()); - i += 1; - }; - - result -} - fn is_alphanumeric_or_apostrophe(ch: u8) -> bool { - // Check if character is alphanumeric or an apostrophe ('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ch == '\'' } diff --git a/exercises/practice/word-count/Scarb.toml b/exercises/practice/word-count/Scarb.toml index e69de29b..f6fc3bbb 100644 --- a/exercises/practice/word-count/Scarb.toml +++ b/exercises/practice/word-count/Scarb.toml @@ -0,0 +1,7 @@ +[package] +name = "count_words" +version = "0.1.0" +edition = "2024_07" + +[dev-dependencies] +cairo_test = "2.8.2" diff --git a/exercises/practice/word-count/src/lib.cairo b/exercises/practice/word-count/src/lib.cairo index 2d885589..7e547046 100644 --- a/exercises/practice/word-count/src/lib.cairo +++ b/exercises/practice/word-count/src/lib.cairo @@ -1,3 +1,3 @@ -pub fn word_count(phrase: ByteArray) -> Felt252Dict { - panic!("implement `word_count`") -} \ No newline at end of file +pub fn count_words(phrase: ByteArray) -> Span { + panic!("implement `count_words`") +} diff --git a/exercises/practice/word-count/tests/word_count.cairo b/exercises/practice/word-count/tests/word_count.cairo index e11acf6b..e204b616 100644 --- a/exercises/practice/word-count/tests/word_count.cairo +++ b/exercises/practice/word-count/tests/word_count.cairo @@ -1,7 +1,6 @@ use super::count_words; #[test] -#[ignore] fn count_one_word() { let input = "word"; let mut output = count_words(input); @@ -11,6 +10,7 @@ fn count_one_word() { } #[test] +#[ignore] fn count_one_of_each_word() { let input = "one of each"; let mut output = count_words(input); @@ -25,16 +25,24 @@ fn count_one_of_each_word() { } #[test] +#[ignore] fn multiple_occurrences_of_a_word() { let input = "one fish two fish red fish blue fish"; let mut output = count_words(input); - let expected = array![WordResult { word: "one", count: 1 }, WordResult { word: "two", count: 1 }, WordResult { word: "red", count: 1 }, WordResult { word: "blue", count: 1 }, WordResult { word: "fish", count: 4 }] + let expected = array![ + WordResult { word: "one", count: 1 }, + WordResult { word: "two", count: 1 }, + WordResult { word: "red", count: 1 }, + WordResult { word: "blue", count: 1 }, + WordResult { word: "fish", count: 4 } + ] .span(); assert_eq!(output, expected); } #[test] +#[ignore] fn handles_cramped_lists() { let input = "one,two,three"; let mut output = count_words(input); @@ -49,6 +57,7 @@ fn handles_cramped_lists() { } #[test] +#[ignore] fn handles_expanded_lists() { let input = "one,\ntwo,\nthree"; let mut output = count_words(input); @@ -63,6 +72,7 @@ fn handles_expanded_lists() { } #[test] +#[ignore] fn ignore_punctuation() { let input = "car: carpet as java: javascript!!&@$%^&"; let mut output = count_words(input); @@ -79,16 +89,22 @@ fn ignore_punctuation() { } #[test] +#[ignore] fn include_numbers() { let input = "testing, 1, 2 testing"; let mut output = count_words(input); - let expected = array![WordResult { word: "1", count: 1 }, WordResult { word: "2", count: 1 }, WordResult { word: "testing", count: 2 }] + let expected = array![ + WordResult { word: "1", count: 1 }, + WordResult { word: "2", count: 1 }, + WordResult { word: "testing", count: 2 } + ] .span(); assert_eq!(output, expected); } #[test] +#[ignore] fn normalize_case() { let input = "go Go GO Stop stop"; let mut output = count_words(input); @@ -101,26 +117,46 @@ fn normalize_case() { } #[test] +#[ignore] fn with_apostrophes() { let input = "'First: don't laugh. Then: don't cry. You're getting it.'"; let mut output = count_words(input); - let expected = array![WordResult { word: "first", count: 1 }, WordResult { word: "laugh", count: 1 }, WordResult { word: "then", count: 1 }, WordResult { word: "don't", count: 2 }, WordResult { word: "cry", count: 1 }, WordResult { word: "you're", count: 1 }, WordResult { word: "getting", count: 1 }, WordResult { word: "it", count: 1 }, WordResult { word: "", count: 1 }] + let expected = array![ + WordResult { word: "first", count: 1 }, + WordResult { word: "laugh", count: 1 }, + WordResult { word: "then", count: 1 }, + WordResult { word: "don't", count: 2 }, + WordResult { word: "cry", count: 1 }, + WordResult { word: "you're", count: 1 }, + WordResult { word: "getting", count: 1 }, + WordResult { word: "it", count: 1 }, + WordResult { word: "", count: 1 } + ] .span(); assert_eq!(output, expected); } #[test] +#[ignore] fn with_quotations() { let input = "Joe can't tell between 'large' and large."; let mut output = count_words(input); - let expected = array![WordResult { word: "joe", count: 1 }, WordResult { word: "can't", count: 1 }, WordResult { word: "tell", count: 1 }, WordResult { word: "between", count: 1 }, WordResult { word: "and", count: 1 }, WordResult { word: "large", count: 2 }] + let expected = array![ + WordResult { word: "joe", count: 1 }, + WordResult { word: "can't", count: 1 }, + WordResult { word: "tell", count: 1 }, + WordResult { word: "between", count: 1 }, + WordResult { word: "and", count: 1 }, + WordResult { word: "large", count: 2 } + ] .span(); assert_eq!(output, expected); } #[test] +#[ignore] fn substrings_from_the_beginning() { let input = "Joe can't tell between app, apple and a."; let mut output = count_words(input); @@ -140,19 +176,20 @@ fn substrings_from_the_beginning() { } #[test] +#[ignore] fn multiple_spaces_not_detected_as_a_word() { let input = " multiple whitespaces"; let mut output = count_words(input); let expected = array![ - WordResult { word: "multiple", count: 1 }, - WordResult { word: "whitespaces", count: 1 } + WordResult { word: "multiple", count: 1 }, WordResult { word: "whitespaces", count: 1 } ] .span(); assert_eq!(output, expected); } #[test] +#[ignore] fn alternating_word_separators_not_detected_as_a_word() { let input = ",\n,one,\n ,two \n 'three'"; let mut output = count_words(input); @@ -167,6 +204,7 @@ fn alternating_word_separators_not_detected_as_a_word() { } #[test] +#[ignore] fn quotation_for_word_with_apostrophe() { let input = "can, can't, 'can't'"; let mut output = count_words(input); From 4d8892c844ed99e584738fa97bff29b89cf1b004 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Mon, 11 Nov 2024 15:54:32 +0100 Subject: [PATCH 35/63] word-count: new changes --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index 54bf5497..234a8131 100644 --- a/config.json +++ b/config.json @@ -826,7 +826,7 @@ "uuid": "5fded933-439a-4faa-bfb6-18ec7b7c8469", "practices": [], "prerequisites": [], - "difficulty": 1 + "difficulty": 4 }, { "slug": "knapsack", From 77b5c4e28e884db35c83b9ef256af88d865b186c Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Mon, 11 Nov 2024 16:28:11 +0100 Subject: [PATCH 36/63] word-count: new changes --- exercises/practice/word-count/tests/word_count.cairo | 1 + 1 file changed, 1 insertion(+) diff --git a/exercises/practice/word-count/tests/word_count.cairo b/exercises/practice/word-count/tests/word_count.cairo index e204b616..bb17e55b 100644 --- a/exercises/practice/word-count/tests/word_count.cairo +++ b/exercises/practice/word-count/tests/word_count.cairo @@ -1,4 +1,5 @@ use super::count_words; +use super::WordResult; #[test] fn count_one_word() { From 2b7d363cabc1799eb5beb88b32862ef1019d8487 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Mon, 11 Nov 2024 16:29:39 +0100 Subject: [PATCH 37/63] word-count: new changes --- exercises/practice/word-count/.meta/example.cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/word-count/.meta/example.cairo b/exercises/practice/word-count/.meta/example.cairo index 00dac420..a0bd8dde 100644 --- a/exercises/practice/word-count/.meta/example.cairo +++ b/exercises/practice/word-count/.meta/example.cairo @@ -4,7 +4,7 @@ pub struct WordResult { pub count: u64, } -fn count_words(phrase: ByteArray) -> Span { +pub fn count_words(phrase: ByteArray) -> Span { let mut results: Array = ArrayTrait::new(); let words = split_phrase_into_words(phrase); From 12fae9814bf24baee291959e76988f222e8493a0 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Mon, 11 Nov 2024 16:32:35 +0100 Subject: [PATCH 38/63] word-count: new changes --- exercises/practice/word-count/tests/word_count.cairo | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/exercises/practice/word-count/tests/word_count.cairo b/exercises/practice/word-count/tests/word_count.cairo index bb17e55b..e0a81f7f 100644 --- a/exercises/practice/word-count/tests/word_count.cairo +++ b/exercises/practice/word-count/tests/word_count.cairo @@ -1,5 +1,4 @@ -use super::count_words; -use super::WordResult; +use word_count::{count_words, WordResult}; #[test] fn count_one_word() { From ac4b1abf5c900c89055aa30c4ce73d1cd2a1e89f Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Mon, 11 Nov 2024 19:37:27 +0100 Subject: [PATCH 39/63] word-count: new changes --- exercises/practice/word-count/Scarb.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/word-count/Scarb.toml b/exercises/practice/word-count/Scarb.toml index f6fc3bbb..fa54cf30 100644 --- a/exercises/practice/word-count/Scarb.toml +++ b/exercises/practice/word-count/Scarb.toml @@ -1,5 +1,5 @@ [package] -name = "count_words" +name = "word_count" version = "0.1.0" edition = "2024_07" From 44213ae6fa0da46cff4b9391395396375dfa7f30 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Fri, 15 Nov 2024 22:03:17 +0100 Subject: [PATCH 40/63] redesign the split function --- .../practice/word-count/.meta/example.cairo | 58 +++++++------------ .../word-count/tests/word_count.cairo | 49 ++++++++++------ 2 files changed, 52 insertions(+), 55 deletions(-) diff --git a/exercises/practice/word-count/.meta/example.cairo b/exercises/practice/word-count/.meta/example.cairo index a0bd8dde..d494bd86 100644 --- a/exercises/practice/word-count/.meta/example.cairo +++ b/exercises/practice/word-count/.meta/example.cairo @@ -4,7 +4,7 @@ pub struct WordResult { pub count: u64, } -pub fn count_words(phrase: ByteArray) -> Span { +fn count_words(phrase: ByteArray) -> Span { let mut results: Array = ArrayTrait::new(); let words = split_phrase_into_words(phrase); @@ -59,61 +59,45 @@ fn split_phrase_into_words(phrase: ByteArray) -> Array { let mut i = 0; while i < phrase.len() { let lower_case = to_lowercase(phrase[i]); + if is_alphanumeric_or_apostrophe(lower_case) { - current_word.append_byte(lower_case); - } else if current_word.len() > 0 { - current_word = split_apostrophe_from_word(current_word); - words.append(current_word); - current_word = ""; + if !is_apostrophe(lower_case) + || (i > 0 && i < phrase.len() + - 1 && is_alphanumeric(phrase[i - 1]) && is_alphanumeric(phrase[i + 1])) { + current_word.append_byte(lower_case); + } + } else { + if current_word.len() > 0 { + words.append(current_word.clone()); + current_word = ""; + } } i += 1; }; if current_word.len() > 0 { - current_word = split_apostrophe_from_word(current_word); words.append(current_word); - }; + } words } -fn split_apostrophe_from_word(mut current_word: ByteArray) -> ByteArray { - let mut i = 0; - let mut new_word = ""; - while i < current_word.len() { - if current_word[0] == '\'' && current_word[current_word.len() - 1] == '\'' { - if i > 0 && current_word[i] == '\'' && i < current_word.len() - 1 { - new_word.append_byte(current_word.at(i).unwrap_or(0)); - } else if current_word[i] != '\'' { - new_word.append_byte(current_word.at(i).unwrap_or(0)); - } - } else if current_word[0] == '\'' { - if i != current_word.len() - 1 { - new_word.append_byte(current_word.at(i + 1).unwrap_or(0)); - } - } else if current_word[current_word.len() - 1] == '\'' { - if current_word[i] != '\'' { - new_word.append_byte(current_word.at(i).unwrap_or(0)); - } - } else { - new_word.append_byte(current_word.at(i).unwrap_or(0)); - } - - i += 1; - }; +fn is_alphanumeric_or_apostrophe(ch: u8) -> bool { + ('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ch == '\'' +} - new_word +fn is_alphanumeric(ch: u8) -> bool { + ('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') } -fn is_alphanumeric_or_apostrophe(ch: u8) -> bool { - ('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ch == '\'' +fn is_apostrophe(ch: u8) -> bool { + ch == '\'' } fn to_lowercase(ch: u8) -> u8 { - // Convert ASCII uppercase letters to lowercase if 'A' <= ch && ch <= 'Z' { - ch + 32 // Convert to lowercase by ASCII offset + ch + 32 } else { ch } diff --git a/exercises/practice/word-count/tests/word_count.cairo b/exercises/practice/word-count/tests/word_count.cairo index e0a81f7f..673bdf60 100644 --- a/exercises/practice/word-count/tests/word_count.cairo +++ b/exercises/practice/word-count/tests/word_count.cairo @@ -6,7 +6,7 @@ fn count_one_word() { let mut output = count_words(input); let expected = array![WordResult { word: "word", count: 1 }].span(); - assert_eq!(output, expected); + assert_unordered(output, expected); } #[test] @@ -16,12 +16,12 @@ fn count_one_of_each_word() { let mut output = count_words(input); let expected = array![ - WordResult { word: "one", count: 1 }, WordResult { word: "of", count: 1 }, - WordResult { word: "each", count: 1 } + WordResult { word: "each", count: 1 }, + WordResult { word: "one", count: 1 } ] .span(); - assert_eq!(output, expected); + assert_unordered(output, expected); } #[test] @@ -38,7 +38,7 @@ fn multiple_occurrences_of_a_word() { WordResult { word: "fish", count: 4 } ] .span(); - assert_eq!(output, expected); + assert_unordered(output, expected); } #[test] @@ -53,7 +53,7 @@ fn handles_cramped_lists() { WordResult { word: "three", count: 1 } ] .span(); - assert_eq!(output, expected); + assert_unordered(output, expected); } #[test] @@ -68,7 +68,7 @@ fn handles_expanded_lists() { WordResult { word: "three", count: 1 } ] .span(); - assert_eq!(output, expected); + assert_unordered(output, expected); } #[test] @@ -85,7 +85,7 @@ fn ignore_punctuation() { WordResult { word: "javascript", count: 1 } ] .span(); - assert_eq!(output, expected); + assert_unordered(output, expected); } #[test] @@ -95,12 +95,13 @@ fn include_numbers() { let mut output = count_words(input); let expected = array![ + WordResult { word: "testing", count: 2 }, WordResult { word: "1", count: 1 }, WordResult { word: "2", count: 1 }, - WordResult { word: "testing", count: 2 } ] .span(); - assert_eq!(output, expected); + + assert_unordered(output, expected); } #[test] @@ -113,7 +114,7 @@ fn normalize_case() { WordResult { word: "go", count: 3 }, WordResult { word: "stop", count: 2 } ] .span(); - assert_eq!(output, expected); + assert_unordered(output, expected); } #[test] @@ -131,10 +132,9 @@ fn with_apostrophes() { WordResult { word: "you're", count: 1 }, WordResult { word: "getting", count: 1 }, WordResult { word: "it", count: 1 }, - WordResult { word: "", count: 1 } ] .span(); - assert_eq!(output, expected); + assert_unordered(output, expected); } #[test] @@ -152,7 +152,7 @@ fn with_quotations() { WordResult { word: "large", count: 2 } ] .span(); - assert_eq!(output, expected); + assert_unordered(output, expected); } #[test] @@ -172,7 +172,7 @@ fn substrings_from_the_beginning() { WordResult { word: "a", count: 1 } ] .span(); - assert_eq!(output, expected); + assert_unordered(output, expected); } #[test] @@ -185,7 +185,7 @@ fn multiple_spaces_not_detected_as_a_word() { WordResult { word: "multiple", count: 1 }, WordResult { word: "whitespaces", count: 1 } ] .span(); - assert_eq!(output, expected); + assert_unordered(output, expected); } #[test] @@ -200,7 +200,7 @@ fn alternating_word_separators_not_detected_as_a_word() { WordResult { word: "three", count: 1 } ] .span(); - assert_eq!(output, expected); + assert_unordered(output, expected); } #[test] @@ -213,5 +213,18 @@ fn quotation_for_word_with_apostrophe() { WordResult { word: "can", count: 1 }, WordResult { word: "can't", count: 2 } ] .span(); - assert_eq!(output, expected); + assert_unordered(output, expected); +} + + +// helper function. +fn assert_unordered(span1: Span, span2: Span) { + for item in span1 { + for other_item in span2 { + if item.word == other_item.word { + assert_eq!(item.word, other_item.word); + assert_eq!(item.count, other_item.count); + } + } + } } From 4dd9516e6cf3db341995f7c39e90c0d0c94e4c53 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Sat, 16 Nov 2024 07:34:30 +0100 Subject: [PATCH 41/63] build passes --- exercises/practice/word-count/.meta/example.cairo | 2 +- exercises/practice/word-count/src/lib.cairo | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/exercises/practice/word-count/.meta/example.cairo b/exercises/practice/word-count/.meta/example.cairo index d494bd86..34da2a35 100644 --- a/exercises/practice/word-count/.meta/example.cairo +++ b/exercises/practice/word-count/.meta/example.cairo @@ -4,7 +4,7 @@ pub struct WordResult { pub count: u64, } -fn count_words(phrase: ByteArray) -> Span { +pub fn count_words(phrase: ByteArray) -> Span { let mut results: Array = ArrayTrait::new(); let words = split_phrase_into_words(phrase); diff --git a/exercises/practice/word-count/src/lib.cairo b/exercises/practice/word-count/src/lib.cairo index 7e547046..9e46cc2b 100644 --- a/exercises/practice/word-count/src/lib.cairo +++ b/exercises/practice/word-count/src/lib.cairo @@ -1,3 +1,9 @@ +#[derive(Debug, PartialEq, Clone, Drop)] +pub struct WordResult { + pub word: ByteArray, + pub count: u64, +} + pub fn count_words(phrase: ByteArray) -> Span { panic!("implement `count_words`") } From 435ff6a6b62e6ee13f447050c3fafd36ec32f99f Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Sun, 17 Nov 2024 09:05:39 +0100 Subject: [PATCH 42/63] remove dup and update --- exercises/practice/word-count/.meta/example.cairo | 14 ++++---------- .../practice/word-count/tests/word_count.cairo | 15 +++++++++++---- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/exercises/practice/word-count/.meta/example.cairo b/exercises/practice/word-count/.meta/example.cairo index 34da2a35..4f2dcbd1 100644 --- a/exercises/practice/word-count/.meta/example.cairo +++ b/exercises/practice/word-count/.meta/example.cairo @@ -63,14 +63,12 @@ fn split_phrase_into_words(phrase: ByteArray) -> Array { if is_alphanumeric_or_apostrophe(lower_case) { if !is_apostrophe(lower_case) || (i > 0 && i < phrase.len() - - 1 && is_alphanumeric(phrase[i - 1]) && is_alphanumeric(phrase[i + 1])) { + - 1 && is_alphanumeric_or_apostrophe(phrase[i - 1]) && is_alphanumeric_or_apostrophe(phrase[i + 1])) { current_word.append_byte(lower_case); } - } else { - if current_word.len() > 0 { - words.append(current_word.clone()); - current_word = ""; - } + } else if current_word.len() > 0 { + words.append(current_word.clone()); + current_word = ""; } i += 1; @@ -87,10 +85,6 @@ fn is_alphanumeric_or_apostrophe(ch: u8) -> bool { ('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ch == '\'' } -fn is_alphanumeric(ch: u8) -> bool { - ('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') -} - fn is_apostrophe(ch: u8) -> bool { ch == '\'' } diff --git a/exercises/practice/word-count/tests/word_count.cairo b/exercises/practice/word-count/tests/word_count.cairo index 673bdf60..3f3f4333 100644 --- a/exercises/practice/word-count/tests/word_count.cairo +++ b/exercises/practice/word-count/tests/word_count.cairo @@ -220,11 +220,18 @@ fn quotation_for_word_with_apostrophe() { // helper function. fn assert_unordered(span1: Span, span2: Span) { for item in span1 { + let mut found = false; for other_item in span2 { - if item.word == other_item.word { - assert_eq!(item.word, other_item.word); - assert_eq!(item.count, other_item.count); + if item == other_item { + found = true; + break; } - } + }; + assert!( + found, + "assertion failed: `(left == right)`\n left: `{:?}`,\n right `{:?}`", + span1, + span2 + ); } } From 401954a18ab5d7a69714d6bec1c72e391d31a39f Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Sun, 17 Nov 2024 09:20:15 +0100 Subject: [PATCH 43/63] formatted: new --- exercises/practice/word-count/.meta/example.cairo | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/exercises/practice/word-count/.meta/example.cairo b/exercises/practice/word-count/.meta/example.cairo index 4f2dcbd1..18a1e19a 100644 --- a/exercises/practice/word-count/.meta/example.cairo +++ b/exercises/practice/word-count/.meta/example.cairo @@ -63,7 +63,9 @@ fn split_phrase_into_words(phrase: ByteArray) -> Array { if is_alphanumeric_or_apostrophe(lower_case) { if !is_apostrophe(lower_case) || (i > 0 && i < phrase.len() - - 1 && is_alphanumeric_or_apostrophe(phrase[i - 1]) && is_alphanumeric_or_apostrophe(phrase[i + 1])) { + - 1 + && is_alphanumeric_or_apostrophe(phrase[i - 1]) + && is_alphanumeric_or_apostrophe(phrase[i + 1])) { current_word.append_byte(lower_case); } } else if current_word.len() > 0 { From cdbd0fe28e0e9ec03071cce75ab9e7465baf65e2 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Sun, 17 Nov 2024 10:01:21 +0100 Subject: [PATCH 44/63] remove dup --- exercises/practice/word-count/.meta/example.cairo | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/exercises/practice/word-count/.meta/example.cairo b/exercises/practice/word-count/.meta/example.cairo index 18a1e19a..75aab9e7 100644 --- a/exercises/practice/word-count/.meta/example.cairo +++ b/exercises/practice/word-count/.meta/example.cairo @@ -84,7 +84,11 @@ fn split_phrase_into_words(phrase: ByteArray) -> Array { } fn is_alphanumeric_or_apostrophe(ch: u8) -> bool { - ('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ch == '\'' + is_alphanumeric(ch) || is_apostrophe(ch) +} + +fn is_alphanumeric(ch: u8) -> bool { + ('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') } fn is_apostrophe(ch: u8) -> bool { From 5f31d6155a6107f5d24fa23ca2dd23b9475b6171 Mon Sep 17 00:00:00 2001 From: Nenad Date: Mon, 18 Nov 2024 21:55:43 +0100 Subject: [PATCH 45/63] assert_unordered->assert_unordered_eq + verify both are subsets of each other --- .../word-count/tests/word_count.cairo | 47 +++++++++++++------ 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/exercises/practice/word-count/tests/word_count.cairo b/exercises/practice/word-count/tests/word_count.cairo index 3f3f4333..920a19bd 100644 --- a/exercises/practice/word-count/tests/word_count.cairo +++ b/exercises/practice/word-count/tests/word_count.cairo @@ -6,7 +6,7 @@ fn count_one_word() { let mut output = count_words(input); let expected = array![WordResult { word: "word", count: 1 }].span(); - assert_unordered(output, expected); + assert_unordered_eq(output, expected); } #[test] @@ -21,7 +21,7 @@ fn count_one_of_each_word() { WordResult { word: "one", count: 1 } ] .span(); - assert_unordered(output, expected); + assert_unordered_eq(output, expected); } #[test] @@ -38,7 +38,7 @@ fn multiple_occurrences_of_a_word() { WordResult { word: "fish", count: 4 } ] .span(); - assert_unordered(output, expected); + assert_unordered_eq(output, expected); } #[test] @@ -53,7 +53,7 @@ fn handles_cramped_lists() { WordResult { word: "three", count: 1 } ] .span(); - assert_unordered(output, expected); + assert_unordered_eq(output, expected); } #[test] @@ -68,7 +68,7 @@ fn handles_expanded_lists() { WordResult { word: "three", count: 1 } ] .span(); - assert_unordered(output, expected); + assert_unordered_eq(output, expected); } #[test] @@ -85,7 +85,7 @@ fn ignore_punctuation() { WordResult { word: "javascript", count: 1 } ] .span(); - assert_unordered(output, expected); + assert_unordered_eq(output, expected); } #[test] @@ -101,7 +101,7 @@ fn include_numbers() { ] .span(); - assert_unordered(output, expected); + assert_unordered_eq(output, expected); } #[test] @@ -114,7 +114,7 @@ fn normalize_case() { WordResult { word: "go", count: 3 }, WordResult { word: "stop", count: 2 } ] .span(); - assert_unordered(output, expected); + assert_unordered_eq(output, expected); } #[test] @@ -134,7 +134,7 @@ fn with_apostrophes() { WordResult { word: "it", count: 1 }, ] .span(); - assert_unordered(output, expected); + assert_unordered_eq(output, expected); } #[test] @@ -152,7 +152,7 @@ fn with_quotations() { WordResult { word: "large", count: 2 } ] .span(); - assert_unordered(output, expected); + assert_unordered_eq(output, expected); } #[test] @@ -172,7 +172,7 @@ fn substrings_from_the_beginning() { WordResult { word: "a", count: 1 } ] .span(); - assert_unordered(output, expected); + assert_unordered_eq(output, expected); } #[test] @@ -185,7 +185,7 @@ fn multiple_spaces_not_detected_as_a_word() { WordResult { word: "multiple", count: 1 }, WordResult { word: "whitespaces", count: 1 } ] .span(); - assert_unordered(output, expected); + assert_unordered_eq(output, expected); } #[test] @@ -200,7 +200,7 @@ fn alternating_word_separators_not_detected_as_a_word() { WordResult { word: "three", count: 1 } ] .span(); - assert_unordered(output, expected); + assert_unordered_eq(output, expected); } #[test] @@ -213,12 +213,13 @@ fn quotation_for_word_with_apostrophe() { WordResult { word: "can", count: 1 }, WordResult { word: "can't", count: 2 } ] .span(); - assert_unordered(output, expected); + assert_unordered_eq(output, expected); } // helper function. -fn assert_unordered(span1: Span, span2: Span) { +fn assert_unordered_eq(span1: Span, span2: Span) { + // `span1` should be subset of `span2` for item in span1 { let mut found = false; for other_item in span2 { @@ -233,5 +234,21 @@ fn assert_unordered(span1: Span, span2: Span) { span1, span2 ); + }; + // and `span2` should be subset of `span1` + for item in span2 { + let mut found = false; + for other_item in span1 { + if item == other_item { + found = true; + break; + } + }; + assert!( + found, + "assertion failed: `(left == right)`\n left: `{:?}`,\n right `{:?}`", + span1, + span2 + ); } } From 55de0ef881dac407e0e834f32f0b643796d665ad Mon Sep 17 00:00:00 2001 From: Nenad Date: Mon, 18 Nov 2024 21:56:50 +0100 Subject: [PATCH 46/63] Check if prev. and next are alphanumeric --- exercises/practice/word-count/.meta/example.cairo | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/exercises/practice/word-count/.meta/example.cairo b/exercises/practice/word-count/.meta/example.cairo index 75aab9e7..4712f0fa 100644 --- a/exercises/practice/word-count/.meta/example.cairo +++ b/exercises/practice/word-count/.meta/example.cairo @@ -63,9 +63,7 @@ fn split_phrase_into_words(phrase: ByteArray) -> Array { if is_alphanumeric_or_apostrophe(lower_case) { if !is_apostrophe(lower_case) || (i > 0 && i < phrase.len() - - 1 - && is_alphanumeric_or_apostrophe(phrase[i - 1]) - && is_alphanumeric_or_apostrophe(phrase[i + 1])) { + - 1 && is_alphanumeric(phrase[i - 1]) && is_alphanumeric(phrase[i + 1])) { current_word.append_byte(lower_case); } } else if current_word.len() > 0 { From 9947334190393afa4a1c334c99f96f1be9a04bb3 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Mon, 9 Dec 2024 14:30:08 +0100 Subject: [PATCH 47/63] transpose exercise --- config.json | 8 + .../transpose/.docs/instructions.md | 61 ++++++ .../transpose/.meta/config.json | 22 +++ .../transpose/.meta/example.cairo | 35 ++++ .../transpose/.meta/tests.toml | 46 +++++ .../sum-of-multiples/transpose/Scarb.lock | 6 + .../sum-of-multiples/transpose/Scarb.toml | 7 + .../sum-of-multiples/transpose/src/lib.cairo | 3 + .../transpose/tests/transpose.cairo | 174 ++++++++++++++++++ 9 files changed, 362 insertions(+) create mode 100644 exercises/practice/sum-of-multiples/transpose/.docs/instructions.md create mode 100644 exercises/practice/sum-of-multiples/transpose/.meta/config.json create mode 100644 exercises/practice/sum-of-multiples/transpose/.meta/example.cairo create mode 100644 exercises/practice/sum-of-multiples/transpose/.meta/tests.toml create mode 100644 exercises/practice/sum-of-multiples/transpose/Scarb.lock create mode 100644 exercises/practice/sum-of-multiples/transpose/Scarb.toml create mode 100644 exercises/practice/sum-of-multiples/transpose/src/lib.cairo create mode 100644 exercises/practice/sum-of-multiples/transpose/tests/transpose.cairo diff --git a/config.json b/config.json index d7a9f9ba..716ddb6d 100644 --- a/config.json +++ b/config.json @@ -859,6 +859,14 @@ "practices": [], "prerequisites": [], "difficulty": 6 + }, + { + "slug": "transpose", + "name": "Transpose", + "uuid": "59b5d30b-62c1-4465-a44d-485c45f4aac2", + "practices": [], + "prerequisites": [], + "difficulty": 1 } ], "foregone": [ diff --git a/exercises/practice/sum-of-multiples/transpose/.docs/instructions.md b/exercises/practice/sum-of-multiples/transpose/.docs/instructions.md new file mode 100644 index 00000000..6033af74 --- /dev/null +++ b/exercises/practice/sum-of-multiples/transpose/.docs/instructions.md @@ -0,0 +1,61 @@ +# Instructions + +Given an input text output it transposed. + +Roughly explained, the transpose of a matrix: + +```text +ABC +DEF +``` + +is given by: + +```text +AD +BE +CF +``` + +Rows become columns and columns become rows. +See [transpose][]. + +If the input has rows of different lengths, this is to be solved as follows: + +- Pad to the left with spaces. +- Don't pad to the right. + +Therefore, transposing this matrix: + +```text +ABC +DE +``` + +results in: + +```text +AD +BE +C +``` + +And transposing: + +```text +AB +DEF +``` + +results in: + +```text +AD +BE + F +``` + +In general, all characters from the input should also be present in the transposed output. +That means that if a column in the input text contains only spaces on its bottom-most row(s), the corresponding output row should contain the spaces in its right-most column(s). + +[transpose]: https://en.wikipedia.org/wiki/Transpose diff --git a/exercises/practice/sum-of-multiples/transpose/.meta/config.json b/exercises/practice/sum-of-multiples/transpose/.meta/config.json new file mode 100644 index 00000000..6b7c6481 --- /dev/null +++ b/exercises/practice/sum-of-multiples/transpose/.meta/config.json @@ -0,0 +1,22 @@ +{ + "authors": [ + "Ephraim-nonso" + ], + "files": { + "solution": [ + "src/lib.cairo" + ], + "test": [ + "tests/transpose.cairo" + ], + "example": [ + ".meta/example.cairo" + ], + "invalidator": [ + "Scarb.toml" + ] + }, + "blurb": "Take input text and output it transposed.", + "source": "Reddit r/dailyprogrammer challenge #270 [Easy].", + "source_url": "https://web.archive.org/web/20230630051421/https://old.reddit.com/r/dailyprogrammer/comments/4msu2x/challenge_270_easy_transpose_the_input_text/" +} diff --git a/exercises/practice/sum-of-multiples/transpose/.meta/example.cairo b/exercises/practice/sum-of-multiples/transpose/.meta/example.cairo new file mode 100644 index 00000000..964aca9e --- /dev/null +++ b/exercises/practice/sum-of-multiples/transpose/.meta/example.cairo @@ -0,0 +1,35 @@ +pub fn transpose(input: Array) -> Array { + let mut output: Array = ArrayTrait::new(); + + let mut max_length = 0; + for line in input.clone() { + if line.len() > max_length { + max_length = line.len(); + } + }; + + let mut i = 0; + loop { + let mut temp: ByteArray = ""; + for line in input + .clone() { + while i < max_length { + match line.at(i) { + Option::Some(char) => { temp.append_byte(char); }, + Option::None => { temp.append_byte(' '); }, + } + break; + }; + if temp.len() == input.len() { + output.append(temp.clone()); + i += 1; + } + continue; + }; + if i == max_length { + break; + } + }; + + output +} diff --git a/exercises/practice/sum-of-multiples/transpose/.meta/tests.toml b/exercises/practice/sum-of-multiples/transpose/.meta/tests.toml new file mode 100644 index 00000000..32e366fb --- /dev/null +++ b/exercises/practice/sum-of-multiples/transpose/.meta/tests.toml @@ -0,0 +1,46 @@ +# 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. + +[404b7262-c050-4df0-a2a2-0cb06cd6a821] +description = "empty string" + +[a89ce8a3-c940-4703-a688-3ea39412fbcb] +description = "two characters in a row" + +[855bb6ae-4180-457c-abd0-ce489803ce98] +description = "two characters in a column" + +[5ceda1c0-f940-441c-a244-0ced197769c8] +description = "simple" + +[a54675dd-ae7d-4a58-a9c4-0c20e99a7c1f] +description = "single line" + +[0dc2ec0b-549d-4047-aeeb-8029fec8d5c5] +description = "first line longer than second line" + +[984e2ec3-b3d3-4b53-8bd6-96f5ef404102] +description = "second line longer than first line" + +[eccd3784-45f0-4a3f-865a-360cb323d314] +description = "mixed line length" + +[85b96b3f-d00c-4f80-8ca2-c8a5c9216c2d] +description = "square" + +[b9257625-7a53-4748-8863-e08e9d27071d] +description = "rectangle" + +[b80badc9-057e-4543-bd07-ce1296a1ea2c] +description = "triangle" + +[76acfd50-5596-4d05-89f1-5116328a7dd9] +description = "jagged triangle" diff --git a/exercises/practice/sum-of-multiples/transpose/Scarb.lock b/exercises/practice/sum-of-multiples/transpose/Scarb.lock new file mode 100644 index 00000000..8f584341 --- /dev/null +++ b/exercises/practice/sum-of-multiples/transpose/Scarb.lock @@ -0,0 +1,6 @@ +# Code generated by scarb DO NOT EDIT. +version = 1 + +[[package]] +name = "transpose" +version = "0.1.0" diff --git a/exercises/practice/sum-of-multiples/transpose/Scarb.toml b/exercises/practice/sum-of-multiples/transpose/Scarb.toml new file mode 100644 index 00000000..cb6b661c --- /dev/null +++ b/exercises/practice/sum-of-multiples/transpose/Scarb.toml @@ -0,0 +1,7 @@ +[package] +name = "transpose" +version = "0.1.0" +edition = "2024_07" + +[dev-dependencies] +cairo_test = "2.8.2" diff --git a/exercises/practice/sum-of-multiples/transpose/src/lib.cairo b/exercises/practice/sum-of-multiples/transpose/src/lib.cairo new file mode 100644 index 00000000..16834eaf --- /dev/null +++ b/exercises/practice/sum-of-multiples/transpose/src/lib.cairo @@ -0,0 +1,3 @@ +pub fn transpose(input: Array) -> Array { + panic!("implement `transpose`") +} diff --git a/exercises/practice/sum-of-multiples/transpose/tests/transpose.cairo b/exercises/practice/sum-of-multiples/transpose/tests/transpose.cairo new file mode 100644 index 00000000..49b135bd --- /dev/null +++ b/exercises/practice/sum-of-multiples/transpose/tests/transpose.cairo @@ -0,0 +1,174 @@ +use transpose::transpose; + +#[test] +fn empty_string() { + let mut input: Array = array![]; + let expected = array![]; + + let output = transpose(input); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn two_characters_in_a_row() { + let mut input: Array = array!["A1"]; + let expected = array!["A", "1"]; + + let output = transpose(input); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn two_characters_in_a_column() { + let mut input: Array = array!["A", "1"]; + let expected = array!["A1"]; + + let output = transpose(input); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn simple() { + let mut input: Array = array!["ABC", "123"]; + let expected = array!["A1", "B2", "C3"]; + + let output = transpose(input); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn single_line() { + let mut input: Array = array!["Single line."]; + let expected = array!["S", "i", "n", "g", "l", "e", " ", "l", "i", "n", "e", "."]; + + let output = transpose(input); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn first_line_longer_than_second_line() { + let mut input: Array = array!["The fourth line.", "The fifth line."]; + let expected = array![ + "TT", + "hh", + "ee", + " ", + "ff", + "oi", + "uf", + "rt", + "th", + "h ", + " l", + "li", + "in", + "ne", + "e.", + ". " + ]; + + let output = transpose(input); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn second_line_longer_than_first_line() { + let mut input: Array = array!["The first line.", "The second line."]; + let expected = array![ + "TT", + "hh", + "ee", + " ", + "fs", + "ie", + "rc", + "so", + "tn", + " d", + "l ", + "il", + "ni", + "en", + ".e", + " ." + ]; + + let output = transpose(input); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn mixed_line_length() { + let mut input: Array = array![ + "The longest line.", "A long line.", "A longer line.", "A line." + ]; + let expected = array![ + "TAAA", + "h ", + "elll", + " ooi", + "lnnn", + "ogge", + "n e.", + "glr ", + "ei ", + "snl ", + "tei ", + " .n ", + "l e ", + "i . ", + "n ", + "e ", + ". " + ]; + + let output = transpose(input); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn square() { + let mut input: Array = array!["HEART", "EMBER", "ABUSE", "RESIN", "TREND"]; + let expected = array!["HEART", "EMBER", "ABUSE", "RESIN", "TREND"]; + + let output = transpose(input); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn rectangle() { + let mut input: Array = array!["FRACTURE", "OUTLINED", "BLOOMING", "SEPTETTE"]; + let expected = array!["FOBS", "RULE", "ATOP", "CLOT", "TIME", "UNIT", "RENT", "EDGE"]; + + let output = transpose(input); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn triangle() { + let mut input: Array = array!["T", "EE", "AAA", "SSSS", "EEEEE", "RRRRRR"]; + let expected = array!["TEASER", " EASER", " ASER", " SER", " ER", " R"]; + + let output = transpose(input); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn jagged_triangle() { + let mut input: Array = array!["11", "2", "3333", "444", "555555", "66666"]; + let expected = array!["123456", "1 3456", " 3456", " 3 56", " 56", " 5 "]; + + let output = transpose(input); + assert_eq!(output, expected); +} From 86c7638253adfd63084b0551a9f5ff93e3b71dc7 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Thu, 17 Oct 2024 14:53:18 +0100 Subject: [PATCH 48/63] Wordy: update fmt --- config.json | 256 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 255 insertions(+), 1 deletion(-) diff --git a/config.json b/config.json index 5430a8f5..692680b9 100644 --- a/config.json +++ b/config.json @@ -39,7 +39,7 @@ "slug": "lucians-luscious-lasagna", "name": "Lucian's Luscious Lasagna", "uuid": "f120ab92-f277-434c-ae38-a3bb86cb67bf", - "concepts": ["functions"], + "concepts": ["functions", "mutability"], "prerequisites": [], "status": "beta" }, @@ -50,6 +50,142 @@ "concepts": ["booleans"], "prerequisites": ["functions"], "status": "wip" + }, + { + "slug": "cryptographer", + "name": "Cryptographer", + "uuid": "7d399f77-4b68-4fc8-9421-43fd24bd4dbe", + "concepts": ["felts"], + "prerequisites": ["functions"], + "status": "wip" + }, + { + "slug": "cars-assemble", + "name": "Cars Assemble", + "uuid": "57845c17-15e5-4c62-bbac-29ad633e9ebb", + "concepts": ["integers"], + "prerequisites": ["functions"], + "status": "wip" + }, + { + "slug": "welcome-to-tech-palace", + "name": "Welcome To Tech Palace!", + "uuid": "f8108950-9819-4540-8a3a-880d0778806c", + "concepts": ["strings"], + "prerequisites": ["functions"], + "status": "wip" + }, + { + "slug": "magician-in-training", + "name": "Magician in Training", + "uuid": "b1f29e1f-adb7-4e37-8101-a1819f1179fa", + "concepts": ["arrays"], + "prerequisites": ["integers"], + "status": "wip" + }, + { + "slug": "rpn-calculator", + "name": "RPN Calculator", + "uuid": "536d9f09-5910-4a26-93fd-2242667b0b87", + "concepts": ["control-flow"], + "prerequisites": ["arrays", "enums"], + "status": "wip" + }, + { + "slug": "gross-store", + "name": "Gross Store", + "uuid": "e2ae76c7-379e-430d-92d6-9eaaa823acca", + "concepts": ["dictionaries"], + "prerequisites": ["control-flow"], + "status": "wip" + }, + { + "slug": "election-day", + "name": "Election Day", + "uuid": "29bc1a4a-f295-44db-be19-d8e63dc526dc", + "concepts": ["ownership", "structs", "references-and-snapshots"], + "prerequisites": ["dictionaries"], + "status": "wip" + }, + { + "slug": "red-vs-blue-darwin-style", + "name": "Red vs. Blue: Darwin Style", + "uuid": "30761b1c-0c9a-4c91-8d16-1adf8bc4a0dd", + "concepts": ["packages-crates-modules"], + "prerequisites": ["structs"], + "status": "wip" + }, + { + "slug": "health-statistics", + "name": "Health Statistics", + "uuid": "69389197-e1dc-43bf-865d-d9b58d59b4e7", + "concepts": ["method-syntax"], + "prerequisites": ["structs", "references-and-snapshots"], + "status": "wip" + }, + { + "slug": "airport-robot", + "name": "Airport Robot", + "uuid": "f0c994d7-d183-4dfa-9048-b20be6f3bf2e", + "concepts": ["generics", "traits"], + "prerequisites": ["method-syntax"], + "status": "wip" + }, + { + "slug": "low-power-embedded-game", + "name": "Low-power Embedded Game", + "uuid": "f3b7ce44-1667-42b4-b792-401d36aee2f1", + "concepts": ["tuples"], + "prerequisites": ["traits"], + "status": "wip" + }, + { + "slug": "the-realm-of-echoes", + "name": "the-realm-of-echoes", + "uuid": "c8fd3bd0-290e-4472-b967-9a201dfd3041", + "concepts": ["printing"], + "prerequisites": ["traits"], + "status": "wip" + }, + { + "slug": "role-playing-game", + "name": "Role Playing Game", + "uuid": "1b014752-c3a4-4250-9483-89696864461b", + "concepts": ["option"], + "prerequisites": ["structs", "method-syntax"], + "status": "wip" + }, + { + "slug": "magical-measurements", + "name": "Magical Measurements", + "uuid": "590fc9b0-2b5d-4dab-81ca-b43f9987b1f5", + "concepts": ["type-conversion"], + "prerequisites": ["option", "printing"], + "status": "wip" + }, + { + "slug": "the-farm", + "name": "The Farm", + "uuid": "e167e30c-84b1-44da-b21c-70bc46688f20", + "concepts": ["error-handling"], + "prerequisites": ["structs"], + "status": "wip" + }, + { + "slug": "chrono-realms", + "name": "Chrono Realms", + "uuid": "eb15461a-ffdc-4bdd-acc1-e95bd7a1ac91", + "concepts": ["operator-overloading"], + "prerequisites": ["generics"], + "status": "wip" + }, + { + "slug": "chrono-realms-time-tree", + "name": "Chrono Realms Time Tree", + "uuid": "a72139a1-825e-4349-a6b5-400b665fbe07", + "concepts": ["smart-pointers"], + "prerequisites": ["structs"], + "status": "wip" } ], "practice": [ @@ -476,6 +612,110 @@ "prerequisites": [], "difficulty": 4 }, + { + "slug": "high-scores", + "name": "High Scores", + "uuid": "993e43d8-e31b-4dd5-a73d-f5e99b499207", + "practices": [], + "prerequisites": [], + "difficulty": 3 + }, + { + "slug": "sum-of-multiples", + "name": "Sum of Multiples", + "uuid": "60b963b1-5c4a-4eb5-8f8e-a5e1ba9faa2f", + "practices": [], + "prerequisites": [], + "difficulty": 1 + }, + { + "slug": "space-age", + "name": "Space Age", + "uuid": "2305b855-30e5-4a24-a1d2-abfc50db3394", + "practices": [], + "prerequisites": [], + "difficulty": 3 + }, + { + "slug": "series", + "name": "Series", + "uuid": "b7a0428f-af52-49a5-a768-65197b9dfaa9", + "practices": [], + "prerequisites": [], + "difficulty": 2 + }, + { + "slug": "minesweeper", + "name": "Minesweeper", + "uuid": "393d862e-2736-49e7-ad7a-cda819b897c9", + "practices": [], + "prerequisites": [], + "difficulty": 6 + }, + { + "slug": "kindergarten-garden", + "name": "Kindergarten Garden", + "uuid": "6e241be1-28ba-4658-a6de-a29f3471725d", + "practices": [], + "prerequisites": [], + "difficulty": 4 + }, + { + "slug": "luhn", + "name": "Luhn", + "uuid": "8b85fe9d-0964-453f-85d7-92acd2c81723", + "practices": [], + "prerequisites": [], + "difficulty": 5 + }, + { + "slug": "all-your-base", + "name": "All Your Base", + "uuid": "102e5a3f-c5bb-4b8a-acab-7bdbacec38fa", + "practices": [], + "prerequisites": [], + "difficulty": 4 + }, + { + "slug": "word-count", + "name": "Word Count", + "uuid": "5fded933-439a-4faa-bfb6-18ec7b7c8469", + "practices": [], + "prerequisites": [], + "difficulty": 4 + }, + { + "slug": "binary-search-tree", + "name": "Binary Search Tree", + "uuid": "97941277-12ff-474b-8a41-e89c065e0620", + "practices": [], + "prerequisites": [], + "difficulty": 6 + }, + { + "slug": "knapsack", + "name": "Knapsack", + "uuid": "ba9a3b81-aa52-4311-8e98-79d589b5091a", + "practices": [], + "prerequisites": [], + "difficulty": 4 + }, + { + "slug": "zipper", + "name": "Zipper", + "uuid": "61120275-6457-43ce-b40b-7e86a18b7f5b", + "practices": [], + "prerequisites": [], + "difficulty": 8 + }, + { + "slug": "word-search", + "name": "Word Search", + "uuid": "adbe715a-e54f-4e6d-9bb7-edef9e26b2cc", + "practices": [], + "prerequisites": [], + "difficulty": 6 + }, { "slug": "transpose", "name": "Transpose", @@ -483,12 +723,21 @@ "practices": [], "prerequisites": [], "difficulty": 1 + }, + { + "slug": "isbn-verifier", + "name": "ISBN Verifier", + "uuid": "84645a75-35f9-44ff-bb1b-c4d8237c43d7", + "practices": [], + "prerequisites": [], + "difficulty": 4 } ], "foregone": [ "bank-account", "complex-numbers", "gigasecond", + "grep", "hangman", "lens-person", "list-ops", @@ -572,6 +821,11 @@ "slug": "operator-overloading", "name": "Operator Overload" }, + { + "uuid": "0bd2a321-f169-49a9-83d6-7d91193db915", + "slug": "option", + "name": "Option" + }, { "uuid": "c11a8aa5-cda4-4d02-a477-3db3d3ca5acf", "slug": "ownership", From 8e6ff9570ed58e9c50b1c8751f0755094bb9fbd1 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Mon, 9 Dec 2024 14:30:08 +0100 Subject: [PATCH 49/63] resolve lost work --- config.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config.json b/config.json index 692680b9..95500fa5 100644 --- a/config.json +++ b/config.json @@ -723,6 +723,7 @@ "practices": [], "prerequisites": [], "difficulty": 1 +<<<<<<< HEAD }, { "slug": "isbn-verifier", @@ -731,6 +732,8 @@ "practices": [], "prerequisites": [], "difficulty": 4 +======= +>>>>>>> 9947334 (transpose exercise) } ], "foregone": [ From 068a20b5ef24cbb74fd9f28648348973a26d8ece Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Mon, 9 Dec 2024 15:08:39 +0100 Subject: [PATCH 50/63] resolve issues --- config.json | 283 ++++++++++++++---- .../sum-of-multiples/transpose/Scarb.lock | 6 - .../transpose/.docs/instructions.md | 0 .../transpose/.meta/config.json | 0 .../transpose/.meta/example.cairo | 0 .../transpose/.meta/tests.toml | 0 .../transpose/Scarb.toml | 0 .../transpose/src/lib.cairo | 0 .../transpose/tests/transpose.cairo | 0 9 files changed, 218 insertions(+), 71 deletions(-) delete mode 100644 exercises/practice/sum-of-multiples/transpose/Scarb.lock rename exercises/practice/{sum-of-multiples => }/transpose/.docs/instructions.md (100%) rename exercises/practice/{sum-of-multiples => }/transpose/.meta/config.json (100%) rename exercises/practice/{sum-of-multiples => }/transpose/.meta/example.cairo (100%) rename exercises/practice/{sum-of-multiples => }/transpose/.meta/tests.toml (100%) rename exercises/practice/{sum-of-multiples => }/transpose/Scarb.toml (100%) rename exercises/practice/{sum-of-multiples => }/transpose/src/lib.cairo (100%) rename exercises/practice/{sum-of-multiples => }/transpose/tests/transpose.cairo (100%) diff --git a/config.json b/config.json index 95500fa5..d1330712 100644 --- a/config.json +++ b/config.json @@ -19,11 +19,21 @@ "average_run_time": 5 }, "files": { - "solution": ["src/lib.cairo"], - "test": ["tests/%{snake_slug}.cairo"], - "example": [".meta/example.cairo"], - "exemplar": [".meta/exemplar.cairo"], - "invalidator": ["Scarb.toml"] + "solution": [ + "src/lib.cairo" + ], + "test": [ + "tests/%{snake_slug}.cairo" + ], + "example": [ + ".meta/example.cairo" + ], + "exemplar": [ + ".meta/exemplar.cairo" + ], + "invalidator": [ + "Scarb.toml" + ] }, "exercises": { "concept": [ @@ -31,15 +41,22 @@ "slug": "low-power-embedded-game", "name": "Low-power Embedded Game", "uuid": "f3b7ce44-1667-42b4-b792-401d36aee2f1", - "concepts": ["tuples"], - "prerequisites": ["traits"], + "concepts": [ + "tuples" + ], + "prerequisites": [ + "traits" + ], "status": "wip" }, { "slug": "lucians-luscious-lasagna", "name": "Lucian's Luscious Lasagna", "uuid": "f120ab92-f277-434c-ae38-a3bb86cb67bf", - "concepts": ["functions", "mutability"], + "concepts": [ + "functions", + "mutability" + ], "prerequisites": [], "status": "beta" }, @@ -47,144 +64,223 @@ "slug": "annalyns-infiltration", "name": "Annalyn's Infiltration", "uuid": "da0f8d71-36ed-4c98-9e43-60a04ea5db3a", - "concepts": ["booleans"], - "prerequisites": ["functions"], + "concepts": [ + "booleans" + ], + "prerequisites": [ + "functions" + ], "status": "wip" }, { "slug": "cryptographer", "name": "Cryptographer", "uuid": "7d399f77-4b68-4fc8-9421-43fd24bd4dbe", - "concepts": ["felts"], - "prerequisites": ["functions"], + "concepts": [ + "felts" + ], + "prerequisites": [ + "functions" + ], "status": "wip" }, { "slug": "cars-assemble", "name": "Cars Assemble", "uuid": "57845c17-15e5-4c62-bbac-29ad633e9ebb", - "concepts": ["integers"], - "prerequisites": ["functions"], + "concepts": [ + "integers" + ], + "prerequisites": [ + "functions" + ], "status": "wip" }, { "slug": "welcome-to-tech-palace", "name": "Welcome To Tech Palace!", "uuid": "f8108950-9819-4540-8a3a-880d0778806c", - "concepts": ["strings"], - "prerequisites": ["functions"], + "concepts": [ + "strings" + ], + "prerequisites": [ + "functions" + ], "status": "wip" }, { "slug": "magician-in-training", "name": "Magician in Training", "uuid": "b1f29e1f-adb7-4e37-8101-a1819f1179fa", - "concepts": ["arrays"], - "prerequisites": ["integers"], + "concepts": [ + "arrays" + ], + "prerequisites": [ + "integers" + ], "status": "wip" }, { "slug": "rpn-calculator", "name": "RPN Calculator", "uuid": "536d9f09-5910-4a26-93fd-2242667b0b87", - "concepts": ["control-flow"], - "prerequisites": ["arrays", "enums"], + "concepts": [ + "control-flow" + ], + "prerequisites": [ + "arrays", + "enums" + ], "status": "wip" }, { "slug": "gross-store", "name": "Gross Store", "uuid": "e2ae76c7-379e-430d-92d6-9eaaa823acca", - "concepts": ["dictionaries"], - "prerequisites": ["control-flow"], + "concepts": [ + "dictionaries" + ], + "prerequisites": [ + "control-flow" + ], "status": "wip" }, { "slug": "election-day", "name": "Election Day", "uuid": "29bc1a4a-f295-44db-be19-d8e63dc526dc", - "concepts": ["ownership", "structs", "references-and-snapshots"], - "prerequisites": ["dictionaries"], + "concepts": [ + "ownership", + "structs", + "references-and-snapshots" + ], + "prerequisites": [ + "dictionaries" + ], "status": "wip" }, { "slug": "red-vs-blue-darwin-style", "name": "Red vs. Blue: Darwin Style", "uuid": "30761b1c-0c9a-4c91-8d16-1adf8bc4a0dd", - "concepts": ["packages-crates-modules"], - "prerequisites": ["structs"], + "concepts": [ + "packages-crates-modules" + ], + "prerequisites": [ + "structs" + ], "status": "wip" }, { "slug": "health-statistics", "name": "Health Statistics", "uuid": "69389197-e1dc-43bf-865d-d9b58d59b4e7", - "concepts": ["method-syntax"], - "prerequisites": ["structs", "references-and-snapshots"], + "concepts": [ + "method-syntax" + ], + "prerequisites": [ + "structs", + "references-and-snapshots" + ], "status": "wip" }, { "slug": "airport-robot", "name": "Airport Robot", "uuid": "f0c994d7-d183-4dfa-9048-b20be6f3bf2e", - "concepts": ["generics", "traits"], - "prerequisites": ["method-syntax"], + "concepts": [ + "generics", + "traits" + ], + "prerequisites": [ + "method-syntax" + ], "status": "wip" }, { "slug": "low-power-embedded-game", "name": "Low-power Embedded Game", "uuid": "f3b7ce44-1667-42b4-b792-401d36aee2f1", - "concepts": ["tuples"], - "prerequisites": ["traits"], + "concepts": [ + "tuples" + ], + "prerequisites": [ + "traits" + ], "status": "wip" }, { "slug": "the-realm-of-echoes", "name": "the-realm-of-echoes", "uuid": "c8fd3bd0-290e-4472-b967-9a201dfd3041", - "concepts": ["printing"], - "prerequisites": ["traits"], + "concepts": [ + "printing" + ], + "prerequisites": [ + "traits" + ], "status": "wip" }, { "slug": "role-playing-game", "name": "Role Playing Game", "uuid": "1b014752-c3a4-4250-9483-89696864461b", - "concepts": ["option"], - "prerequisites": ["structs", "method-syntax"], + "concepts": [ + "option" + ], + "prerequisites": [ + "structs", + "method-syntax" + ], "status": "wip" }, { "slug": "magical-measurements", "name": "Magical Measurements", "uuid": "590fc9b0-2b5d-4dab-81ca-b43f9987b1f5", - "concepts": ["type-conversion"], - "prerequisites": ["option", "printing"], + "concepts": [ + "type-conversion" + ], + "prerequisites": [ + "option", + "printing" + ], "status": "wip" }, { "slug": "the-farm", "name": "The Farm", "uuid": "e167e30c-84b1-44da-b21c-70bc46688f20", - "concepts": ["error-handling"], - "prerequisites": ["structs"], + "concepts": [ + "error-handling" + ], + "prerequisites": [ + "structs" + ], "status": "wip" }, { "slug": "chrono-realms", "name": "Chrono Realms", "uuid": "eb15461a-ffdc-4bdd-acc1-e95bd7a1ac91", - "concepts": ["operator-overloading"], - "prerequisites": ["generics"], + "concepts": [ + "operator-overloading" + ], + "prerequisites": [ + "generics" + ], "status": "wip" }, { "slug": "chrono-realms-time-tree", "name": "Chrono Realms Time Tree", "uuid": "a72139a1-825e-4349-a6b5-400b665fbe07", - "concepts": ["smart-pointers"], - "prerequisites": ["structs"], + "concepts": [ + "smart-pointers" + ], + "prerequisites": [ + "structs" + ], "status": "wip" } ], @@ -193,7 +289,10 @@ "slug": "hello-world", "name": "Hello World", "uuid": "1a0e23d9-e8f9-493a-af46-2be040173b64", - "practices": ["strings", "felts"], + "practices": [ + "strings", + "felts" + ], "prerequisites": [], "difficulty": 1 }, @@ -201,7 +300,9 @@ "slug": "reverse-string", "name": "Reverse String", "uuid": "df9f3e80-acf5-41e0-9321-d4b13b26a036", - "practices": ["strings"], + "practices": [ + "strings" + ], "prerequisites": [], "difficulty": 1 }, @@ -249,7 +350,10 @@ "slug": "leap", "name": "Leap", "uuid": "9b586e17-928c-42bf-95ed-67539daea9a8", - "practices": ["booleans", "integers"], + "practices": [ + "booleans", + "integers" + ], "prerequisites": [], "difficulty": 2 }, @@ -257,7 +361,10 @@ "slug": "semi-structured-logs", "name": "Semi Structured Logs", "uuid": "4ca5087f-0128-4845-89a8-a2fa7791ed98", - "practices": ["enums", "match-basics"], + "practices": [ + "enums", + "match-basics" + ], "prerequisites": [], "difficulty": 2 }, @@ -265,7 +372,9 @@ "slug": "darts", "name": "Darts", "uuid": "3e5fb791-59b5-4ea6-b68f-70ed851a3308", - "practices": ["control-flow"], + "practices": [ + "control-flow" + ], "prerequisites": [], "difficulty": 2 }, @@ -329,7 +438,9 @@ "slug": "raindrops", "name": "Raindrops", "uuid": "d2cc23d5-2ed1-4115-9b9a-4b62993e750c", - "practices": ["strings"], + "practices": [ + "strings" + ], "prerequisites": [], "difficulty": 2 }, @@ -377,7 +488,9 @@ "slug": "armstrong-numbers", "name": "Armstrong Numbers", "uuid": "4aaa153d-3416-4101-8143-35b068a15451", - "practices": ["packages-crates-modules"], + "practices": [ + "packages-crates-modules" + ], "prerequisites": [], "difficulty": 3 }, @@ -385,7 +498,11 @@ "slug": "sublist", "name": "Sublist", "uuid": "e62b1bb4-fb37-4dfe-ad81-e0fa5c494ba3", - "practices": ["arrays", "enums", "generics"], + "practices": [ + "arrays", + "enums", + "generics" + ], "prerequisites": [], "difficulty": 3 }, @@ -393,7 +510,11 @@ "slug": "scrabble-score", "name": "Scrabble Score", "uuid": "3ef58f8c-99d4-48be-bb15-a1a5763e5052", - "practices": ["dictionaries", "strings", "felts"], + "practices": [ + "dictionaries", + "strings", + "felts" + ], "prerequisites": [], "difficulty": 3 }, @@ -417,7 +538,10 @@ "slug": "beer-song", "name": "Beer Song", "uuid": "d96a8ba2-6e80-45ce-91d6-5b4cac391db6", - "practices": ["control-flow", "strings"], + "practices": [ + "control-flow", + "strings" + ], "prerequisites": [], "difficulty": 3 }, @@ -425,7 +549,10 @@ "slug": "clock", "name": "Clock", "uuid": "b44728f6-f2ad-4fa4-a20e-5144f9a81e3e", - "practices": ["traits", "printing"], + "practices": [ + "traits", + "printing" + ], "prerequisites": [], "difficulty": 4 }, @@ -455,7 +582,12 @@ "slug": "binary-search", "name": "Binary Search", "uuid": "46be407d-13b8-4a7f-9a9a-4cef93485ba7", - "practices": ["arrays", "enums", "control-flow", "generics"], + "practices": [ + "arrays", + "enums", + "control-flow", + "generics" + ], "prerequisites": [], "difficulty": 4 }, @@ -463,7 +595,11 @@ "slug": "largest-series-product", "name": "Largest Series Product", "uuid": "d0cae4fa-22a8-4604-9f0f-f90751245ce3", - "practices": ["enums", "error-handling", "control-flow"], + "practices": [ + "enums", + "error-handling", + "control-flow" + ], "prerequisites": [], "difficulty": 4 }, @@ -471,7 +607,11 @@ "slug": "allergies", "name": "Allergies", "uuid": "ef701095-b324-49f0-913e-2fb2e1f5f27a", - "practices": ["enums", "structs", "traits"], + "practices": [ + "enums", + "structs", + "traits" + ], "prerequisites": [], "difficulty": 4 }, @@ -514,7 +654,12 @@ "slug": "custom-set", "name": "Custom Set", "uuid": "aad80498-750c-4a7d-b82a-f52f90c54e11", - "practices": ["structs", "generics", "traits", "operator-overloading"], + "practices": [ + "structs", + "generics", + "traits", + "operator-overloading" + ], "prerequisites": [], "difficulty": 6 }, @@ -536,7 +681,10 @@ "slug": "simple-linked-list", "name": "Simple Linked List", "uuid": "cc9a6bf9-9027-42c4-a71d-082ce48f7869", - "practices": ["smart-pointers", "generics"], + "practices": [ + "smart-pointers", + "generics" + ], "prerequisites": [], "difficulty": 7 }, @@ -544,7 +692,12 @@ "slug": "protein-translation", "name": "Protein Translation", "uuid": "d42e7a29-64b9-478b-8b2a-44fd002391fa", - "practices": ["dictionaries", "strings", "felts", "type-conversion"], + "practices": [ + "dictionaries", + "strings", + "felts", + "type-conversion" + ], "prerequisites": [], "difficulty": 8 }, @@ -560,7 +713,10 @@ "slug": "linked-list", "name": "Linked List", "uuid": "1924c44e-bfa2-4dac-a7a9-779e4039ac56", - "practices": ["structs", "traits"], + "practices": [ + "structs", + "traits" + ], "prerequisites": [], "difficulty": 10 }, @@ -723,7 +879,6 @@ "practices": [], "prerequisites": [], "difficulty": 1 -<<<<<<< HEAD }, { "slug": "isbn-verifier", @@ -732,8 +887,6 @@ "practices": [], "prerequisites": [], "difficulty": 4 -======= ->>>>>>> 9947334 (transpose exercise) } ], "foregone": [ diff --git a/exercises/practice/sum-of-multiples/transpose/Scarb.lock b/exercises/practice/sum-of-multiples/transpose/Scarb.lock deleted file mode 100644 index 8f584341..00000000 --- a/exercises/practice/sum-of-multiples/transpose/Scarb.lock +++ /dev/null @@ -1,6 +0,0 @@ -# Code generated by scarb DO NOT EDIT. -version = 1 - -[[package]] -name = "transpose" -version = "0.1.0" diff --git a/exercises/practice/sum-of-multiples/transpose/.docs/instructions.md b/exercises/practice/transpose/.docs/instructions.md similarity index 100% rename from exercises/practice/sum-of-multiples/transpose/.docs/instructions.md rename to exercises/practice/transpose/.docs/instructions.md diff --git a/exercises/practice/sum-of-multiples/transpose/.meta/config.json b/exercises/practice/transpose/.meta/config.json similarity index 100% rename from exercises/practice/sum-of-multiples/transpose/.meta/config.json rename to exercises/practice/transpose/.meta/config.json diff --git a/exercises/practice/sum-of-multiples/transpose/.meta/example.cairo b/exercises/practice/transpose/.meta/example.cairo similarity index 100% rename from exercises/practice/sum-of-multiples/transpose/.meta/example.cairo rename to exercises/practice/transpose/.meta/example.cairo diff --git a/exercises/practice/sum-of-multiples/transpose/.meta/tests.toml b/exercises/practice/transpose/.meta/tests.toml similarity index 100% rename from exercises/practice/sum-of-multiples/transpose/.meta/tests.toml rename to exercises/practice/transpose/.meta/tests.toml diff --git a/exercises/practice/sum-of-multiples/transpose/Scarb.toml b/exercises/practice/transpose/Scarb.toml similarity index 100% rename from exercises/practice/sum-of-multiples/transpose/Scarb.toml rename to exercises/practice/transpose/Scarb.toml diff --git a/exercises/practice/sum-of-multiples/transpose/src/lib.cairo b/exercises/practice/transpose/src/lib.cairo similarity index 100% rename from exercises/practice/sum-of-multiples/transpose/src/lib.cairo rename to exercises/practice/transpose/src/lib.cairo diff --git a/exercises/practice/sum-of-multiples/transpose/tests/transpose.cairo b/exercises/practice/transpose/tests/transpose.cairo similarity index 100% rename from exercises/practice/sum-of-multiples/transpose/tests/transpose.cairo rename to exercises/practice/transpose/tests/transpose.cairo From 1bc2263ebed73b0e15edba9d591371525dc40659 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Mon, 9 Dec 2024 15:11:00 +0100 Subject: [PATCH 51/63] resolve issues in config --- config.json | 284 +++++++++++----------------------------------------- 1 file changed, 60 insertions(+), 224 deletions(-) diff --git a/config.json b/config.json index d1330712..386e8f01 100644 --- a/config.json +++ b/config.json @@ -19,44 +19,19 @@ "average_run_time": 5 }, "files": { - "solution": [ - "src/lib.cairo" - ], - "test": [ - "tests/%{snake_slug}.cairo" - ], - "example": [ - ".meta/example.cairo" - ], - "exemplar": [ - ".meta/exemplar.cairo" - ], - "invalidator": [ - "Scarb.toml" - ] + "solution": ["src/lib.cairo"], + "test": ["tests/%{snake_slug}.cairo"], + "example": [".meta/example.cairo"], + "exemplar": [".meta/exemplar.cairo"], + "invalidator": ["Scarb.toml"] }, "exercises": { "concept": [ - { - "slug": "low-power-embedded-game", - "name": "Low-power Embedded Game", - "uuid": "f3b7ce44-1667-42b4-b792-401d36aee2f1", - "concepts": [ - "tuples" - ], - "prerequisites": [ - "traits" - ], - "status": "wip" - }, { "slug": "lucians-luscious-lasagna", "name": "Lucian's Luscious Lasagna", "uuid": "f120ab92-f277-434c-ae38-a3bb86cb67bf", - "concepts": [ - "functions", - "mutability" - ], + "concepts": ["functions", "mutability"], "prerequisites": [], "status": "beta" }, @@ -64,223 +39,144 @@ "slug": "annalyns-infiltration", "name": "Annalyn's Infiltration", "uuid": "da0f8d71-36ed-4c98-9e43-60a04ea5db3a", - "concepts": [ - "booleans" - ], - "prerequisites": [ - "functions" - ], + "concepts": ["booleans"], + "prerequisites": ["functions"], "status": "wip" }, { "slug": "cryptographer", "name": "Cryptographer", "uuid": "7d399f77-4b68-4fc8-9421-43fd24bd4dbe", - "concepts": [ - "felts" - ], - "prerequisites": [ - "functions" - ], + "concepts": ["felts"], + "prerequisites": ["functions"], "status": "wip" }, { "slug": "cars-assemble", "name": "Cars Assemble", "uuid": "57845c17-15e5-4c62-bbac-29ad633e9ebb", - "concepts": [ - "integers" - ], - "prerequisites": [ - "functions" - ], + "concepts": ["integers"], + "prerequisites": ["functions"], "status": "wip" }, { "slug": "welcome-to-tech-palace", "name": "Welcome To Tech Palace!", "uuid": "f8108950-9819-4540-8a3a-880d0778806c", - "concepts": [ - "strings" - ], - "prerequisites": [ - "functions" - ], + "concepts": ["strings"], + "prerequisites": ["functions"], "status": "wip" }, { "slug": "magician-in-training", "name": "Magician in Training", "uuid": "b1f29e1f-adb7-4e37-8101-a1819f1179fa", - "concepts": [ - "arrays" - ], - "prerequisites": [ - "integers" - ], + "concepts": ["arrays"], + "prerequisites": ["integers"], "status": "wip" }, { "slug": "rpn-calculator", "name": "RPN Calculator", "uuid": "536d9f09-5910-4a26-93fd-2242667b0b87", - "concepts": [ - "control-flow" - ], - "prerequisites": [ - "arrays", - "enums" - ], + "concepts": ["control-flow"], + "prerequisites": ["arrays", "enums"], "status": "wip" }, { "slug": "gross-store", "name": "Gross Store", "uuid": "e2ae76c7-379e-430d-92d6-9eaaa823acca", - "concepts": [ - "dictionaries" - ], - "prerequisites": [ - "control-flow" - ], + "concepts": ["dictionaries"], + "prerequisites": ["control-flow"], "status": "wip" }, { "slug": "election-day", "name": "Election Day", "uuid": "29bc1a4a-f295-44db-be19-d8e63dc526dc", - "concepts": [ - "ownership", - "structs", - "references-and-snapshots" - ], - "prerequisites": [ - "dictionaries" - ], + "concepts": ["ownership", "structs", "references-and-snapshots"], + "prerequisites": ["dictionaries"], "status": "wip" }, { "slug": "red-vs-blue-darwin-style", "name": "Red vs. Blue: Darwin Style", "uuid": "30761b1c-0c9a-4c91-8d16-1adf8bc4a0dd", - "concepts": [ - "packages-crates-modules" - ], - "prerequisites": [ - "structs" - ], + "concepts": ["packages-crates-modules"], + "prerequisites": ["structs"], "status": "wip" }, { "slug": "health-statistics", "name": "Health Statistics", "uuid": "69389197-e1dc-43bf-865d-d9b58d59b4e7", - "concepts": [ - "method-syntax" - ], - "prerequisites": [ - "structs", - "references-and-snapshots" - ], + "concepts": ["method-syntax"], + "prerequisites": ["structs", "references-and-snapshots"], "status": "wip" }, { "slug": "airport-robot", "name": "Airport Robot", "uuid": "f0c994d7-d183-4dfa-9048-b20be6f3bf2e", - "concepts": [ - "generics", - "traits" - ], - "prerequisites": [ - "method-syntax" - ], + "concepts": ["generics", "traits"], + "prerequisites": ["method-syntax"], "status": "wip" }, { "slug": "low-power-embedded-game", "name": "Low-power Embedded Game", "uuid": "f3b7ce44-1667-42b4-b792-401d36aee2f1", - "concepts": [ - "tuples" - ], - "prerequisites": [ - "traits" - ], + "concepts": ["tuples"], + "prerequisites": ["traits"], "status": "wip" }, { "slug": "the-realm-of-echoes", "name": "the-realm-of-echoes", "uuid": "c8fd3bd0-290e-4472-b967-9a201dfd3041", - "concepts": [ - "printing" - ], - "prerequisites": [ - "traits" - ], + "concepts": ["printing"], + "prerequisites": ["traits"], "status": "wip" }, { "slug": "role-playing-game", "name": "Role Playing Game", "uuid": "1b014752-c3a4-4250-9483-89696864461b", - "concepts": [ - "option" - ], - "prerequisites": [ - "structs", - "method-syntax" - ], + "concepts": ["option"], + "prerequisites": ["structs", "method-syntax"], "status": "wip" }, { "slug": "magical-measurements", "name": "Magical Measurements", "uuid": "590fc9b0-2b5d-4dab-81ca-b43f9987b1f5", - "concepts": [ - "type-conversion" - ], - "prerequisites": [ - "option", - "printing" - ], + "concepts": ["type-conversion"], + "prerequisites": ["option", "printing"], "status": "wip" }, { "slug": "the-farm", "name": "The Farm", "uuid": "e167e30c-84b1-44da-b21c-70bc46688f20", - "concepts": [ - "error-handling" - ], - "prerequisites": [ - "structs" - ], + "concepts": ["error-handling"], + "prerequisites": ["structs"], "status": "wip" }, { "slug": "chrono-realms", "name": "Chrono Realms", "uuid": "eb15461a-ffdc-4bdd-acc1-e95bd7a1ac91", - "concepts": [ - "operator-overloading" - ], - "prerequisites": [ - "generics" - ], + "concepts": ["operator-overloading"], + "prerequisites": ["generics"], "status": "wip" }, { "slug": "chrono-realms-time-tree", "name": "Chrono Realms Time Tree", "uuid": "a72139a1-825e-4349-a6b5-400b665fbe07", - "concepts": [ - "smart-pointers" - ], - "prerequisites": [ - "structs" - ], + "concepts": ["smart-pointers"], + "prerequisites": ["structs"], "status": "wip" } ], @@ -289,10 +185,7 @@ "slug": "hello-world", "name": "Hello World", "uuid": "1a0e23d9-e8f9-493a-af46-2be040173b64", - "practices": [ - "strings", - "felts" - ], + "practices": ["strings", "felts"], "prerequisites": [], "difficulty": 1 }, @@ -300,9 +193,7 @@ "slug": "reverse-string", "name": "Reverse String", "uuid": "df9f3e80-acf5-41e0-9321-d4b13b26a036", - "practices": [ - "strings" - ], + "practices": ["strings"], "prerequisites": [], "difficulty": 1 }, @@ -350,10 +241,7 @@ "slug": "leap", "name": "Leap", "uuid": "9b586e17-928c-42bf-95ed-67539daea9a8", - "practices": [ - "booleans", - "integers" - ], + "practices": ["booleans", "integers"], "prerequisites": [], "difficulty": 2 }, @@ -361,10 +249,7 @@ "slug": "semi-structured-logs", "name": "Semi Structured Logs", "uuid": "4ca5087f-0128-4845-89a8-a2fa7791ed98", - "practices": [ - "enums", - "match-basics" - ], + "practices": ["enums", "match-basics"], "prerequisites": [], "difficulty": 2 }, @@ -372,9 +257,7 @@ "slug": "darts", "name": "Darts", "uuid": "3e5fb791-59b5-4ea6-b68f-70ed851a3308", - "practices": [ - "control-flow" - ], + "practices": ["control-flow"], "prerequisites": [], "difficulty": 2 }, @@ -438,9 +321,7 @@ "slug": "raindrops", "name": "Raindrops", "uuid": "d2cc23d5-2ed1-4115-9b9a-4b62993e750c", - "practices": [ - "strings" - ], + "practices": ["strings"], "prerequisites": [], "difficulty": 2 }, @@ -488,9 +369,7 @@ "slug": "armstrong-numbers", "name": "Armstrong Numbers", "uuid": "4aaa153d-3416-4101-8143-35b068a15451", - "practices": [ - "packages-crates-modules" - ], + "practices": ["packages-crates-modules"], "prerequisites": [], "difficulty": 3 }, @@ -498,11 +377,7 @@ "slug": "sublist", "name": "Sublist", "uuid": "e62b1bb4-fb37-4dfe-ad81-e0fa5c494ba3", - "practices": [ - "arrays", - "enums", - "generics" - ], + "practices": ["arrays", "enums", "generics"], "prerequisites": [], "difficulty": 3 }, @@ -510,11 +385,7 @@ "slug": "scrabble-score", "name": "Scrabble Score", "uuid": "3ef58f8c-99d4-48be-bb15-a1a5763e5052", - "practices": [ - "dictionaries", - "strings", - "felts" - ], + "practices": ["dictionaries", "strings", "felts"], "prerequisites": [], "difficulty": 3 }, @@ -538,10 +409,7 @@ "slug": "beer-song", "name": "Beer Song", "uuid": "d96a8ba2-6e80-45ce-91d6-5b4cac391db6", - "practices": [ - "control-flow", - "strings" - ], + "practices": ["control-flow", "strings"], "prerequisites": [], "difficulty": 3 }, @@ -549,10 +417,7 @@ "slug": "clock", "name": "Clock", "uuid": "b44728f6-f2ad-4fa4-a20e-5144f9a81e3e", - "practices": [ - "traits", - "printing" - ], + "practices": ["traits", "printing"], "prerequisites": [], "difficulty": 4 }, @@ -582,12 +447,7 @@ "slug": "binary-search", "name": "Binary Search", "uuid": "46be407d-13b8-4a7f-9a9a-4cef93485ba7", - "practices": [ - "arrays", - "enums", - "control-flow", - "generics" - ], + "practices": ["arrays", "enums", "control-flow", "generics"], "prerequisites": [], "difficulty": 4 }, @@ -595,11 +455,7 @@ "slug": "largest-series-product", "name": "Largest Series Product", "uuid": "d0cae4fa-22a8-4604-9f0f-f90751245ce3", - "practices": [ - "enums", - "error-handling", - "control-flow" - ], + "practices": ["enums", "error-handling", "control-flow"], "prerequisites": [], "difficulty": 4 }, @@ -607,11 +463,7 @@ "slug": "allergies", "name": "Allergies", "uuid": "ef701095-b324-49f0-913e-2fb2e1f5f27a", - "practices": [ - "enums", - "structs", - "traits" - ], + "practices": ["enums", "structs", "traits"], "prerequisites": [], "difficulty": 4 }, @@ -654,12 +506,7 @@ "slug": "custom-set", "name": "Custom Set", "uuid": "aad80498-750c-4a7d-b82a-f52f90c54e11", - "practices": [ - "structs", - "generics", - "traits", - "operator-overloading" - ], + "practices": ["structs", "generics", "traits", "operator-overloading"], "prerequisites": [], "difficulty": 6 }, @@ -681,10 +528,7 @@ "slug": "simple-linked-list", "name": "Simple Linked List", "uuid": "cc9a6bf9-9027-42c4-a71d-082ce48f7869", - "practices": [ - "smart-pointers", - "generics" - ], + "practices": ["smart-pointers", "generics"], "prerequisites": [], "difficulty": 7 }, @@ -692,12 +536,7 @@ "slug": "protein-translation", "name": "Protein Translation", "uuid": "d42e7a29-64b9-478b-8b2a-44fd002391fa", - "practices": [ - "dictionaries", - "strings", - "felts", - "type-conversion" - ], + "practices": ["dictionaries", "strings", "felts", "type-conversion"], "prerequisites": [], "difficulty": 8 }, @@ -713,10 +552,7 @@ "slug": "linked-list", "name": "Linked List", "uuid": "1924c44e-bfa2-4dac-a7a9-779e4039ac56", - "practices": [ - "structs", - "traits" - ], + "practices": ["structs", "traits"], "prerequisites": [], "difficulty": 10 }, From 3c90f2dc8c53425a39750f86c63cc2a21adb4278 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Mon, 9 Dec 2024 15:31:13 +0100 Subject: [PATCH 52/63] format config --- config.json | 272 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 212 insertions(+), 60 deletions(-) diff --git a/config.json b/config.json index 386e8f01..73ccb357 100644 --- a/config.json +++ b/config.json @@ -19,11 +19,21 @@ "average_run_time": 5 }, "files": { - "solution": ["src/lib.cairo"], - "test": ["tests/%{snake_slug}.cairo"], - "example": [".meta/example.cairo"], - "exemplar": [".meta/exemplar.cairo"], - "invalidator": ["Scarb.toml"] + "solution": [ + "src/lib.cairo" + ], + "test": [ + "tests/%{snake_slug}.cairo" + ], + "example": [ + ".meta/example.cairo" + ], + "exemplar": [ + ".meta/exemplar.cairo" + ], + "invalidator": [ + "Scarb.toml" + ] }, "exercises": { "concept": [ @@ -31,7 +41,10 @@ "slug": "lucians-luscious-lasagna", "name": "Lucian's Luscious Lasagna", "uuid": "f120ab92-f277-434c-ae38-a3bb86cb67bf", - "concepts": ["functions", "mutability"], + "concepts": [ + "functions", + "mutability" + ], "prerequisites": [], "status": "beta" }, @@ -39,144 +52,223 @@ "slug": "annalyns-infiltration", "name": "Annalyn's Infiltration", "uuid": "da0f8d71-36ed-4c98-9e43-60a04ea5db3a", - "concepts": ["booleans"], - "prerequisites": ["functions"], + "concepts": [ + "booleans" + ], + "prerequisites": [ + "functions" + ], "status": "wip" }, { "slug": "cryptographer", "name": "Cryptographer", "uuid": "7d399f77-4b68-4fc8-9421-43fd24bd4dbe", - "concepts": ["felts"], - "prerequisites": ["functions"], + "concepts": [ + "felts" + ], + "prerequisites": [ + "functions" + ], "status": "wip" }, { "slug": "cars-assemble", "name": "Cars Assemble", "uuid": "57845c17-15e5-4c62-bbac-29ad633e9ebb", - "concepts": ["integers"], - "prerequisites": ["functions"], + "concepts": [ + "integers" + ], + "prerequisites": [ + "functions" + ], "status": "wip" }, { "slug": "welcome-to-tech-palace", "name": "Welcome To Tech Palace!", "uuid": "f8108950-9819-4540-8a3a-880d0778806c", - "concepts": ["strings"], - "prerequisites": ["functions"], + "concepts": [ + "strings" + ], + "prerequisites": [ + "functions" + ], "status": "wip" }, { "slug": "magician-in-training", "name": "Magician in Training", "uuid": "b1f29e1f-adb7-4e37-8101-a1819f1179fa", - "concepts": ["arrays"], - "prerequisites": ["integers"], + "concepts": [ + "arrays" + ], + "prerequisites": [ + "integers" + ], "status": "wip" }, { "slug": "rpn-calculator", "name": "RPN Calculator", "uuid": "536d9f09-5910-4a26-93fd-2242667b0b87", - "concepts": ["control-flow"], - "prerequisites": ["arrays", "enums"], + "concepts": [ + "control-flow" + ], + "prerequisites": [ + "arrays", + "enums" + ], "status": "wip" }, { "slug": "gross-store", "name": "Gross Store", "uuid": "e2ae76c7-379e-430d-92d6-9eaaa823acca", - "concepts": ["dictionaries"], - "prerequisites": ["control-flow"], + "concepts": [ + "dictionaries" + ], + "prerequisites": [ + "control-flow" + ], "status": "wip" }, { "slug": "election-day", "name": "Election Day", "uuid": "29bc1a4a-f295-44db-be19-d8e63dc526dc", - "concepts": ["ownership", "structs", "references-and-snapshots"], - "prerequisites": ["dictionaries"], + "concepts": [ + "ownership", + "structs", + "references-and-snapshots" + ], + "prerequisites": [ + "dictionaries" + ], "status": "wip" }, { "slug": "red-vs-blue-darwin-style", "name": "Red vs. Blue: Darwin Style", "uuid": "30761b1c-0c9a-4c91-8d16-1adf8bc4a0dd", - "concepts": ["packages-crates-modules"], - "prerequisites": ["structs"], + "concepts": [ + "packages-crates-modules" + ], + "prerequisites": [ + "structs" + ], "status": "wip" }, { "slug": "health-statistics", "name": "Health Statistics", "uuid": "69389197-e1dc-43bf-865d-d9b58d59b4e7", - "concepts": ["method-syntax"], - "prerequisites": ["structs", "references-and-snapshots"], + "concepts": [ + "method-syntax" + ], + "prerequisites": [ + "structs", + "references-and-snapshots" + ], "status": "wip" }, { "slug": "airport-robot", "name": "Airport Robot", "uuid": "f0c994d7-d183-4dfa-9048-b20be6f3bf2e", - "concepts": ["generics", "traits"], - "prerequisites": ["method-syntax"], + "concepts": [ + "generics", + "traits" + ], + "prerequisites": [ + "method-syntax" + ], "status": "wip" }, { "slug": "low-power-embedded-game", "name": "Low-power Embedded Game", "uuid": "f3b7ce44-1667-42b4-b792-401d36aee2f1", - "concepts": ["tuples"], - "prerequisites": ["traits"], + "concepts": [ + "tuples" + ], + "prerequisites": [ + "traits" + ], "status": "wip" }, { "slug": "the-realm-of-echoes", "name": "the-realm-of-echoes", "uuid": "c8fd3bd0-290e-4472-b967-9a201dfd3041", - "concepts": ["printing"], - "prerequisites": ["traits"], + "concepts": [ + "printing" + ], + "prerequisites": [ + "traits" + ], "status": "wip" }, { "slug": "role-playing-game", "name": "Role Playing Game", "uuid": "1b014752-c3a4-4250-9483-89696864461b", - "concepts": ["option"], - "prerequisites": ["structs", "method-syntax"], + "concepts": [ + "option" + ], + "prerequisites": [ + "structs", + "method-syntax" + ], "status": "wip" }, { "slug": "magical-measurements", "name": "Magical Measurements", "uuid": "590fc9b0-2b5d-4dab-81ca-b43f9987b1f5", - "concepts": ["type-conversion"], - "prerequisites": ["option", "printing"], + "concepts": [ + "type-conversion" + ], + "prerequisites": [ + "option", + "printing" + ], "status": "wip" }, { "slug": "the-farm", "name": "The Farm", "uuid": "e167e30c-84b1-44da-b21c-70bc46688f20", - "concepts": ["error-handling"], - "prerequisites": ["structs"], + "concepts": [ + "error-handling" + ], + "prerequisites": [ + "structs" + ], "status": "wip" }, { "slug": "chrono-realms", "name": "Chrono Realms", "uuid": "eb15461a-ffdc-4bdd-acc1-e95bd7a1ac91", - "concepts": ["operator-overloading"], - "prerequisites": ["generics"], + "concepts": [ + "operator-overloading" + ], + "prerequisites": [ + "generics" + ], "status": "wip" }, { "slug": "chrono-realms-time-tree", "name": "Chrono Realms Time Tree", "uuid": "a72139a1-825e-4349-a6b5-400b665fbe07", - "concepts": ["smart-pointers"], - "prerequisites": ["structs"], + "concepts": [ + "smart-pointers" + ], + "prerequisites": [ + "structs" + ], "status": "wip" } ], @@ -185,7 +277,10 @@ "slug": "hello-world", "name": "Hello World", "uuid": "1a0e23d9-e8f9-493a-af46-2be040173b64", - "practices": ["strings", "felts"], + "practices": [ + "strings", + "felts" + ], "prerequisites": [], "difficulty": 1 }, @@ -193,7 +288,9 @@ "slug": "reverse-string", "name": "Reverse String", "uuid": "df9f3e80-acf5-41e0-9321-d4b13b26a036", - "practices": ["strings"], + "practices": [ + "strings" + ], "prerequisites": [], "difficulty": 1 }, @@ -241,7 +338,10 @@ "slug": "leap", "name": "Leap", "uuid": "9b586e17-928c-42bf-95ed-67539daea9a8", - "practices": ["booleans", "integers"], + "practices": [ + "booleans", + "integers" + ], "prerequisites": [], "difficulty": 2 }, @@ -249,7 +349,10 @@ "slug": "semi-structured-logs", "name": "Semi Structured Logs", "uuid": "4ca5087f-0128-4845-89a8-a2fa7791ed98", - "practices": ["enums", "match-basics"], + "practices": [ + "enums", + "match-basics" + ], "prerequisites": [], "difficulty": 2 }, @@ -257,7 +360,9 @@ "slug": "darts", "name": "Darts", "uuid": "3e5fb791-59b5-4ea6-b68f-70ed851a3308", - "practices": ["control-flow"], + "practices": [ + "control-flow" + ], "prerequisites": [], "difficulty": 2 }, @@ -321,7 +426,9 @@ "slug": "raindrops", "name": "Raindrops", "uuid": "d2cc23d5-2ed1-4115-9b9a-4b62993e750c", - "practices": ["strings"], + "practices": [ + "strings" + ], "prerequisites": [], "difficulty": 2 }, @@ -369,7 +476,9 @@ "slug": "armstrong-numbers", "name": "Armstrong Numbers", "uuid": "4aaa153d-3416-4101-8143-35b068a15451", - "practices": ["packages-crates-modules"], + "practices": [ + "packages-crates-modules" + ], "prerequisites": [], "difficulty": 3 }, @@ -377,7 +486,11 @@ "slug": "sublist", "name": "Sublist", "uuid": "e62b1bb4-fb37-4dfe-ad81-e0fa5c494ba3", - "practices": ["arrays", "enums", "generics"], + "practices": [ + "arrays", + "enums", + "generics" + ], "prerequisites": [], "difficulty": 3 }, @@ -385,7 +498,11 @@ "slug": "scrabble-score", "name": "Scrabble Score", "uuid": "3ef58f8c-99d4-48be-bb15-a1a5763e5052", - "practices": ["dictionaries", "strings", "felts"], + "practices": [ + "dictionaries", + "strings", + "felts" + ], "prerequisites": [], "difficulty": 3 }, @@ -409,7 +526,10 @@ "slug": "beer-song", "name": "Beer Song", "uuid": "d96a8ba2-6e80-45ce-91d6-5b4cac391db6", - "practices": ["control-flow", "strings"], + "practices": [ + "control-flow", + "strings" + ], "prerequisites": [], "difficulty": 3 }, @@ -417,7 +537,10 @@ "slug": "clock", "name": "Clock", "uuid": "b44728f6-f2ad-4fa4-a20e-5144f9a81e3e", - "practices": ["traits", "printing"], + "practices": [ + "traits", + "printing" + ], "prerequisites": [], "difficulty": 4 }, @@ -447,7 +570,12 @@ "slug": "binary-search", "name": "Binary Search", "uuid": "46be407d-13b8-4a7f-9a9a-4cef93485ba7", - "practices": ["arrays", "enums", "control-flow", "generics"], + "practices": [ + "arrays", + "enums", + "control-flow", + "generics" + ], "prerequisites": [], "difficulty": 4 }, @@ -455,7 +583,11 @@ "slug": "largest-series-product", "name": "Largest Series Product", "uuid": "d0cae4fa-22a8-4604-9f0f-f90751245ce3", - "practices": ["enums", "error-handling", "control-flow"], + "practices": [ + "enums", + "error-handling", + "control-flow" + ], "prerequisites": [], "difficulty": 4 }, @@ -463,7 +595,11 @@ "slug": "allergies", "name": "Allergies", "uuid": "ef701095-b324-49f0-913e-2fb2e1f5f27a", - "practices": ["enums", "structs", "traits"], + "practices": [ + "enums", + "structs", + "traits" + ], "prerequisites": [], "difficulty": 4 }, @@ -506,7 +642,12 @@ "slug": "custom-set", "name": "Custom Set", "uuid": "aad80498-750c-4a7d-b82a-f52f90c54e11", - "practices": ["structs", "generics", "traits", "operator-overloading"], + "practices": [ + "structs", + "generics", + "traits", + "operator-overloading" + ], "prerequisites": [], "difficulty": 6 }, @@ -528,7 +669,10 @@ "slug": "simple-linked-list", "name": "Simple Linked List", "uuid": "cc9a6bf9-9027-42c4-a71d-082ce48f7869", - "practices": ["smart-pointers", "generics"], + "practices": [ + "smart-pointers", + "generics" + ], "prerequisites": [], "difficulty": 7 }, @@ -536,7 +680,12 @@ "slug": "protein-translation", "name": "Protein Translation", "uuid": "d42e7a29-64b9-478b-8b2a-44fd002391fa", - "practices": ["dictionaries", "strings", "felts", "type-conversion"], + "practices": [ + "dictionaries", + "strings", + "felts", + "type-conversion" + ], "prerequisites": [], "difficulty": 8 }, @@ -552,7 +701,10 @@ "slug": "linked-list", "name": "Linked List", "uuid": "1924c44e-bfa2-4dac-a7a9-779e4039ac56", - "practices": ["structs", "traits"], + "practices": [ + "structs", + "traits" + ], "prerequisites": [], "difficulty": 10 }, From 0df06b23a8cae7d773031756acbff04793b5e829 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Mon, 9 Dec 2024 15:51:33 +0100 Subject: [PATCH 53/63] make test passes --- .../practice/transpose/tests/transpose.cairo | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/exercises/practice/transpose/tests/transpose.cairo b/exercises/practice/transpose/tests/transpose.cairo index 49b135bd..e5d07532 100644 --- a/exercises/practice/transpose/tests/transpose.cairo +++ b/exercises/practice/transpose/tests/transpose.cairo @@ -1,11 +1,11 @@ -use transpose::transpose; +use transpose::transpose as transpose_matrix; #[test] fn empty_string() { let mut input: Array = array![]; let expected = array![]; - let output = transpose(input); + let output = transpose_matrix(input); assert_eq!(output, expected); } @@ -15,7 +15,7 @@ fn two_characters_in_a_row() { let mut input: Array = array!["A1"]; let expected = array!["A", "1"]; - let output = transpose(input); + let output = transpose_matrix(input); assert_eq!(output, expected); } @@ -25,7 +25,7 @@ fn two_characters_in_a_column() { let mut input: Array = array!["A", "1"]; let expected = array!["A1"]; - let output = transpose(input); + let output = transpose_matrix(input); assert_eq!(output, expected); } @@ -35,7 +35,7 @@ fn simple() { let mut input: Array = array!["ABC", "123"]; let expected = array!["A1", "B2", "C3"]; - let output = transpose(input); + let output = transpose_matrix(input); assert_eq!(output, expected); } @@ -45,7 +45,7 @@ fn single_line() { let mut input: Array = array!["Single line."]; let expected = array!["S", "i", "n", "g", "l", "e", " ", "l", "i", "n", "e", "."]; - let output = transpose(input); + let output = transpose_matrix(input); assert_eq!(output, expected); } @@ -72,7 +72,7 @@ fn first_line_longer_than_second_line() { ". " ]; - let output = transpose(input); + let output = transpose_matrix(input); assert_eq!(output, expected); } @@ -99,7 +99,7 @@ fn second_line_longer_than_first_line() { " ." ]; - let output = transpose(input); + let output = transpose_matrix(input); assert_eq!(output, expected); } @@ -129,7 +129,7 @@ fn mixed_line_length() { ". " ]; - let output = transpose(input); + let output = transpose_matrix(input); assert_eq!(output, expected); } @@ -139,7 +139,7 @@ fn square() { let mut input: Array = array!["HEART", "EMBER", "ABUSE", "RESIN", "TREND"]; let expected = array!["HEART", "EMBER", "ABUSE", "RESIN", "TREND"]; - let output = transpose(input); + let output = transpose_matrix(input); assert_eq!(output, expected); } @@ -149,7 +149,7 @@ fn rectangle() { let mut input: Array = array!["FRACTURE", "OUTLINED", "BLOOMING", "SEPTETTE"]; let expected = array!["FOBS", "RULE", "ATOP", "CLOT", "TIME", "UNIT", "RENT", "EDGE"]; - let output = transpose(input); + let output = transpose_matrix(input); assert_eq!(output, expected); } @@ -159,7 +159,7 @@ fn triangle() { let mut input: Array = array!["T", "EE", "AAA", "SSSS", "EEEEE", "RRRRRR"]; let expected = array!["TEASER", " EASER", " ASER", " SER", " ER", " R"]; - let output = transpose(input); + let output = transpose_matrix(input); assert_eq!(output, expected); } @@ -169,6 +169,6 @@ fn jagged_triangle() { let mut input: Array = array!["11", "2", "3333", "444", "555555", "66666"]; let expected = array!["123456", "1 3456", " 3456", " 3 56", " 56", " 5 "]; - let output = transpose(input); + let output = transpose_matrix(input); assert_eq!(output, expected); } From 1f63916ff89685be8cb6e9dd7d16fb9c7c56ba34 Mon Sep 17 00:00:00 2001 From: Ephraim-nonso Date: Mon, 9 Dec 2024 15:51:33 +0100 Subject: [PATCH 54/63] make test passes --- .../practice/transpose/tests/transpose.cairo | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/exercises/practice/transpose/tests/transpose.cairo b/exercises/practice/transpose/tests/transpose.cairo index 49b135bd..e5d07532 100644 --- a/exercises/practice/transpose/tests/transpose.cairo +++ b/exercises/practice/transpose/tests/transpose.cairo @@ -1,11 +1,11 @@ -use transpose::transpose; +use transpose::transpose as transpose_matrix; #[test] fn empty_string() { let mut input: Array = array![]; let expected = array![]; - let output = transpose(input); + let output = transpose_matrix(input); assert_eq!(output, expected); } @@ -15,7 +15,7 @@ fn two_characters_in_a_row() { let mut input: Array = array!["A1"]; let expected = array!["A", "1"]; - let output = transpose(input); + let output = transpose_matrix(input); assert_eq!(output, expected); } @@ -25,7 +25,7 @@ fn two_characters_in_a_column() { let mut input: Array = array!["A", "1"]; let expected = array!["A1"]; - let output = transpose(input); + let output = transpose_matrix(input); assert_eq!(output, expected); } @@ -35,7 +35,7 @@ fn simple() { let mut input: Array = array!["ABC", "123"]; let expected = array!["A1", "B2", "C3"]; - let output = transpose(input); + let output = transpose_matrix(input); assert_eq!(output, expected); } @@ -45,7 +45,7 @@ fn single_line() { let mut input: Array = array!["Single line."]; let expected = array!["S", "i", "n", "g", "l", "e", " ", "l", "i", "n", "e", "."]; - let output = transpose(input); + let output = transpose_matrix(input); assert_eq!(output, expected); } @@ -72,7 +72,7 @@ fn first_line_longer_than_second_line() { ". " ]; - let output = transpose(input); + let output = transpose_matrix(input); assert_eq!(output, expected); } @@ -99,7 +99,7 @@ fn second_line_longer_than_first_line() { " ." ]; - let output = transpose(input); + let output = transpose_matrix(input); assert_eq!(output, expected); } @@ -129,7 +129,7 @@ fn mixed_line_length() { ". " ]; - let output = transpose(input); + let output = transpose_matrix(input); assert_eq!(output, expected); } @@ -139,7 +139,7 @@ fn square() { let mut input: Array = array!["HEART", "EMBER", "ABUSE", "RESIN", "TREND"]; let expected = array!["HEART", "EMBER", "ABUSE", "RESIN", "TREND"]; - let output = transpose(input); + let output = transpose_matrix(input); assert_eq!(output, expected); } @@ -149,7 +149,7 @@ fn rectangle() { let mut input: Array = array!["FRACTURE", "OUTLINED", "BLOOMING", "SEPTETTE"]; let expected = array!["FOBS", "RULE", "ATOP", "CLOT", "TIME", "UNIT", "RENT", "EDGE"]; - let output = transpose(input); + let output = transpose_matrix(input); assert_eq!(output, expected); } @@ -159,7 +159,7 @@ fn triangle() { let mut input: Array = array!["T", "EE", "AAA", "SSSS", "EEEEE", "RRRRRR"]; let expected = array!["TEASER", " EASER", " ASER", " SER", " ER", " R"]; - let output = transpose(input); + let output = transpose_matrix(input); assert_eq!(output, expected); } @@ -169,6 +169,6 @@ fn jagged_triangle() { let mut input: Array = array!["11", "2", "3333", "444", "555555", "66666"]; let expected = array!["123456", "1 3456", " 3456", " 3 56", " 56", " 5 "]; - let output = transpose(input); + let output = transpose_matrix(input); assert_eq!(output, expected); } From 13dfe9436c07682a3ba5f262939e2dec3398e521 Mon Sep 17 00:00:00 2001 From: Nenad Date: Mon, 16 Dec 2024 19:21:46 +0100 Subject: [PATCH 55/63] Sync scarb version --- exercises/practice/transpose/Scarb.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/transpose/Scarb.toml b/exercises/practice/transpose/Scarb.toml index cb6b661c..2f6d0627 100644 --- a/exercises/practice/transpose/Scarb.toml +++ b/exercises/practice/transpose/Scarb.toml @@ -4,4 +4,4 @@ version = "0.1.0" edition = "2024_07" [dev-dependencies] -cairo_test = "2.8.2" +cairo_test = "2.9.2" From 1551365d41fea1db5feba567c7a2902117a1ce6d Mon Sep 17 00:00:00 2001 From: Ephraim Chukwu Date: Fri, 20 Dec 2024 12:32:58 +0100 Subject: [PATCH 56/63] Delete exercises/practice/word-count/tests/word_count.cairo --- .../word-count/tests/word_count.cairo | 254 ------------------ 1 file changed, 254 deletions(-) delete mode 100644 exercises/practice/word-count/tests/word_count.cairo diff --git a/exercises/practice/word-count/tests/word_count.cairo b/exercises/practice/word-count/tests/word_count.cairo deleted file mode 100644 index 920a19bd..00000000 --- a/exercises/practice/word-count/tests/word_count.cairo +++ /dev/null @@ -1,254 +0,0 @@ -use word_count::{count_words, WordResult}; - -#[test] -fn count_one_word() { - let input = "word"; - let mut output = count_words(input); - - let expected = array![WordResult { word: "word", count: 1 }].span(); - assert_unordered_eq(output, expected); -} - -#[test] -#[ignore] -fn count_one_of_each_word() { - let input = "one of each"; - let mut output = count_words(input); - - let expected = array![ - WordResult { word: "of", count: 1 }, - WordResult { word: "each", count: 1 }, - WordResult { word: "one", count: 1 } - ] - .span(); - assert_unordered_eq(output, expected); -} - -#[test] -#[ignore] -fn multiple_occurrences_of_a_word() { - let input = "one fish two fish red fish blue fish"; - let mut output = count_words(input); - - let expected = array![ - WordResult { word: "one", count: 1 }, - WordResult { word: "two", count: 1 }, - WordResult { word: "red", count: 1 }, - WordResult { word: "blue", count: 1 }, - WordResult { word: "fish", count: 4 } - ] - .span(); - assert_unordered_eq(output, expected); -} - -#[test] -#[ignore] -fn handles_cramped_lists() { - let input = "one,two,three"; - let mut output = count_words(input); - - let expected = array![ - WordResult { word: "one", count: 1 }, - WordResult { word: "two", count: 1 }, - WordResult { word: "three", count: 1 } - ] - .span(); - assert_unordered_eq(output, expected); -} - -#[test] -#[ignore] -fn handles_expanded_lists() { - let input = "one,\ntwo,\nthree"; - let mut output = count_words(input); - - let expected = array![ - WordResult { word: "one", count: 1 }, - WordResult { word: "two", count: 1 }, - WordResult { word: "three", count: 1 } - ] - .span(); - assert_unordered_eq(output, expected); -} - -#[test] -#[ignore] -fn ignore_punctuation() { - let input = "car: carpet as java: javascript!!&@$%^&"; - let mut output = count_words(input); - - let expected = array![ - WordResult { word: "car", count: 1 }, - WordResult { word: "carpet", count: 1 }, - WordResult { word: "as", count: 1 }, - WordResult { word: "java", count: 1 }, - WordResult { word: "javascript", count: 1 } - ] - .span(); - assert_unordered_eq(output, expected); -} - -#[test] -#[ignore] -fn include_numbers() { - let input = "testing, 1, 2 testing"; - let mut output = count_words(input); - - let expected = array![ - WordResult { word: "testing", count: 2 }, - WordResult { word: "1", count: 1 }, - WordResult { word: "2", count: 1 }, - ] - .span(); - - assert_unordered_eq(output, expected); -} - -#[test] -#[ignore] -fn normalize_case() { - let input = "go Go GO Stop stop"; - let mut output = count_words(input); - - let expected = array![ - WordResult { word: "go", count: 3 }, WordResult { word: "stop", count: 2 } - ] - .span(); - assert_unordered_eq(output, expected); -} - -#[test] -#[ignore] -fn with_apostrophes() { - let input = "'First: don't laugh. Then: don't cry. You're getting it.'"; - let mut output = count_words(input); - - let expected = array![ - WordResult { word: "first", count: 1 }, - WordResult { word: "laugh", count: 1 }, - WordResult { word: "then", count: 1 }, - WordResult { word: "don't", count: 2 }, - WordResult { word: "cry", count: 1 }, - WordResult { word: "you're", count: 1 }, - WordResult { word: "getting", count: 1 }, - WordResult { word: "it", count: 1 }, - ] - .span(); - assert_unordered_eq(output, expected); -} - -#[test] -#[ignore] -fn with_quotations() { - let input = "Joe can't tell between 'large' and large."; - let mut output = count_words(input); - - let expected = array![ - WordResult { word: "joe", count: 1 }, - WordResult { word: "can't", count: 1 }, - WordResult { word: "tell", count: 1 }, - WordResult { word: "between", count: 1 }, - WordResult { word: "and", count: 1 }, - WordResult { word: "large", count: 2 } - ] - .span(); - assert_unordered_eq(output, expected); -} - -#[test] -#[ignore] -fn substrings_from_the_beginning() { - let input = "Joe can't tell between app, apple and a."; - let mut output = count_words(input); - - let expected = array![ - WordResult { word: "joe", count: 1 }, - WordResult { word: "can't", count: 1 }, - WordResult { word: "tell", count: 1 }, - WordResult { word: "between", count: 1 }, - WordResult { word: "app", count: 1 }, - WordResult { word: "apple", count: 1 }, - WordResult { word: "and", count: 1 }, - WordResult { word: "a", count: 1 } - ] - .span(); - assert_unordered_eq(output, expected); -} - -#[test] -#[ignore] -fn multiple_spaces_not_detected_as_a_word() { - let input = " multiple whitespaces"; - let mut output = count_words(input); - - let expected = array![ - WordResult { word: "multiple", count: 1 }, WordResult { word: "whitespaces", count: 1 } - ] - .span(); - assert_unordered_eq(output, expected); -} - -#[test] -#[ignore] -fn alternating_word_separators_not_detected_as_a_word() { - let input = ",\n,one,\n ,two \n 'three'"; - let mut output = count_words(input); - - let expected = array![ - WordResult { word: "one", count: 1 }, - WordResult { word: "two", count: 1 }, - WordResult { word: "three", count: 1 } - ] - .span(); - assert_unordered_eq(output, expected); -} - -#[test] -#[ignore] -fn quotation_for_word_with_apostrophe() { - let input = "can, can't, 'can't'"; - let mut output = count_words(input); - - let expected = array![ - WordResult { word: "can", count: 1 }, WordResult { word: "can't", count: 2 } - ] - .span(); - assert_unordered_eq(output, expected); -} - - -// helper function. -fn assert_unordered_eq(span1: Span, span2: Span) { - // `span1` should be subset of `span2` - for item in span1 { - let mut found = false; - for other_item in span2 { - if item == other_item { - found = true; - break; - } - }; - assert!( - found, - "assertion failed: `(left == right)`\n left: `{:?}`,\n right `{:?}`", - span1, - span2 - ); - }; - // and `span2` should be subset of `span1` - for item in span2 { - let mut found = false; - for other_item in span1 { - if item == other_item { - found = true; - break; - } - }; - assert!( - found, - "assertion failed: `(left == right)`\n left: `{:?}`,\n right `{:?}`", - span1, - span2 - ); - } -} From f497c865c906c55263e3f539d28c3f81e4c1caa8 Mon Sep 17 00:00:00 2001 From: Ephraim Chukwu Date: Fri, 20 Dec 2024 12:33:40 +0100 Subject: [PATCH 57/63] Delete exercises/practice/word-count/src/lib.cairo --- exercises/practice/word-count/src/lib.cairo | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 exercises/practice/word-count/src/lib.cairo diff --git a/exercises/practice/word-count/src/lib.cairo b/exercises/practice/word-count/src/lib.cairo deleted file mode 100644 index 9e46cc2b..00000000 --- a/exercises/practice/word-count/src/lib.cairo +++ /dev/null @@ -1,9 +0,0 @@ -#[derive(Debug, PartialEq, Clone, Drop)] -pub struct WordResult { - pub word: ByteArray, - pub count: u64, -} - -pub fn count_words(phrase: ByteArray) -> Span { - panic!("implement `count_words`") -} From 5ed367cd27ebc10043c5019e92a56855661711f3 Mon Sep 17 00:00:00 2001 From: Ephraim Chukwu Date: Fri, 20 Dec 2024 12:34:03 +0100 Subject: [PATCH 58/63] Delete exercises/practice/word-count/Scarb.toml --- exercises/practice/word-count/Scarb.toml | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 exercises/practice/word-count/Scarb.toml diff --git a/exercises/practice/word-count/Scarb.toml b/exercises/practice/word-count/Scarb.toml deleted file mode 100644 index fa54cf30..00000000 --- a/exercises/practice/word-count/Scarb.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "word_count" -version = "0.1.0" -edition = "2024_07" - -[dev-dependencies] -cairo_test = "2.8.2" From c32d87f919faf3a85a424a89e4b37668a1e2dd52 Mon Sep 17 00:00:00 2001 From: Ephraim Chukwu Date: Fri, 20 Dec 2024 12:34:28 +0100 Subject: [PATCH 59/63] Delete exercises/practice/word-count/.meta/tests.toml --- .../practice/word-count/.meta/tests.toml | 57 ------------------- 1 file changed, 57 deletions(-) delete mode 100644 exercises/practice/word-count/.meta/tests.toml diff --git a/exercises/practice/word-count/.meta/tests.toml b/exercises/practice/word-count/.meta/tests.toml deleted file mode 100644 index 1be425b3..00000000 --- a/exercises/practice/word-count/.meta/tests.toml +++ /dev/null @@ -1,57 +0,0 @@ -# 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. - -[61559d5f-2cad-48fb-af53-d3973a9ee9ef] -description = "count one word" - -[5abd53a3-1aed-43a4-a15a-29f88c09cbbd] -description = "count one of each word" - -[2a3091e5-952e-4099-9fac-8f85d9655c0e] -description = "multiple occurrences of a word" - -[e81877ae-d4da-4af4-931c-d923cd621ca6] -description = "handles cramped lists" - -[7349f682-9707-47c0-a9af-be56e1e7ff30] -description = "handles expanded lists" - -[a514a0f2-8589-4279-8892-887f76a14c82] -description = "ignore punctuation" - -[d2e5cee6-d2ec-497b-bdc9-3ebe092ce55e] -description = "include numbers" - -[dac6bc6a-21ae-4954-945d-d7f716392dbf] -description = "normalize case" - -[4185a902-bdb0-4074-864c-f416e42a0f19] -description = "with apostrophes" -include = false - -[4ff6c7d7-fcfc-43ef-b8e7-34ff1837a2d3] -description = "with apostrophes" -reimplements = "4185a902-bdb0-4074-864c-f416e42a0f19" - -[be72af2b-8afe-4337-b151-b297202e4a7b] -description = "with quotations" - -[8d6815fe-8a51-4a65-96f9-2fb3f6dc6ed6] -description = "substrings from the beginning" - -[c5f4ef26-f3f7-4725-b314-855c04fb4c13] -description = "multiple spaces not detected as a word" - -[50176e8a-fe8e-4f4c-b6b6-aa9cf8f20360] -description = "alternating word separators not detected as a word" - -[6d00f1db-901c-4bec-9829-d20eb3044557] -description = "quotation for word with apostrophe" From d4e956e81b68c2addd10665debbcff5c7fe132ef Mon Sep 17 00:00:00 2001 From: Ephraim Chukwu Date: Fri, 20 Dec 2024 12:35:02 +0100 Subject: [PATCH 60/63] Delete exercises/practice/word-count/.meta/example.cairo --- .../practice/word-count/.meta/example.cairo | 102 ------------------ 1 file changed, 102 deletions(-) delete mode 100644 exercises/practice/word-count/.meta/example.cairo diff --git a/exercises/practice/word-count/.meta/example.cairo b/exercises/practice/word-count/.meta/example.cairo deleted file mode 100644 index 4712f0fa..00000000 --- a/exercises/practice/word-count/.meta/example.cairo +++ /dev/null @@ -1,102 +0,0 @@ -#[derive(Debug, PartialEq, Clone, Drop)] -pub struct WordResult { - pub word: ByteArray, - pub count: u64, -} - -pub fn count_words(phrase: ByteArray) -> Span { - let mut results: Array = ArrayTrait::new(); - let words = split_phrase_into_words(phrase); - - let mut i = 0; - while i < words.len() { - let mut found = false; - - let mut j = 0; - while j < results.len() { - if results[j].word == words[i] { - let updated_result = WordResult { - word: results[j].word.clone(), count: *results[j].count + 1, - }; - - results = remove_index_from_array(results, j); - results.append(updated_result); - found = true; - break; - } - j += 1; - }; - - if !found { - let word_and_count = WordResult { word: words[i].clone(), count: 1 }; - results.append(word_and_count); - } - - i += 1; - }; - - results.span() -} - -fn remove_index_from_array(arr: Array, index: u32) -> Array { - let mut new_arr: Array = ArrayTrait::new(); - - let mut i = 0; - while i < arr.len() { - if i != index { - new_arr.append(arr[i].clone()); - } - i += 1; - }; - - new_arr -} - -fn split_phrase_into_words(phrase: ByteArray) -> Array { - let mut words: Array = ArrayTrait::new(); - let mut current_word = ""; - - let mut i = 0; - while i < phrase.len() { - let lower_case = to_lowercase(phrase[i]); - - if is_alphanumeric_or_apostrophe(lower_case) { - if !is_apostrophe(lower_case) - || (i > 0 && i < phrase.len() - - 1 && is_alphanumeric(phrase[i - 1]) && is_alphanumeric(phrase[i + 1])) { - current_word.append_byte(lower_case); - } - } else if current_word.len() > 0 { - words.append(current_word.clone()); - current_word = ""; - } - - i += 1; - }; - - if current_word.len() > 0 { - words.append(current_word); - } - - words -} - -fn is_alphanumeric_or_apostrophe(ch: u8) -> bool { - is_alphanumeric(ch) || is_apostrophe(ch) -} - -fn is_alphanumeric(ch: u8) -> bool { - ('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') -} - -fn is_apostrophe(ch: u8) -> bool { - ch == '\'' -} - -fn to_lowercase(ch: u8) -> u8 { - if 'A' <= ch && ch <= 'Z' { - ch + 32 - } else { - ch - } -} From a3f385779a8f8fb646f3fcfedd2ab40ddb72a4fc Mon Sep 17 00:00:00 2001 From: Ephraim Chukwu Date: Fri, 20 Dec 2024 12:36:11 +0100 Subject: [PATCH 61/63] Delete exercises/practice/word-count/.docs/instructions.md --- .../practice/word-count/.docs/instructions.md | 47 ------------------- 1 file changed, 47 deletions(-) delete mode 100644 exercises/practice/word-count/.docs/instructions.md diff --git a/exercises/practice/word-count/.docs/instructions.md b/exercises/practice/word-count/.docs/instructions.md deleted file mode 100644 index 064393c8..00000000 --- a/exercises/practice/word-count/.docs/instructions.md +++ /dev/null @@ -1,47 +0,0 @@ -# Instructions - -Your task is to count how many times each word occurs in a subtitle of a drama. - -The subtitles from these dramas use only ASCII characters. - -The characters often speak in casual English, using contractions like _they're_ or _it's_. -Though these contractions come from two words (e.g. _we are_), the contraction (_we're_) is considered a single word. - -Words can be separated by any form of punctuation (e.g. ":", "!", or "?") or whitespace (e.g. "\t", "\n", or " "). -The only punctuation that does not separate words is the apostrophe in contractions. - -Numbers are considered words. -If the subtitles say _It costs 100 dollars._ then _100_ will be its own word. - -Words are case insensitive. -For example, the word _you_ occurs three times in the following sentence: - -> You come back, you hear me? DO YOU HEAR ME? - -The ordering of the word counts in the results doesn't matter. - -Here's an example that incorporates several of the elements discussed above: - -- simple words -- contractions -- numbers -- case insensitive words -- punctuation (including apostrophes) to separate words -- different forms of whitespace to separate words - -`"That's the password: 'PASSWORD 123'!", cried the Special Agent.\nSo I fled.` - -The mapping for this subtitle would be: - -```text -123: 1 -agent: 1 -cried: 1 -fled: 1 -i: 1 -password: 2 -so: 1 -special: 1 -that's: 1 -the: 2 -``` From df6290910f8fb9b681eabd06bff43f93547d2648 Mon Sep 17 00:00:00 2001 From: Ephraim Chukwu Date: Fri, 20 Dec 2024 12:36:37 +0100 Subject: [PATCH 62/63] Delete exercises/practice/word-count/.meta/config.json --- .../practice/word-count/.meta/config.json | 21 ------------------- 1 file changed, 21 deletions(-) delete mode 100644 exercises/practice/word-count/.meta/config.json diff --git a/exercises/practice/word-count/.meta/config.json b/exercises/practice/word-count/.meta/config.json deleted file mode 100644 index a390fa4f..00000000 --- a/exercises/practice/word-count/.meta/config.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "authors": [ - "Ephraim-nonso" - ], - "files": { - "solution": [ - "src/lib.cairo" - ], - "test": [ - "tests/word_count.cairo" - ], - "example": [ - ".meta/example.cairo" - ], - "invalidator": [ - "Scarb.toml" - ] - }, - "blurb": "Given a phrase, count the occurrences of each word in that phrase.", - "source": "This is a classic toy problem, but we were reminded of it by seeing it in the Go Tour." -} From 3de1993096c14b2448f86f9810a9aa530f8b6f2f Mon Sep 17 00:00:00 2001 From: Ephraim Chukwu Date: Fri, 20 Dec 2024 12:37:17 +0100 Subject: [PATCH 63/63] Delete exercises/practice/word-count/.docs/introduction.md --- exercises/practice/word-count/.docs/introduction.md | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 exercises/practice/word-count/.docs/introduction.md diff --git a/exercises/practice/word-count/.docs/introduction.md b/exercises/practice/word-count/.docs/introduction.md deleted file mode 100644 index 1654508e..00000000 --- a/exercises/practice/word-count/.docs/introduction.md +++ /dev/null @@ -1,8 +0,0 @@ -# Introduction - -You teach English as a foreign language to high school students. - -You've decided to base your entire curriculum on TV shows. -You need to analyze which words are used, and how often they're repeated. - -This will let you choose the simplest shows to start with, and to gradually increase the difficulty as time passes.