diff --git a/config.json b/config.json index 5609f8e10..cb4a45c89 100644 --- a/config.json +++ b/config.json @@ -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" + ], + "prerequisites": [ + "booleans" + ], + "status": "wip" + }, { "slug": "lucians-luscious-lasagna", "uuid": "29a2d3bd-eec8-454d-9dba-4b2d7d071925", diff --git a/exercises/concept/cars-assemble/.docs/hints.md b/exercises/concept/cars-assemble/.docs/hints.md new file mode 100644 index 000000000..58101279d --- /dev/null +++ b/exercises/concept/cars-assemble/.docs/hints.md @@ -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 diff --git a/exercises/concept/cars-assemble/.docs/instructions.md b/exercises/concept/cars-assemble/.docs/instructions.md new file mode 100644 index 000000000..d15c23d57 --- /dev/null +++ b/exercises/concept/cars-assemble/.docs/instructions.md @@ -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`. diff --git a/exercises/concept/cars-assemble/.docs/introduction.md b/exercises/concept/cars-assemble/.docs/introduction.md new file mode 100644 index 000000000..8b796766c --- /dev/null +++ b/exercises/concept/cars-assemble/.docs/introduction.md @@ -0,0 +1,180 @@ +# 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. + +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 + +let my_float2 = 5.0; +let my_int2 = my_float2; // => panic +``` + +### 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 `.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 diff --git a/exercises/concept/cars-assemble/.gitignore b/exercises/concept/cars-assemble/.gitignore new file mode 100644 index 000000000..db7f315c0 --- /dev/null +++ b/exercises/concept/cars-assemble/.gitignore @@ -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 diff --git a/exercises/concept/cars-assemble/.meta/config.json b/exercises/concept/cars-assemble/.meta/config.json new file mode 100644 index 000000000..f067cad5b --- /dev/null +++ b/exercises/concept/cars-assemble/.meta/config.json @@ -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" + ] + } +} diff --git a/exercises/concept/cars-assemble/.meta/design.md b/exercises/concept/cars-assemble/.meta/design.md new file mode 100644 index 000000000..0d255d172 --- /dev/null +++ b/exercises/concept/cars-assemble/.meta/design.md @@ -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` diff --git a/exercises/concept/cars-assemble/.meta/exemplar.rs b/exercises/concept/cars-assemble/.meta/exemplar.rs new file mode 100644 index 000000000..c17e22317 --- /dev/null +++ b/exercises/concept/cars-assemble/.meta/exemplar.rs @@ -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).into() +} + +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 + } +} diff --git a/exercises/concept/cars-assemble/Cargo.toml b/exercises/concept/cars-assemble/Cargo.toml new file mode 100644 index 000000000..a0e3ab7e7 --- /dev/null +++ b/exercises/concept/cars-assemble/Cargo.toml @@ -0,0 +1,4 @@ +[package] +edition = "2021" +name = "cars_assemble" +version = "1.0.0" diff --git a/exercises/concept/cars-assemble/src/lib.rs b/exercises/concept/cars-assemble/src/lib.rs new file mode 100644 index 000000000..2678bf86d --- /dev/null +++ b/exercises/concept/cars-assemble/src/lib.rs @@ -0,0 +1,11 @@ +pub fn production_rate_per_hour(_speed: i32) -> f32 { + unimplemented!("Implement production_rate_per_hour") +} + +pub fn working_items_per_minute(_speed: i32) -> i32 { + unimplemented!("Implement working_items_per_minute") +} + +pub fn success_rate(_speed: i32) -> f32 { + unimplemented!("Implement success_rate") +} diff --git a/exercises/concept/cars-assemble/tests/cars-assemble.rs b/exercises/concept/cars-assemble/tests/cars-assemble.rs new file mode 100644 index 000000000..27bc06802 --- /dev/null +++ b/exercises/concept/cars-assemble/tests/cars-assemble.rs @@ -0,0 +1,108 @@ +#[test] +fn success_rate_for_speed_zero() { + assert_eq!(0.0, cars_assemble::success_rate(0)); +} + +#[test] +#[ignore] +fn success_rate_for_speed_one() { + assert_eq!(1.0, cars_assemble::success_rate(1)); +} + +#[test] +#[ignore] +fn success_rate_for_speed_four() { + assert_eq!(1.0, cars_assemble::success_rate(4)); +} + +#[test] +#[ignore] +fn success_rate_for_speed_five() { + assert_eq!(0.9, cars_assemble::success_rate(5)); +} + +#[test] +#[ignore] +fn success_rate_for_speed_nine() { + assert_eq!(0.8, cars_assemble::success_rate(9)); +} + +#[test] +#[ignore] +fn success_rate_for_speed_ten() { + assert_eq!(0.77, cars_assemble::success_rate(10)); +} + +#[test] +#[ignore] +fn production_rate_per_hour_for_speed_zero() { + assert_eq!(0.0, cars_assemble::production_rate_per_hour(0)); +} + +#[test] +#[ignore] +fn production_rate_per_hour_for_speed_one() { + assert_eq!(221.0, cars_assemble::production_rate_per_hour(1)); +} + +#[test] +#[ignore] +fn production_rate_per_hour_for_speed_four() { + assert_eq!(884.0, cars_assemble::production_rate_per_hour(4)); +} + +#[test] +#[ignore] +fn production_rate_per_hour_for_speed_seven() { + assert_eq!(1392.3, cars_assemble::production_rate_per_hour(7)); +} + +#[test] +#[ignore] +fn production_rate_per_hour_for_speed_nine() { + assert_eq!(1591.2, cars_assemble::production_rate_per_hour(9)); +} + +#[test] +#[ignore] +fn production_rate_per_hour_for_speed_ten() { + assert_eq!(1701.7, cars_assemble::production_rate_per_hour(10)); +} + +#[test] +#[ignore] +fn working_items_per_minute_for_speed_zero() { + assert_eq!(0, cars_assemble::working_items_per_minute(0)); +} + +#[test] +#[ignore] +fn working_items_per_minute_for_speed_one() { + assert_eq!(3, cars_assemble::working_items_per_minute(1)); +} + +#[test] +#[ignore] +fn working_items_per_minute_for_speed_five() { + assert_eq!(16, cars_assemble::working_items_per_minute(5)); +} + +#[test] +#[ignore] +fn working_items_per_minute_for_speed_eight() { + let my_int = 5; + let my_float: f64 = my_int.into(); + assert_eq!(my_float, 5.0); + assert_eq!(26, cars_assemble::working_items_per_minute(8)); +} +#[test] +#[ignore] +fn working_items_per_minute_for_speed_nine() { + assert_eq!(26, cars_assemble::working_items_per_minute(9)); +} + +#[test] +#[ignore] +fn working_items_per_minute_for_speed_ten() { + assert_eq!(28, cars_assemble::working_items_per_minute(10)); +}