Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ (concept) Add new concept exercise cars-assemble #1675

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,21 @@
},
"exercises": {
"concept": [
{
"slug": "cars-assemble",
"uuid": "1d0e6e2c-c319-48bc-8626-7b3c98473f42",
"name": "Cars Assemble",
"difficulty": 1,
"concepts": [
"if-statements",
"assignment",
"numbers"
Comment on lines +44 to +46
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can tell, these concepts do not exist? I'm assuming these need to reference some actual concept, I didn't find precise documentation on the purpose of this key here.

],
"prerequisites": [
"booleans"
],
"status": "wip"
},
{
"slug": "lucians-luscious-lasagna",
"uuid": "29a2d3bd-eec8-454d-9dba-4b2d7d071925",
Expand Down
34 changes: 34 additions & 0 deletions exercises/concept/cars-assemble/.docs/hints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Hints

## General

- [Rust book][rust-book-data-types] on Integers and Floating point numbers.

## 1. Calculate the success rate

- Determining the success rate can be done through a [conditional statement][if-statement].

## 2. Calculate the production rate per second

- Use `.into()` to convert `i32` to `f64`.
- Use the `success_rate()` method you wrote earlier to determine the success rate.
- Rust does not allow for multiplication to be applied to two different number
types (such as an `i32` and a `f64`). Both must be of the same type.
- Numbers can be compared using the built-in comparision and equality operators.
Checkout [full list of operators][operators-list] supported by Rust.
## 3. Calculate the number of working items produced per second

- Use `.into()` to convert `i32` to `f64`.
- Rounding a float to a certain precision (here 1 decimal places) can be done using:
```rust
let my_float = 3.166;
let rounded = (my_float * 10.0).round() / 10.0;
// => 3.2
```
Read more on this [StackOverflow answer][stackoverflow-rounding].

[if-statement]: https://doc.rust-lang.org/rust-by-example/flow_control/if_else.html#ifelse
[stackoverflow-rounding]: https://stackoverflow.com/a/28656825
[operators-list]:https://doc.rust-lang.org/book/appendix-02-operators.html#operators
[rust-book-data-types]:
https://doc.rust-lang.org/book/ch03-02-data-types.html#integer-types
51 changes: 51 additions & 0 deletions exercises/concept/cars-assemble/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Instructions

In this exercise you'll be writing code to analyze the production of an assembly line in a car factory.
The assembly line's speed can range from `0` (off) to `10` (maximum).

At its lowest speed (`1`), `221` cars are produced each hour. The production increases linearly with the speed.
So with the speed set to `4`, it should produce `4 * 221 = 884` cars per hour.
However, higher speeds increase the likelihood that faulty cars are produced, which then have to be discarded.

You have three tasks.

## 1. Calculate the success rate

Implement the `success_rate()` function to calculate the ratio of an item being
created without error for a given speed.
The following table shows how speed influences the success rate:

- `0`: 0% success rate.
- `1` to `4`: 100% success rate.
- `5` to `8`: 90% success rate.
- `9`: 80% success rate.
- `10`: 77% success rate.

```rust
success_rate(10)
// => 0.77
```

Note that the value returned is a `f64`.

## 2. Calculate the production rate per hour

Implement the `production_rate_per_hour()` function to calculate the assembly line's production rate per hour, taking into account its success rate:

```rust
production_rate_per_hour(6)
// => 1193.4
```

Note that the value returned is a `f64`.

## 3. Calculate the number of working items produced per minute

Implement the `working_items_per_minute()` function to calculate how many working cars are produced per minute:

```rust
working_items_per_minute(6)
// => 19
```

Note that the value returned is an `i32`.
185 changes: 185 additions & 0 deletions exercises/concept/cars-assemble/.docs/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
# Introduction

## Numbers

There are two different types of numbers in Rust:

- Integers: numbers with no digits behind the decimal separator (whole numbers). Examples are `-6`, `0`, `1`, `25`, `976` and `500000`.
- Floating-point numbers: numbers with zero or more digits behind the decimal separator. Examples are `-2.4`, `0.1`, `3.14`, `16.984025` and `1024.0`.

The two default numeric types in Rust are `i32` and `f64`. An `i32` is a 32-bit integer and a `f64` is a 64-bit floating-point number.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They aren't used in the exercise, but it might be appropriate to include a note about the other number types? Something like:

There are other number types with different precision, like f32 and i16. Unsigned (always positive) integers start with a u instead of i. For example, a byte is expressed as u8. Another number type you'll come across is usize, its precision depends on your computer (usually 64 bits) and is used for lengths and indexes.


Arithmetic is done using the standard arithmetic operators. Numbers can be
compared using the standard numeric comparison operators and the equality (`==`)
and inequality (`!=`) operators.

## Assignment

The following syntax can be used to define a variable and assign a value to it.

```rust
let my_variable = 5;
```

The above defines a variable with value 5 which automatically makes its type as
`i32`. The value of this variable cannot be changed.
In Rust, `snake_case` is used to define the name of a variable.

To create a variable that can be assigned a different value one can use `mut`
keyword:

```rust
let mut my_variable = 5;
my_variable = 10;
```

In Rust, integers and floats are different types hence you cannot assign a
float to an integer variable and vice-versa. Not even if the values seem equal:

```rust
let my_int = 5;
let my_float = my_int; // => panic
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let my_float = my_int; // => panic
let my_float = my_int; // => compiler error


let my_float2 = 5.0;
let my_int2 = my_float2; // => panic
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let my_int2 = my_float2; // => panic
let my_int2 = my_float2; // => compiler error

```

### Constants
Like immutable variables, *constants* are values that are bound to a name and
are not allowed to change, but there are a few differences between constants
and variables.

- First, you aren’t allowed to use `mut` with constants.
- Constants aren’t just immutable by default—they’re always immutable.
- You declare constants using the `const` keyword instead of the `let` keyword, and the type of the value *must* be annotated.
- Constants can be declared in any scope, including the global scope, which makes them useful for values that many parts of code need to know about.
- The last difference is that constants may be set only to a constant expression, not the result of a value that could only be computed at runtime.

Here’s an example of a constant declaration:

```rust
const SECONDS_IN_A_MINUTE: u32 = 60;
```

In Rust, constants are defined using `CAPITAL_SNAKE_CASE`.

### Rust requires explicit conversion between types

- Using the `as` casting:
```rust
let my_float: f64 = 50.0;
let my_int = my_float as i32; // works as expected
```

- Using the `.into()` method:
```rust
let my_int = 50;
let my_float: f64 = my_int.into(); // works as expected
```

Note that this requires specifying the variable type explicitly.

As an `i32` has less precision than a `f64`, converting from an `i32` to a `f64` is safe and lossless. However, converting from a `f64` to an `i32` could mean losing data.

## Numeric Operators

Rust supports various operators on integers and floats.

Take a look at the following table that illustrates how each operator behaves with integers and floats.

| Symbol | Integer | Floating Point |
|--------|-------------------------|----------------|
| `+` | Addition | Addition |
| `-` | Subtraction | Subtraction |
| `*` | Multiplication | Multiplication |
| `/` | Division* | Division |
| `%` | Remainder** | Remainder |

\* Integer division rounds towards zero.

\*\* Rust uses a remainder defined with [truncating division].
Given `remainder = dividend % divisor`, the remainder will have the same sign as the dividend.

Note that both operands of an operator must be of same type.
e.g. For `+` operator, an integer cannot be added to a float and vice-versa.

Following example demonstrates usage for these operators.

```rust
let result_1 = 3 + 6;
// => 9
let result_2 = 5.5 - 1.25;
// => 4.25
let result_3 = -5 * 14;
// => -70
let result_4 = 14 / 3;
// => 4
let result_5 = 100 % 7;
// => 2
```

## If Statements

In this exercise you must conditionally execute logic. The most common way to do this in Rust is by using an `if/else` statement:

`if` expressions start with the keyword `if`, followed by a condition. In this
case, the condition checks whether or not the variable `number` has a value less
than `5`.


```rust
let number = 3;

if number < 5 {
println!("condition was true");
} else {
println!("condition was false");
}
```

Optionally, we can also include an `else` expression, which we chose to do here,
to give the program an alternative block of code to execute should the condition
evaluate to `false`.

If you don’t provide an `else` expression and the condition is `false`, the program will just skip the `if` block and move on to the next bit of code.

The condition of an `if` statement must be of type `bool`. Rust has no concept of
_truthy_ values.

```rust
let number = 3;

if number {
println!("number was three");
}
```

The `if` condition evaluates to a value of `3` this time, and Rust throws an
error:

```txt
|
4 | if number {
| ^^^^^^ expected `bool`, found integer

For more information about this error, try `rustc --explain E0308`.
error: could not compile `branches` due to previous error
```

You can use multiple conditions by combining `if` and `else` in an `else if` expression. For example:

```rust
let x = 6;

if x == 5 {
// Execute logic if x equals 5
} else if x > 7 {
// Execute logic if x greater than 7
} else {
// Execute logic in all other cases
}
```


[truncating division]:
https://en.wikipedia.org/wiki/Modulo_operation#Variants_of_the_definition
8 changes: 8 additions & 0 deletions exercises/concept/cars-assemble/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Generated by Cargo
# will have compiled files and executables
/target/
**/*.rs.bk

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
Cargo.lock
19 changes: 19 additions & 0 deletions exercises/concept/cars-assemble/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"blurb": "Learn about numbers by analyzing the production of an assembly line.",
"authors": [
"devkabiir"
],
"contributors": [],
"files": {
"solution": [
"src/lib.rs",
"Cargo.toml"
],
"test": [
"tests/cars-assemble.rs"
],
"exemplar": [
".meta/exemplar.rs"
]
}
}
26 changes: 26 additions & 0 deletions exercises/concept/cars-assemble/.meta/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Design

## Learning objectives

- Know of the existence of the two default number types, `i32` and `f64`.
- Understand that an `i32` represents whole numbers, and a `f64` represents floating-point numbers.
- Know of basic operators such as multiplication, comparison and equality.
- Know how to convert from one numeric type to another.
- Know how to conditionally execute code using an `if` statement.

## Out of scope

- Any other numeric types besides `i32` and `f64` (so no `float`, `byte`, etc.).
- Parsing a `string` to an `i32` or `f64`.
- Converting an `i32` or `f64` to a `string`.

## Concepts

- `integers`: know about `i32` and `f64` types
- `if-statements`: know how to conditionally execute code using an `if` statement.
- `math-operators`: know the math operators; know about precedence; know the role of parentheses
- `assignment`: know the syntax and behavior of assignment in OO languages

## Prerequisites

- `booleans`
33 changes: 33 additions & 0 deletions exercises/concept/cars-assemble/.meta/exemplar.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const PRODUCTION_RATE_PER_HOUR_FOR_DEFAULT_SPEED: i32 = 221;

pub fn production_rate_per_hour(speed: i32) -> f64 {
let result = production_rate_per_hour_for_speed(speed) * success_rate(speed);

round_to_1_decimal(result)
}

fn round_to_1_decimal(input: f64) -> f64 {
(input * 10.0).round() / 10.0
}

fn production_rate_per_hour_for_speed(speed: i32) -> f64 {
(PRODUCTION_RATE_PER_HOUR_FOR_DEFAULT_SPEED * speed).into()
}

pub fn working_items_per_minute(speed: i32) -> i32 {
(production_rate_per_hour(speed) / 60.0) as i32
}
Comment on lines +17 to +19
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub fn working_items_per_minute(speed: i32) -> i32 {
(production_rate_per_hour(speed) / 60.0) as i32
}
pub fn working_items_per_minute(speed: i32) -> f64 {
production_rate_per_hour(speed) / 60.0
}

As discussed here.


pub fn success_rate(speed: i32) -> f64 {
if speed == 10 {
0.77
} else if speed == 9 {
0.8
} else if speed >= 5 {
0.9
} else if speed <= 0 {
0.0
} else {
1.0
}
}
4 changes: 4 additions & 0 deletions exercises/concept/cars-assemble/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[package]
edition = "2021"
name = "cars_assemble"
version = "1.0.0"
Loading