Skip to content

Commit

Permalink
Add Lucians luscious lasagna exercise (#14)
Browse files Browse the repository at this point in the history
* add spellcheck

* format test.yml

* format md files with prettier

* fix spellcheck issues in sh files

* enable passing a single exercise to verify-exercises + add exit 1 on cd

* refactor shell scripts

* use markdownlint-cli (instead of v2) + fix arm. num md file

* Add Lucians Luscious Lasagna exercise
  • Loading branch information
Nenad Misić authored Jun 20, 2024
1 parent adb479f commit d3b1b33
Show file tree
Hide file tree
Showing 18 changed files with 435 additions and 57 deletions.
25 changes: 18 additions & 7 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,23 +36,34 @@ jobs:

- name: Run markdown lint
run: ./bin/lint_markdown.sh


# stolen from https://raw.githubusercontent.com/exercism/github-actions/main/.github/workflows/shellcheck.yml
shellcheck:
name: Run shellcheck on scripts
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332

- name: Run shellcheck
uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38

build:
name: Check build
runs-on: ubuntu-22.04

steps:
- name: Checkout code
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332

- name: Fetch origin/main
run: git fetch --depth=1 origin main

- name: Getting scarb
uses: software-mansion/setup-scarb@v1
with:
scarb-version: "2.6.3"

- name: Verify all exercises
env:
DENYWARNINGS: "1"
Expand All @@ -61,11 +72,11 @@ jobs:
format:
name: Check Cairo formatting
runs-on: ubuntu-22.04

steps:
- name: Checkout code
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332

- name: Getting scarb
uses: software-mansion/setup-scarb@v1
with:
Expand Down
40 changes: 25 additions & 15 deletions bin/format_exercises.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,42 @@ repo=$(git rev-parse --show-toplevel)
# traverse either concept or practice exercise
# directory and format Cairo files
format_exercises() {
exercises_path="$repo/exercises/$1"
exercises_path="$repo/exercises/$1/*"
source_file_name="$2"
for exercise_dir in "$exercises_path"/*; do
cd "$exercise_dir"

for exercise_dir in $exercises_path; do
cd "$exercise_dir" || exit 1

exercise=$(basename "$exercise_dir")

# scarb fmt cannot currently format individual files, so we have to
# temporarily move the solution files into the Cairo package, where
# 'scarb fmt' can format it as well
tmp_file=$(mktemp "./src/tmp.XXXXXXXXXXX.cairo")

config_file="$exercise_dir/.meta/config.json"
if jq --exit-status '.custom?."allowed-to-not-compile"?' "$config_file"; then
exercise=$(basename "$exercise_dir")
echo "$exercise's stub is allowed to not compile"
# exit the subshell successfully to continue
# to the next exercise directory
exit 0
fi
# scarb fmt cannot currently format individual files, so we have to
# temporarily move the solution files into the Cairo package, where
# 'scarb fmt' can format it as well
tmp_file=$(mktemp "./src/tmp.XXXXXXXXXXX.cairo")
file_name=".meta/$source_file_name.cairo"
if [ -f "$file_name" ]; then
cp "$file_name" "$tmp_file"

solution_file=".meta/$source_file_name.cairo"
if [ -z "$solution_file" ]; then
echo "Could not find solution file for $exercise"
exit 1
fi

# move the solution file into the package
cp "$solution_file" "$tmp_file"

scarb fmt

# move the solution file back
if [ -f "$file_name" ]; then
cp "$tmp_file" "$file_name"
fi
rm $tmp_file
cp "$tmp_file" "$solution_file"

rm "$tmp_file"
done
}

Expand Down
3 changes: 0 additions & 3 deletions bin/lint_markdown.sh
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
#!/usr/bin/env bash
set -eo pipefail

markdownlint_cli_args="$1"

npx markdownlint-cli2 \
$markdownlint_cli_args \
docs/*.md \
concepts/**/*.md \
exercises/**/*.md
45 changes: 17 additions & 28 deletions bin/verify-exercises
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,6 @@

# Synopsis:
# Test the track's exercises.
#
# At a minimum, this file must check if the example/exemplar solution of each
# Practice/Concept Exercise passes the exercise's tests.
#
# To check this, you usually have to (temporarily) replace the exercise's solution files
# with its exemplar/example files.
#
# If your track uses skipped tests, make sure to (temporarily) enable these tests
# before running the tests.
#
# The path to the solution/example/exemplar files can be found in the exercise's
# .meta/config.json file, or possibly inferred from the exercise's directory name.

# Example: verify all exercises
# ./bin/verify-exercises
Expand All @@ -25,38 +13,39 @@ repo=$(git rev-parse --show-toplevel)

lib_cairo="./src/lib.cairo"

slug="${1:-*}"

verify_exercise() {
exercises_path="$repo/exercises/$1"
exercises_path="$repo/exercises/$1/$slug"
source_file_name="$2"
tmp_file=$(mktemp)

for exercise_dir in "$exercises_path"/*; do
if [ -z $exercise_dir ]; then
trap 'rm $tmp_file' EXIT INT TERM

for exercise_dir in $exercises_path; do
if [ -z "$exercise_dir" ]; then
continue
fi
slug=$(basename "$exercise_dir")
echo "Checking $slug exercise..."
cd "$exercise_dir"

exercise=$(basename "$exercise_dir")
echo "Checking $exercise exercise..."

cd "$exercise_dir" || exit 1

solution_file=".meta/$source_file_name.cairo"
if [ -z "$solution_file" ]; then
echo "Could not find solution for $1"
echo "Could not find solution file for $exercise"
exit 1
fi

# since we're testing the solution, we need to temporarily replace
# the exercise's solution files with its exemplar/example files
cp "$lib_cairo" "$tmp_file"
cp "$solution_file" "$lib_cairo"

scarb cairo-test

cp "$tmp_file" "$lib_cairo"
done

rm $tmp_file
}

# https://github.com/exercism/docs/blob/main/anatomy/tracks/concept-exercises.md#file-exemplar-implementation
Expand Down
10 changes: 10 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
]
},
Expand Down
1 change: 1 addition & 0 deletions docs/ABOUT.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ scalable [dApps][dapps] with the power of [validity proofs][zkp].
[cairo]: https://www.cairo-lang.org/
[dapps]: https://en.wikipedia.org/wiki/Decentralized_application
[zkp]: https://en.wikipedia.org/wiki/Zero-knowledge_proof

<!-- TODO: write document
This document contains a short introduction to the language.
Expand Down
2 changes: 1 addition & 1 deletion exercises/practice/armstrong-numbers/.docs/instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ For example:
- 10 is _not_ an Armstrong number, because `10 != 1^2 + 0^2 = 1`
- 153 is an Armstrong number, because: `153 = 1^3 + 5^3 + 3^3 = 1 + 125 + 27 = 153`
- 154 is _not_ an Armstrong number, because:
`154 != 1^3 + 5^3 + 4^3 = 1 + 125 + 64 = 190`
`154 != 1^3 + 5^3 + 4^3 = 1 + 125 + 64 = 190`

Write some code to determine whether a number is an Armstrong number.

Expand Down
4 changes: 2 additions & 2 deletions exercises/practice/leap/.docs/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ A leap year (in the Gregorian calendar) occurs:

- In every year that is evenly divisible by 4.
- Unless the year is evenly divisible by 100, in which case it's only a leap
year if the year is also evenly divisible by 400.
year if the year is also evenly divisible by 400.

Some examples:

Expand All @@ -13,6 +13,6 @@ Some examples:
- 2000 was a leap year!

> For a delightful, four-minute explanation of the whole phenomenon of leap
years, check out [this YouTube video][video].
> years, check out [this YouTube video][video].
[video]: https://www.youtube.com/watch?v=xX96xng7sAE
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
```
Loading

0 comments on commit d3b1b33

Please sign in to comment.