From a810c87b2ebac4357f9ecd11b44e42a963e22c3b Mon Sep 17 00:00:00 2001 From: Nenad Date: Thu, 20 Jun 2024 09:27:24 +0200 Subject: [PATCH] Add Lucians Luscious Lasagna exercise --- config.json | 10 ++ .../lucians-luscious-lasagna/.docs/hints.md | 37 +++++ .../.docs/instructions.md | 55 +++++++ .../.docs/introduction.md | 134 ++++++++++++++++++ .../.meta/config.json | 19 +++ .../lucians-luscious-lasagna/.meta/design.md | 37 +++++ .../.meta/example.cairo | 18 +++ .../lucians-luscious-lasagna/Scarb.toml | 4 + .../lucians-luscious-lasagna/src/lib.cairo | 22 +++ .../lucians-luscious-lasagna/src/tests.cairo | 34 +++++ 10 files changed, 370 insertions(+) create mode 100644 exercises/practice/lucians-luscious-lasagna/.docs/hints.md create mode 100644 exercises/practice/lucians-luscious-lasagna/.docs/instructions.md create mode 100644 exercises/practice/lucians-luscious-lasagna/.docs/introduction.md create mode 100644 exercises/practice/lucians-luscious-lasagna/.meta/config.json create mode 100644 exercises/practice/lucians-luscious-lasagna/.meta/design.md create mode 100644 exercises/practice/lucians-luscious-lasagna/.meta/example.cairo create mode 100644 exercises/practice/lucians-luscious-lasagna/Scarb.toml create mode 100644 exercises/practice/lucians-luscious-lasagna/src/lib.cairo create mode 100644 exercises/practice/lucians-luscious-lasagna/src/tests.cairo diff --git a/config.json b/config.json index fd6c9669..aa9eeec6 100644 --- a/config.json +++ b/config.json @@ -77,6 +77,16 @@ ], "prerequisites": [], "difficulty": 1 + }, + { + "slug": "lucians-luscious-lasagna", + "name": "lucians-luscious-lasagna", + "uuid": "8302f8de-14d7-45dd-9a65-812bc1ed5464", + "practices": [ + "functions" + ], + "prerequisites": [], + "difficulty": 1 } ] }, diff --git a/exercises/practice/lucians-luscious-lasagna/.docs/hints.md b/exercises/practice/lucians-luscious-lasagna/.docs/hints.md new file mode 100644 index 00000000..c660140b --- /dev/null +++ b/exercises/practice/lucians-luscious-lasagna/.docs/hints.md @@ -0,0 +1,37 @@ +# Hints + +## General + +- An integer literal can be defined as one or more consecutive digits. + +## 1. Define the expected oven time in minutes + +- You need to define a [function][functions] without any parameters. + +## 2. Calculate the remaining oven time in minutes + +- You need to define a [function][functions] with a single parameter. +- You can use and refer to the previously defined item by its name. +- The last expression in a function is [automatically returned][return-values] + from the function; you don't have to explicitly indicate which value to + return. +- You can use the [mathematical operator for subtraction][operators] to + subtract values. + +## 3. Calculate the preparation time in minutes + +- You need to define a [function][functions] with a single parameter. +- You can use the [mathematical operator for multiplication][operators] to + multiply values. + +## 4. Calculate the elapsed time in minutes + +- You need to define a [function][functions] with two parameters. +- You can [call][functions] one of the other functions you've defined + previously. +- You can use the [mathematical operator for addition][operators] to add + values. + +[functions]: https://book.cairo-lang.org/ch02-03-functions.html +[return-values]: https://book.cairo-lang.org/ch02-03-functions.html#functions-with-return-values +[operators]: https://book.cairo-lang.org/appendix-02-operators-and-symbols.html diff --git a/exercises/practice/lucians-luscious-lasagna/.docs/instructions.md b/exercises/practice/lucians-luscious-lasagna/.docs/instructions.md new file mode 100644 index 00000000..0068e266 --- /dev/null +++ b/exercises/practice/lucians-luscious-lasagna/.docs/instructions.md @@ -0,0 +1,55 @@ +# Instructions + +In this exercise you're going to write some code to help you cook a brilliant +lasagna from your favorite cooking book. + +You have four tasks, all related to the time spent cooking the lasagna. + +## 1. Define the expected oven time in minutes + +Define the `expected_minutes_in_oven` binding to check how many minutes the +lasagna should be in the oven. According to the cooking book, the expected +oven time in minutes is 40: + +```rust +expected_minutes_in_oven() +// Returns: 40 +``` + +## 2. Calculate the remaining oven time in minutes + +Define the `remaining_minutes_in_oven` function that takes the actual minutes +the lasagna has been in the oven as a parameter and returns how many minutes +the lasagna still has to remain in the oven, based on the expected oven time +in minutes from the previous task. + +```rust +remaining_minutes_in_oven(30) +// Returns: 10 +``` + +## 3. Calculate the preparation time in minutes + +Define the `preparation_time_in_minutes` function that takes the number of +layers you added to the lasagna as a parameter and returns how many minutes you +spent preparing the lasagna, assuming each layer takes you 2 minutes to +prepare. + +```rust +preparation_time_in_minutes(2) +// Returns: 4 +``` + +## 4. Calculate the elapsed time in minutes + +Define the `elapsed_time_in_minutes` function that takes two parameters: the +first parameter is the number of layers you added to the lasagna, and the +second parameter is the number of minutes the lasagna has been in the oven. +The function should return how many minutes you've worked on cooking the +lasagna, which is the sum of the preparation time in minutes, and the time in +minutes the lasagna has spent in the oven at the moment. + +```rust +elapsed_time_in_minutes(3, 20) +// Returns: 26 +``` diff --git a/exercises/practice/lucians-luscious-lasagna/.docs/introduction.md b/exercises/practice/lucians-luscious-lasagna/.docs/introduction.md new file mode 100644 index 00000000..a6f13d1a --- /dev/null +++ b/exercises/practice/lucians-luscious-lasagna/.docs/introduction.md @@ -0,0 +1,134 @@ +# Introduction + +In Cairo, assigning a value to a name is referred to as a _binding_. Bindings +are immutable unless declared with the `mut` keyword. As Cairo is a +statically-typed language, each binding has a type known at compile-time. + +Bindings are most commonly defined using the `let` keyword. Specifying a +binding's type is optional for most bindings, as Cairo's _type inference_ +can usually infer the type based on their value. A binding looks like this: + +```rust +// Automatically inferred type +let fingers = 10; +``` + +Functions are _items_. Where bindings typically refer to a particular value, +items refer to a unit of code organization, typically a function or a module, +which is available throughout the lifetime of the program. A function +automatically returns the result of its last expression. A function may have 0 +or more parameters, which are bindings with a lifetime of the function call. + +Type inference is theoretically possible for functions, but is disabled as an +intentional language design choice. While this means that you need to spend a +little more time when writing code to specify precisely what a function's input +and output types are, you save the time when you're reading the code, because +all the input and output types are explicitly defined. + +```rust +fn add(x: i32, y: i32) -> i32 { + x + y +} +``` + +Invoking a function is done by specifying its name followed by parentheses. +If the function requires parameters, an argument must be specified for each +within the parentheses. + +```rust +let five = add(2, 3); +``` + +If a binding's type cannot be inferred, the compiler will report an error. To +fix this, add an explicit type annotation to the binding. + +```rust +// Explicit type annotation +let fingers: i32 = 10; +``` + +Items in Cairo can be used before or after they are defined, because they have +a static lifetime. Bindings, on the other hand, can only be used _after_ they +have been defined. Using a binding before it has been defined results in a +compile error. + +```rust +fn main() { + // `fn add` hasn't yet been defined, but that's perfectly ok + dbg!(add(3, 4)); +} + +fn add(x: i32, y: i32) -> i32 { + x + y +} +``` + +```rust +// this won't compile; `a` is used before its binding is defined +let b = a; +let a = x + y; +``` + +Cairo uses curly braces (`{}`) to define a scope. A binding defined within a +scope can't escape from it. + +```rust +let a = 1; +dbg!(a); // 1 +{ + // Here, we re-bind `a` to a new value, which is still immutable. + // This technique is called _shadowing_. The new binding is constrained to + // this anonymous scope. Outside this scope, the previous binding still + // applies. + let a = 2; + let b = 3; + dbg!(a, b); // 2, 3 +} +// can't use `b` anymore because it is out of scope +// dbg!(b); + +// The shadowed `a` in the inner scope above has fallen out of scope, +// leaving us with our original binding. +dbg!(a); // 1 +``` + +Cairo items are often organized in modules. Each crate is implicitly a module, +but it can define inner sub-modules of arbitrary depth. A module groups related +functionality and is defined using the `mod` keyword. + +```rust +mod calc_i32 { + fn add(a: i32, b: i32) -> i32 { a + b } + fn sub(a: i32, b: i32) -> i32 { a - b } + fn mul(a: i32, b: i32) -> i32 { a * b } + fn div(a: i32, b: i32) -> i32 { a / b } +} +``` + +Cairo supports two types of comments. The keyword `//` indicates a single-line +comment; everything following the keyword until the end of the line is ignored. +The keywords `/*` and `*/` indicate a multi-line comment; everything within +those two keywords is ignored. It is idiomatic and good practice to prefer +single-line comments. + +Cairo also supports doc-comments, which show up in the generated documentation +produced by `cargo doc`. Outer doc comments are formed with the keyword `///`, +which acts identically to the `//` keyword. They apply to the item which +follows them, such as a function: + +```rust +/// The `add` function produces the sum of its arguments. +fn add(x: i32, y: i32) -> i32 { x + y } +``` + +Inner doc comments are formed with the keyword `//!`, which acts identically to +the `//` keyword. They apply to the item enclosing them, such as a module: + +```rust +mod my_cool_module { + //! This module is the bee's knees. +} +``` + +Doc comments can be of arbitrary length and contain markdown, which is rendered +into the generated documentation. diff --git a/exercises/practice/lucians-luscious-lasagna/.meta/config.json b/exercises/practice/lucians-luscious-lasagna/.meta/config.json new file mode 100644 index 00000000..3252f418 --- /dev/null +++ b/exercises/practice/lucians-luscious-lasagna/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "misicnenad" + ], + "files": { + "solution": [ + "src/lib.cairo", + "Scarb.toml" + ], + "test": [ + "src/tests.cairo" + ], + "example": [ + ".meta/example.cairo" + ] + }, + "icon": "lasagna", + "blurb": "Learn about the basics of Cairo by following a lasagna recipe." +} diff --git a/exercises/practice/lucians-luscious-lasagna/.meta/design.md b/exercises/practice/lucians-luscious-lasagna/.meta/design.md new file mode 100644 index 00000000..5edb8a76 --- /dev/null +++ b/exercises/practice/lucians-luscious-lasagna/.meta/design.md @@ -0,0 +1,37 @@ +# Design + +## Learning objectives + +- Know how to define a function +- Know how to return a value from a function + +## Out of scope + +- Know how to work with `const` values + +## Concepts + +- Functions + +## Prerequisites + +None + +## Resources to refer to + +### Hints + +- [Functions](https://book.cairo-lang.org/ch02-03-functions.html) +- [Return values](https://book.cairo-lang.org/ch02-03-functions.html#functions-with-return-values) +- [Operators](https://book.cairo-lang.org/appendix-02-operators-and-symbols.html) + +### After + +## Representer + +This exercise does not require any specific representation logic to be added to +the representer. + +## Analyzer + +This exercise does not require any specific logic to be added to the analyzer. diff --git a/exercises/practice/lucians-luscious-lasagna/.meta/example.cairo b/exercises/practice/lucians-luscious-lasagna/.meta/example.cairo new file mode 100644 index 00000000..d85502ed --- /dev/null +++ b/exercises/practice/lucians-luscious-lasagna/.meta/example.cairo @@ -0,0 +1,18 @@ +pub fn expected_minutes_in_oven() -> u32 { + 40 +} + +pub fn remaining_minutes_in_oven(actual_minutes_in_oven: u32) -> u32 { + expected_minutes_in_oven() - actual_minutes_in_oven +} + +pub fn preparation_time_in_minutes(number_of_layers: u32) -> u32 { + number_of_layers * 2 +} + +pub fn elapsed_time_in_minutes(number_of_layers: u32, actual_minutes_in_oven: u32) -> u32 { + preparation_time_in_minutes(number_of_layers) + actual_minutes_in_oven +} + +#[cfg(test)] +mod tests; diff --git a/exercises/practice/lucians-luscious-lasagna/Scarb.toml b/exercises/practice/lucians-luscious-lasagna/Scarb.toml new file mode 100644 index 00000000..88827db0 --- /dev/null +++ b/exercises/practice/lucians-luscious-lasagna/Scarb.toml @@ -0,0 +1,4 @@ +[package] +name = "lucians_luscious_lasagna" +version = "0.1.0" +edition = "2023_11" diff --git a/exercises/practice/lucians-luscious-lasagna/src/lib.cairo b/exercises/practice/lucians-luscious-lasagna/src/lib.cairo new file mode 100644 index 00000000..e0577240 --- /dev/null +++ b/exercises/practice/lucians-luscious-lasagna/src/lib.cairo @@ -0,0 +1,22 @@ +pub fn expected_minutes_in_oven() -> u32 { + panic!("return expected minutes in the oven") +} + +pub fn remaining_minutes_in_oven(actual_minutes_in_oven: u32) -> u32 { + panic!( + "calculate remaining minutes in oven given actual minutes in oven: {actual_minutes_in_oven}" + ) +} + +pub fn preparation_time_in_minutes(number_of_layers: u32) -> u32 { + panic!("calculate preparation time in minutes for number of layers: {number_of_layers}") +} + +pub fn elapsed_time_in_minutes(number_of_layers: u32, actual_minutes_in_oven: u32) -> u32 { + panic!( + "calculate elapsed time in minutes for number of layers {number_of_layers} and actual minutes in oven {actual_minutes_in_oven}" + ) +} + +#[cfg(test)] +mod tests; diff --git a/exercises/practice/lucians-luscious-lasagna/src/tests.cairo b/exercises/practice/lucians-luscious-lasagna/src/tests.cairo new file mode 100644 index 00000000..3733f035 --- /dev/null +++ b/exercises/practice/lucians-luscious-lasagna/src/tests.cairo @@ -0,0 +1,34 @@ +use lucians_luscious_lasagna::{ + elapsed_time_in_minutes, expected_minutes_in_oven, preparation_time_in_minutes, + remaining_minutes_in_oven +}; + +#[test] +fn expected_minutes_in_oven_is_correct() { + assert_eq!(40, expected_minutes_in_oven()); +} + +#[test] +fn remaining_minutes_in_oven_after_fifteen_minutes() { + assert_eq!(15, remaining_minutes_in_oven(25)); +} + +#[test] +fn preparation_time_in_minutes_for_one_layer() { + assert_eq!(2, preparation_time_in_minutes(1)); +} + +#[test] +fn preparation_time_in_minutes_for_multiple_layers() { + assert_eq!(8, preparation_time_in_minutes(4)); +} + +#[test] +fn elapsed_time_in_minutes_for_one_layer() { + assert_eq!(32, elapsed_time_in_minutes(1, 30)); +} + +#[test] +fn elapsed_time_in_minutes_for_multiple_layers() { + assert_eq!(16, elapsed_time_in_minutes(4, 8)); +}