Skip to content

Commit

Permalink
Add Lucians Luscious Lasagna exercise
Browse files Browse the repository at this point in the history
  • Loading branch information
Nenad committed Jun 20, 2024
1 parent e29a83b commit 64707a9
Show file tree
Hide file tree
Showing 10 changed files with 368 additions and 0 deletions.
8 changes: 8 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@
],
"prerequisites": [],
"difficulty": 1
},
{
"slug": "lucians-luscious-lasagna",
"name": "lucians-luscious-lasagna",
"uuid": "8302f8de-14d7-45dd-9a65-812bc1ed5464",
"practices": [],
"prerequisites": [],
"difficulty": 1
}
]
},
Expand Down
37 changes: 37 additions & 0 deletions exercises/practice/lucians-luscious-lasagna/.docs/hints.md
Original file line number Diff line number Diff line change
@@ -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
55 changes: 55 additions & 0 deletions exercises/practice/lucians-luscious-lasagna/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -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
```
134 changes: 134 additions & 0 deletions exercises/practice/lucians-luscious-lasagna/.docs/introduction.md
Original file line number Diff line number Diff line change
@@ -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.
19 changes: 19 additions & 0 deletions exercises/practice/lucians-luscious-lasagna/.meta/config.json
Original file line number Diff line number Diff line change
@@ -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."
}
37 changes: 37 additions & 0 deletions exercises/practice/lucians-luscious-lasagna/.meta/design.md
Original file line number Diff line number Diff line change
@@ -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.
18 changes: 18 additions & 0 deletions exercises/practice/lucians-luscious-lasagna/.meta/example.cairo
Original file line number Diff line number Diff line change
@@ -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;
4 changes: 4 additions & 0 deletions exercises/practice/lucians-luscious-lasagna/Scarb.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[package]
name = "lucians_luscious_lasagna"
version = "0.1.0"
edition = "2023_11"
22 changes: 22 additions & 0 deletions exercises/practice/lucians-luscious-lasagna/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -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;
34 changes: 34 additions & 0 deletions exercises/practice/lucians-luscious-lasagna/src/tests.cairo
Original file line number Diff line number Diff line change
@@ -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));
}

0 comments on commit 64707a9

Please sign in to comment.