-
Notifications
You must be signed in to change notification settings - Fork 525
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 |
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`. |
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. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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:
|
||||||
|
||||||
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 | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
let my_float2 = 5.0; | ||||||
let my_int2 = my_float2; // => panic | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
``` | ||||||
|
||||||
### 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 |
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 |
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" | ||
] | ||
} | ||
} |
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` |
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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
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 | ||||||||||||||
} | ||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
[package] | ||
edition = "2021" | ||
name = "cars_assemble" | ||
version = "1.0.0" |
There was a problem hiding this comment.
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.