Compare commits
No commits in common. 'c4a6491c5be823d82be344bf12380eb582404c9f' and 'a1b5033cf89920d5774883a91792d88a4153005b' have entirely different histories.
c4a6491c5b
...
a1b5033cf8
18 changed files with 0 additions and 1104 deletions
@ -1,4 +0,0 @@
|
||||
[package] |
||||
name = "health_statistics" |
||||
version = "0.1.0" |
||||
edition = "2021" |
||||
@ -1,85 +0,0 @@
|
||||
# Help |
||||
|
||||
## Running the tests |
||||
|
||||
Execute the tests with: |
||||
|
||||
```bash |
||||
$ cargo test |
||||
``` |
||||
|
||||
All but the first test have been ignored. After you get the first test to |
||||
pass, open the tests source file which is located in the `tests` directory |
||||
and remove the `#[ignore]` flag from the next test and get the tests to pass |
||||
again. Each separate test is a function with `#[test]` flag above it. |
||||
Continue, until you pass every test. |
||||
|
||||
If you wish to run _only ignored_ tests without editing the tests source file, use: |
||||
|
||||
```bash |
||||
$ cargo test -- --ignored |
||||
``` |
||||
|
||||
If you are using Rust 1.51 or later, you can run _all_ tests with |
||||
|
||||
```bash |
||||
$ cargo test -- --include-ignored |
||||
``` |
||||
|
||||
To run a specific test, for example `some_test`, you can use: |
||||
|
||||
```bash |
||||
$ cargo test some_test |
||||
``` |
||||
|
||||
If the specific test is ignored, use: |
||||
|
||||
```bash |
||||
$ cargo test some_test -- --ignored |
||||
``` |
||||
|
||||
To learn more about Rust tests refer to the online [test documentation][rust-tests]. |
||||
|
||||
[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html |
||||
|
||||
## Submitting your solution |
||||
|
||||
You can submit your solution using the `exercism submit src/lib.rs Cargo.toml` command. |
||||
This command will upload your solution to the Exercism website and print the solution page's URL. |
||||
|
||||
It's possible to submit an incomplete solution which allows you to: |
||||
|
||||
- See how others have completed the exercise |
||||
- Request help from a mentor |
||||
|
||||
## Need to get help? |
||||
|
||||
If you'd like help solving the exercise, check the following pages: |
||||
|
||||
- The [Rust track's documentation](https://exercism.org/docs/tracks/rust) |
||||
- [Exercism's support channel on gitter](https://gitter.im/exercism/support) |
||||
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) |
||||
|
||||
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. |
||||
|
||||
## Rust Installation |
||||
|
||||
Refer to the [exercism help page][help-page] for Rust installation and learning |
||||
resources. |
||||
|
||||
## Submitting the solution |
||||
|
||||
Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. |
||||
|
||||
## Feedback, Issues, Pull Requests |
||||
|
||||
The GitHub [track repository][github] is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! |
||||
|
||||
If you want to know more about Exercism, take a look at the [contribution guide]. |
||||
|
||||
## Submitting Incomplete Solutions |
||||
It's possible to submit an incomplete solution so you can see how others have completed the exercise. |
||||
|
||||
[help-page]: https://exercism.org/tracks/rust/learning |
||||
[github]: https://github.com/exercism/rust |
||||
[contribution guide]: https://exercism.org/docs/community/contributors |
||||
@ -1,31 +0,0 @@
|
||||
# Hints |
||||
|
||||
## General |
||||
|
||||
## 1. Implement the `new()` method |
||||
|
||||
- The `new()` method receives the arguments we want to instantiate a `User` instance with. It should return an instance of `User` with the specified name, age, and weight. |
||||
|
||||
- See [here](https://doc.rust-lang.org/book/ch05-01-defining-structs.html) for additional examples on defining and instantiating structs. |
||||
|
||||
## 2. Implement the getter methods |
||||
|
||||
- The `name()`, `age()`, and `weight()` methods are getters. In other words, they are responsible for returning the corresponding field from a struct instance. |
||||
|
||||
- Notice that the `name` method returns a `&str` when the `name` field on the `User` struct is a `String`. How can we get `&str` and `String` to play nice with each other? |
||||
|
||||
- There's no need to use a `return` statement in Rust unless you expressly want a function or method to return early. Otherwise, it's more idiomatic to utilize an _implicit_ return by omitting the semicolon for the result we want a function or method to return. It's not _wrong_ to use an explicit return, but it's cleaner to take advantage of implicit returns where possible. |
||||
|
||||
```rust |
||||
fn foo() -> i32 { |
||||
1 |
||||
} |
||||
``` |
||||
|
||||
- See [here](https://doc.rust-lang.org/book/ch05-03-method-syntax.html) for some more examples of defining methods on structs. |
||||
|
||||
## 3. Implement the setter methods |
||||
|
||||
- The `set_age()` and `set_weight()` methods are setters, responsible for updating the corresponding field on a struct instance with the input argument. |
||||
|
||||
- As the signatures of these methods specify, the setter methods shouldn't return anything. |
||||
@ -1,91 +0,0 @@
|
||||
# Health Statistics |
||||
|
||||
Welcome to Health Statistics on Exercism's Rust Track. |
||||
If you need help running the tests or submitting your code, check out `HELP.md`. |
||||
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) |
||||
|
||||
## Introduction |
||||
|
||||
It is often useful to group a collection of items together, and handle those groups as units. In Rust, we call such a group a struct, and each item one of the struct's fields. A struct defines the general set of fields available, but a particular example of a struct is called an instance. |
||||
|
||||
Furthermore, structs can have methods defined on them, which have access to the fields. The struct itself in that case is referred to as `self`. When a method uses `&mut self`, the fields can be changed, or mutated. When a method uses `&self`, the fields cannot be changed: they are immutable. Controlling mutability helps the borrow-checker ensure that entire classes of concurrency bug just don't happen in Rust. |
||||
|
||||
In this exercise, you'll be implementing two kinds of methods on a struct. The first are generally known as getters: they expose the struct's fields to the world, without letting anyone else mutate that value. In Rust, these methods idiomatically share the name of the field they expose, i.e., if we have a getter method that fetches a struct field called `name`, the method would simply be called `name()`. |
||||
|
||||
You'll also be implementing methods of another type, generally known as setters. These change the value of the field. Setters aren't very common in Rust--if a field can be freely modified, it is more common to just make it public--but they're useful if updating the field should have side effects, or for access control: a setter marked as `pub(crate)` allows other modules within the same crate to update a private field, which can't be affected by the outside world. |
||||
|
||||
Structs come in three flavors: structs with named fields, tuple structs, and unit structs. For this concept exercise, we'll be exploring the first variant: structs with named fields. |
||||
|
||||
Structs are defined using the `struct` keyword, followed by the capitalized name of the type the struct is describing: |
||||
|
||||
```rust |
||||
struct Item {} |
||||
``` |
||||
|
||||
Additional types are then brought into the struct body as _fields_ of the struct, each with their own type: |
||||
|
||||
```rust |
||||
struct Item { |
||||
name: String, |
||||
weight: f32, |
||||
worth: u32, |
||||
} |
||||
``` |
||||
|
||||
Lastly, methods can be defined on structs inside of an `impl` block: |
||||
|
||||
```rust |
||||
impl Item { |
||||
// initializes and returns a new instance of our Item struct |
||||
fn new() -> Self { |
||||
unimplemented!() |
||||
} |
||||
} |
||||
``` |
||||
|
||||
With that brief introduction to the syntax of structs out of the way, go ahead and take a look at the [instructions](instructions.md) for this exercise! |
||||
|
||||
## Instructions |
||||
|
||||
You're working on implementing a health-monitoring system. As part of that, you need to keep track of users' health statistics. |
||||
|
||||
You'll start with some stubbed functions in an `impl` block as well as the following struct definition: |
||||
|
||||
```rust |
||||
pub struct User { |
||||
name: String, |
||||
age: u32, |
||||
weight: f32, |
||||
} |
||||
``` |
||||
|
||||
Your goal is to implement the stubbed out methods on the `User` `struct` defined in the `impl` block. |
||||
|
||||
For example, the `new` method should return an instance of the `User` struct with the specified name, age, and weight values. |
||||
|
||||
```rust |
||||
let mut bob = User::new(String::from("Bob"), 32, 155.2); |
||||
// Returns: a User with name "Bob", age 32, and weight 155.2 |
||||
``` |
||||
|
||||
The `weight` method should return the weight of the `User`. |
||||
|
||||
```rust |
||||
bob.weight(); |
||||
// Returns: 155.2 |
||||
``` |
||||
|
||||
The `set_age` method should set the age of the `User`. |
||||
|
||||
```rust |
||||
bob.set_age(33); |
||||
// Updates Bob's age to 33; happy birthday Bob! |
||||
``` |
||||
|
||||
Have fun! |
||||
|
||||
## Source |
||||
|
||||
### Created by |
||||
|
||||
- @seanchen1991 |
||||
@ -1,35 +0,0 @@
|
||||
// This stub file contains items that aren't used yet; feel free to remove this module attribute
|
||||
// to enable stricter warnings.
|
||||
#![allow(unused)] |
||||
|
||||
pub struct User { |
||||
name: String, |
||||
age: u32, |
||||
weight: f32, |
||||
} |
||||
|
||||
impl User { |
||||
pub fn new(name: String, age: u32, weight: f32) -> Self { |
||||
User { name, age, weight} |
||||
} |
||||
|
||||
pub fn name(&self) -> &str { |
||||
&self.name |
||||
} |
||||
|
||||
pub fn age(&self) -> u32 { |
||||
self.age |
||||
} |
||||
|
||||
pub fn weight(&self) -> f32 { |
||||
self.weight |
||||
} |
||||
|
||||
pub fn set_age(&mut self, new_age: u32) { |
||||
self.age = new_age; |
||||
} |
||||
|
||||
pub fn set_weight(&mut self, new_weight: f32) { |
||||
self.weight = new_weight; |
||||
} |
||||
} |
||||
@ -1,43 +0,0 @@
|
||||
use health_statistics::*; |
||||
|
||||
const NAME: &str = "Ebenezer"; |
||||
const AGE: u32 = 89; |
||||
const WEIGHT: f32 = 131.6; |
||||
|
||||
#[test] |
||||
fn test_name() { |
||||
let user = User::new(NAME.into(), AGE, WEIGHT); |
||||
assert_eq!(user.name(), NAME); |
||||
} |
||||
|
||||
#[test] |
||||
#[ignore] |
||||
fn test_age() { |
||||
let user = User::new(NAME.into(), AGE, WEIGHT); |
||||
assert_eq!(user.age(), AGE); |
||||
} |
||||
|
||||
#[test] |
||||
#[ignore] |
||||
fn test_weight() { |
||||
let user = User::new(NAME.into(), AGE, WEIGHT); |
||||
assert!((user.weight() - WEIGHT).abs() < f32::EPSILON); |
||||
} |
||||
|
||||
#[test] |
||||
#[ignore] |
||||
fn test_set_age() { |
||||
let new_age: u32 = 90; |
||||
let mut user = User::new(NAME.into(), AGE, WEIGHT); |
||||
user.set_age(new_age); |
||||
assert_eq!(user.age(), new_age); |
||||
} |
||||
|
||||
#[test] |
||||
#[ignore] |
||||
fn test_set_weight() { |
||||
let new_weight: f32 = 129.4; |
||||
let mut user = User::new(NAME.into(), AGE, WEIGHT); |
||||
user.set_weight(new_weight); |
||||
assert!((user.weight() - new_weight).abs() < f32::EPSILON); |
||||
} |
||||
@ -1,4 +0,0 @@
|
||||
[package] |
||||
name = "low_power_embedded_game" |
||||
version = "0.1.0" |
||||
edition = "2021" |
||||
@ -1,85 +0,0 @@
|
||||
# Help |
||||
|
||||
## Running the tests |
||||
|
||||
Execute the tests with: |
||||
|
||||
```bash |
||||
$ cargo test |
||||
``` |
||||
|
||||
All but the first test have been ignored. After you get the first test to |
||||
pass, open the tests source file which is located in the `tests` directory |
||||
and remove the `#[ignore]` flag from the next test and get the tests to pass |
||||
again. Each separate test is a function with `#[test]` flag above it. |
||||
Continue, until you pass every test. |
||||
|
||||
If you wish to run _only ignored_ tests without editing the tests source file, use: |
||||
|
||||
```bash |
||||
$ cargo test -- --ignored |
||||
``` |
||||
|
||||
If you are using Rust 1.51 or later, you can run _all_ tests with |
||||
|
||||
```bash |
||||
$ cargo test -- --include-ignored |
||||
``` |
||||
|
||||
To run a specific test, for example `some_test`, you can use: |
||||
|
||||
```bash |
||||
$ cargo test some_test |
||||
``` |
||||
|
||||
If the specific test is ignored, use: |
||||
|
||||
```bash |
||||
$ cargo test some_test -- --ignored |
||||
``` |
||||
|
||||
To learn more about Rust tests refer to the online [test documentation][rust-tests]. |
||||
|
||||
[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html |
||||
|
||||
## Submitting your solution |
||||
|
||||
You can submit your solution using the `exercism submit src/lib.rs Cargo.toml` command. |
||||
This command will upload your solution to the Exercism website and print the solution page's URL. |
||||
|
||||
It's possible to submit an incomplete solution which allows you to: |
||||
|
||||
- See how others have completed the exercise |
||||
- Request help from a mentor |
||||
|
||||
## Need to get help? |
||||
|
||||
If you'd like help solving the exercise, check the following pages: |
||||
|
||||
- The [Rust track's documentation](https://exercism.org/docs/tracks/rust) |
||||
- [Exercism's support channel on gitter](https://gitter.im/exercism/support) |
||||
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) |
||||
|
||||
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. |
||||
|
||||
## Rust Installation |
||||
|
||||
Refer to the [exercism help page][help-page] for Rust installation and learning |
||||
resources. |
||||
|
||||
## Submitting the solution |
||||
|
||||
Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. |
||||
|
||||
## Feedback, Issues, Pull Requests |
||||
|
||||
The GitHub [track repository][github] is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! |
||||
|
||||
If you want to know more about Exercism, take a look at the [contribution guide]. |
||||
|
||||
## Submitting Incomplete Solutions |
||||
It's possible to submit an incomplete solution so you can see how others have completed the exercise. |
||||
|
||||
[help-page]: https://exercism.org/tracks/rust/learning |
||||
[github]: https://github.com/exercism/rust |
||||
[contribution guide]: https://exercism.org/docs/community/contributors |
||||
@ -1,23 +0,0 @@
|
||||
# Hints |
||||
|
||||
## General |
||||
|
||||
- [Rust Book: The Tuple Type](https://doc.rust-lang.org/book/ch03-02-data-types.html#the-tuple-type) |
||||
- [Rust By Example: Tuples](https://doc.rust-lang.org/stable/rust-by-example/primitives/tuples.html) |
||||
- [Rust By Example: Destructuring](https://doc.rust-lang.org/stable/rust-by-example/flow_control/match/destructuring.html) |
||||
|
||||
## 1. Write a function `divmod` which returns both the quotient and remainder of a division |
||||
|
||||
- Don't worry about optimizing for efficiency; the naive implementation is fine |
||||
|
||||
## 2. Write an iterator adaptor `evens` which returns the even items from an arbitrary iterator |
||||
|
||||
- Just chain together the suggested methods and everything will work out |
||||
- A number `n` is even if `n % 2 == 0` |
||||
- A closure is a function with abbreviated syntax: the argument name(s) go within a pair of `|` symbols, and the expression follows. Unlike normal functions, it is not always necessary to explicitly state the type of each argument, just the name. For example, here is how you can construct an iterator of odd squares: `(0..).map(|n| 2 * n + 1).map(|n| n * n)`. |
||||
|
||||
## 3. Implement a `manhattan` method on a `Position` tuple struct |
||||
|
||||
- Don't worry about method syntax; just replacing the `unimplemented` portion within the `impl Position` block will do the right thing. |
||||
- Consider that some values within a `Position` may be negative, but a distance is never negative. |
||||
- Calculating the absolute value is [built-in](https://doc.rust-lang.org/std/primitive.i16.html#method.abs) |
||||
@ -1,162 +0,0 @@
|
||||
# Low-Power Embedded Game |
||||
|
||||
Welcome to Low-Power Embedded Game on Exercism's Rust Track. |
||||
If you need help running the tests or submitting your code, check out `HELP.md`. |
||||
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) |
||||
|
||||
## Introduction |
||||
|
||||
Tuples are a lightweight way to group a fixed set of arbitrary types of data together. A tuple doesn't have |
||||
a particular name; naming a data structure turns it into a `struct`. A tuple's fields don't have names; |
||||
they are accessed by means of destructuring or by position. |
||||
|
||||
## Syntax |
||||
|
||||
### Creation |
||||
|
||||
Tuples are always created with a tuple expression: |
||||
|
||||
```rust |
||||
// pointless but legal |
||||
let unit = (); |
||||
// single element |
||||
let single_element = ("note the comma",); |
||||
// two element |
||||
let two_element = (123, "elements can be of differing types"); |
||||
``` |
||||
|
||||
Tuples can have an arbitrary number of elements. |
||||
|
||||
### Access by destructuring |
||||
|
||||
It is possible to access the elements of a tuple by destructuring. This just means assigning variable |
||||
names to the individual elements of the tuple, consuming it. |
||||
|
||||
```rust |
||||
let (elem1, _elem2) = two_element; |
||||
assert_eq!(elem1, 123); |
||||
``` |
||||
|
||||
### Access by position |
||||
|
||||
It is also possible to access the elements of a tuple by numeric positional index. Indexing, as always, |
||||
begins at 0. |
||||
|
||||
```rust |
||||
let notation = single_element.0; |
||||
assert_eq!(notation, "note the comma"); |
||||
``` |
||||
|
||||
## Tuple Structs |
||||
|
||||
You will also be asked to work with tuple structs. Like normal structs, these are named types; unlike |
||||
normal structs, they have anonymous fields. Their syntax is very similar to normal tuple syntax. It is |
||||
legal to use both destructuring and positional access. |
||||
|
||||
```rust |
||||
struct TupleStruct(u8, i32); |
||||
let my_tuple_struct = TupleStruct(123, -321); |
||||
let neg = my_tuple_struct.1; |
||||
let TupleStruct(byte, _) = my_tuple_struct; |
||||
assert_eq!(neg, -321); |
||||
assert_eq!(byte, 123); |
||||
``` |
||||
|
||||
### Field Visibility |
||||
|
||||
All fields of anonymous tuples are always public. However, fields of tuple structs have individual |
||||
visibility which defaults to private, just like fields of standard structs. You can make the fields |
||||
public with the `pub` modifier, just as in a standard struct. |
||||
|
||||
```rust |
||||
// fails due to private fields |
||||
mod tuple { pub struct TupleStruct(u8, i32); } |
||||
fn main() { let _my_tuple_struct = tuple::TupleStruct(123, -321); } |
||||
``` |
||||
|
||||
```rust |
||||
// succeeds: fields are public |
||||
mod tuple { pub struct TupleStruct(pub u8, pub i32); } |
||||
fn main() { let _my_tuple_struct = tuple::TupleStruct(123, -321); } |
||||
``` |
||||
|
||||
## Instructions |
||||
|
||||
You are working on a game targeting a low-power embedded system and need to write several convenience functions which will be used by other parts of the game. |
||||
|
||||
## 1. Calculate the quotient and remainder of a division |
||||
|
||||
A quotient is the output of a division. |
||||
|
||||
```rust |
||||
fn divmod(dividend: i16, divisor: i16) -> (i16, i16) |
||||
``` |
||||
|
||||
Example: |
||||
|
||||
```rust |
||||
assert_eq!(divmod(10, 3), (3, 1)); |
||||
``` |
||||
|
||||
## 2. Choose even-positioned items from an iterator |
||||
|
||||
This will be helpful to enable a screen-buffer optimization, your boss promises. |
||||
|
||||
Iterators are items which expose the methods defined by the [`Iterator` trait](https://doc.rust-lang.org/std/iter/trait.Iterator.html). That documentation is fairly extensive, because they offer many methods; here are the most relevant properties: |
||||
|
||||
- An iterator is an arbitrary-length stream of items |
||||
- They have an [`enumerate` method](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.enumerate) which returns a tuple `(i, val)` for each value |
||||
- They have a [`filter` method](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.filter) which uses a closure to determine whether to yield an element of the iterator |
||||
- They have a [`map` method](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.map) which uses a closure to modify elements of the iterator |
||||
|
||||
Because your function can run on any kind of iterator, it uses `impl` to signify that this is a trait instance instead of a simple item. Likewise, the `<Item=T>` syntax just means that it doesn't matter what kind of item the iterator produces; your function can produce the even elements of any iterator. |
||||
|
||||
```rust |
||||
fn evens<T>(iter: impl Iterator<Item=T>) -> impl Iterator<Item=T> |
||||
``` |
||||
|
||||
Examples: |
||||
|
||||
```rust |
||||
let mut even_ints = evens(0_u8..); |
||||
assert_eq!(even_ints.next(), Some(0)); |
||||
assert_eq!(even_ints.next(), Some(2)); |
||||
assert_eq!(even_ints.next(), Some(4)); |
||||
assert_eq!(even_ints.next(), Some(6)); |
||||
``` |
||||
|
||||
```rust |
||||
let mut evens_from_odds = evens(1_i16..); |
||||
assert_eq!(evens_from_odds.next(), Some(1)); |
||||
assert_eq!(evens_from_odds.next(), Some(3)); |
||||
assert_eq!(evens_from_odds.next(), Some(5)); |
||||
assert_eq!(evens_from_odds.next(), Some(7)); |
||||
``` |
||||
|
||||
## 3. Calculate the manhattan distance of a position from the origin |
||||
|
||||
For mapping convenience, you have a tuple struct `Position`: |
||||
|
||||
```rust |
||||
struct Position(i16, i16); |
||||
``` |
||||
|
||||
You need to implement a method `manhattan` on `Position` which returns the [manhattan distance](https://en.wikipedia.org/wiki/Taxicab_geometry) of that position from the origin (`Position(0, 0)`). |
||||
|
||||
```rust |
||||
impl Position { |
||||
fn manhattan(&self) -> i16 |
||||
} |
||||
``` |
||||
|
||||
Example: |
||||
|
||||
```rust |
||||
assert_eq!(Position(3, 4).manhattan(), 7); |
||||
``` |
||||
|
||||
## Source |
||||
|
||||
### Created by |
||||
|
||||
- @coriolinus |
||||
@ -1,18 +0,0 @@
|
||||
// This stub file contains items that aren't used yet; feel free to remove this module attribute
|
||||
// to enable stricter warnings.
|
||||
#![allow(unused)] |
||||
|
||||
pub fn divmod(dividend: i16, divisor: i16) -> (i16, i16) { |
||||
(dividend / divisor, dividend % divisor) |
||||
} |
||||
|
||||
pub fn evens<T>(iter: impl Iterator<Item = T>) -> impl Iterator<Item = T> { |
||||
iter.enumerate().filter(|(index, item)| index % 2 == 0).map(|(_,item)| item) |
||||
} |
||||
|
||||
pub struct Position(pub i16, pub i16); |
||||
impl Position { |
||||
pub fn manhattan(&self) -> i16 { |
||||
self.0.abs() + self.1.abs() |
||||
} |
||||
} |
||||
@ -1,96 +0,0 @@
|
||||
mod divmod { |
||||
//! tests of divmod
|
||||
//!
|
||||
//! note that we're only testing positive quantities; no need to get into the mod/rem distinction
|
||||
|
||||
use low_power_embedded_game::divmod; |
||||
|
||||
#[test] |
||||
fn example() { |
||||
assert_eq!(divmod(10, 3), (3, 1)); |
||||
} |
||||
|
||||
#[test] |
||||
fn powerup() { |
||||
assert_eq!(divmod(100, 3), (33, 1)); |
||||
} |
||||
|
||||
#[test] |
||||
fn less() { |
||||
assert_eq!(divmod(3, 10), (0, 3)); |
||||
} |
||||
|
||||
#[test] |
||||
fn eq() { |
||||
assert_eq!(divmod(3, 3), (1, 0)); |
||||
} |
||||
|
||||
#[test] |
||||
fn multiple() { |
||||
assert_eq!(divmod(9, 3), (3, 0)); |
||||
} |
||||
} |
||||
|
||||
mod evens { |
||||
use low_power_embedded_game::evens; |
||||
|
||||
#[test] |
||||
fn simple_i32() { |
||||
let out: Vec<i32> = evens(0..).take(5).collect(); |
||||
assert_eq!(out, &[0, 2, 4, 6, 8]); |
||||
} |
||||
|
||||
#[test] |
||||
fn reverse_i32() { |
||||
let out: Vec<i32> = evens((0..=10).rev()).collect(); |
||||
assert_eq!(out, &[10, 8, 6, 4, 2, 0]); |
||||
} |
||||
|
||||
#[test] |
||||
fn offset_i32() { |
||||
let out: Vec<i32> = evens(1..).take(5).collect(); |
||||
assert_eq!(out, &[1, 3, 5, 7, 9]); |
||||
} |
||||
|
||||
#[test] |
||||
fn strs() { |
||||
let input = "You really must never be above joking.".split_whitespace(); |
||||
let expected: Vec<_> = "You must be joking.".split_whitespace().collect(); |
||||
let out: Vec<_> = evens(input).collect(); |
||||
assert_eq!(out, expected); |
||||
} |
||||
} |
||||
|
||||
mod manhattan { |
||||
use low_power_embedded_game::Position; |
||||
|
||||
#[test] |
||||
fn origin() { |
||||
assert_eq!(Position(0, 0).manhattan(), 0); |
||||
} |
||||
|
||||
#[test] |
||||
fn q1_unit() { |
||||
assert_eq!(Position(1, 1).manhattan(), 2); |
||||
} |
||||
|
||||
#[test] |
||||
fn q2_unit() { |
||||
assert_eq!(Position(1, -1).manhattan(), 2); |
||||
} |
||||
|
||||
#[test] |
||||
fn q3_unit() { |
||||
assert_eq!(Position(-1, -1).manhattan(), 2); |
||||
} |
||||
|
||||
#[test] |
||||
fn q4_unit() { |
||||
assert_eq!(Position(-1, 1).manhattan(), 2); |
||||
} |
||||
|
||||
#[test] |
||||
fn relative_prime() { |
||||
assert_eq!(Position(30, 70).manhattan(), 100); |
||||
} |
||||
} |
||||
@ -1,4 +0,0 @@
|
||||
[package] |
||||
name = "role_playing_game" |
||||
version = "0.1.0" |
||||
edition = "2021" |
||||
@ -1,85 +0,0 @@
|
||||
# Help |
||||
|
||||
## Running the tests |
||||
|
||||
Execute the tests with: |
||||
|
||||
```bash |
||||
$ cargo test |
||||
``` |
||||
|
||||
All but the first test have been ignored. After you get the first test to |
||||
pass, open the tests source file which is located in the `tests` directory |
||||
and remove the `#[ignore]` flag from the next test and get the tests to pass |
||||
again. Each separate test is a function with `#[test]` flag above it. |
||||
Continue, until you pass every test. |
||||
|
||||
If you wish to run _only ignored_ tests without editing the tests source file, use: |
||||
|
||||
```bash |
||||
$ cargo test -- --ignored |
||||
``` |
||||
|
||||
If you are using Rust 1.51 or later, you can run _all_ tests with |
||||
|
||||
```bash |
||||
$ cargo test -- --include-ignored |
||||
``` |
||||
|
||||
To run a specific test, for example `some_test`, you can use: |
||||
|
||||
```bash |
||||
$ cargo test some_test |
||||
``` |
||||
|
||||
If the specific test is ignored, use: |
||||
|
||||
```bash |
||||
$ cargo test some_test -- --ignored |
||||
``` |
||||
|
||||
To learn more about Rust tests refer to the online [test documentation][rust-tests]. |
||||
|
||||
[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html |
||||
|
||||
## Submitting your solution |
||||
|
||||
You can submit your solution using the `exercism submit src/lib.rs Cargo.toml` command. |
||||
This command will upload your solution to the Exercism website and print the solution page's URL. |
||||
|
||||
It's possible to submit an incomplete solution which allows you to: |
||||
|
||||
- See how others have completed the exercise |
||||
- Request help from a mentor |
||||
|
||||
## Need to get help? |
||||
|
||||
If you'd like help solving the exercise, check the following pages: |
||||
|
||||
- The [Rust track's documentation](https://exercism.org/docs/tracks/rust) |
||||
- [Exercism's support channel on gitter](https://gitter.im/exercism/support) |
||||
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) |
||||
|
||||
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. |
||||
|
||||
## Rust Installation |
||||
|
||||
Refer to the [exercism help page][help-page] for Rust installation and learning |
||||
resources. |
||||
|
||||
## Submitting the solution |
||||
|
||||
Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. |
||||
|
||||
## Feedback, Issues, Pull Requests |
||||
|
||||
The GitHub [track repository][github] is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! |
||||
|
||||
If you want to know more about Exercism, take a look at the [contribution guide]. |
||||
|
||||
## Submitting Incomplete Solutions |
||||
It's possible to submit an incomplete solution so you can see how others have completed the exercise. |
||||
|
||||
[help-page]: https://exercism.org/tracks/rust/learning |
||||
[github]: https://github.com/exercism/rust |
||||
[contribution guide]: https://exercism.org/docs/community/contributors |
||||
@ -1,163 +0,0 @@
|
||||
# Role-Playing Game |
||||
|
||||
Welcome to Role-Playing Game on Exercism's Rust Track. |
||||
If you need help running the tests or submitting your code, check out `HELP.md`. |
||||
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) |
||||
|
||||
## Introduction |
||||
|
||||
## Null-References |
||||
|
||||
If you have ever used another programming language (C/C++, Python, Java, Ruby, Lisp, etc.), it is likely that you have encountered `null` or `nil` before. |
||||
The use of `null` or `nil` is the way that these languages indicate that a particular variable has no value. |
||||
However, this makes accidentally using a variable that points to `null` an easy (and frequent) mistake to make. |
||||
As you might imagine, trying to call a function that isn't there, or access a value that doesn't exist can lead to all sorts of bugs and crashes. |
||||
The creator of `null` went so far as to call it his ['billion-dollar mistake'.](https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare/) |
||||
|
||||
## The `Option` Type |
||||
|
||||
To avoid these problems, Rust does not use null-references. |
||||
However, it still needs a safe way to indicate that a particular variable has no value. |
||||
This is where `Option` comes in. |
||||
Instead of having a variable which lacks a value, Rust variables can use the `Option` enum. |
||||
This enum has two variants: `None`, Rust's null-equivalent; and `Some(T)`, where T is a value of any type. |
||||
|
||||
It looks like this: |
||||
|
||||
```rust |
||||
enum Option<T> { |
||||
None, |
||||
Some(T), |
||||
} |
||||
``` |
||||
|
||||
You can think of `Option` as a layer of safety between you and the problems that null-references can cause, while still retaining their conceptual usefulness. |
||||
|
||||
## Using `Option` |
||||
|
||||
Setting a variable to `None` is fairly straightforward: |
||||
|
||||
```rust |
||||
let nothing: Option<u32> = None; // Variable nothing is set to None |
||||
``` |
||||
|
||||
However, if you wish for the `Option` type to carry a value, you cannot assign this value directly. |
||||
An `Option` type variable and, say, an `i32` type variable are not equivalent. |
||||
You will need to use `Some`: |
||||
|
||||
```rust |
||||
let wrong_way: Option<i32> = -4; // This will not work |
||||
|
||||
let right_way: Option<i32> = Some(-4); // This will work |
||||
let another_right_way = Some(-4); // Compiler infers that this is Option<i32> |
||||
``` |
||||
|
||||
It's also for this reason that the following will not work: |
||||
|
||||
```rust |
||||
let number = 47; |
||||
let option_number = Some(15); |
||||
|
||||
let compile_error = number + option_number; // Cannot add an i32 and an Option<i32> - they are of different types |
||||
``` |
||||
|
||||
If you wish to get the value that is contained by Some, you will first need to check that it exists: |
||||
|
||||
```rust |
||||
let mut some_words = Some("choose something to say"); // some_words set to something |
||||
|
||||
match some_words { |
||||
Some(str) => println!("Here, we will {}", str), |
||||
None => println!("I've got nothing to say"), |
||||
} // Prints "Here, we will choose something to say" |
||||
|
||||
some_words = None; // some_words now set to None |
||||
|
||||
// exactly the same match block as above |
||||
match some_words { |
||||
Some(str) => println!("Here, we will {}", str), |
||||
None => println!("I've got nothing to say"), |
||||
} // Prints "I've got nothing to say" |
||||
``` |
||||
|
||||
Besides `match`, Rust has other tools available for checking and accessing values contained within `Option`, but `match` should be familiar to you by now. |
||||
|
||||
Additionally, consider this a demonstration of why Rust uses `Option` instead of a null-reference. |
||||
The point is that **you _must_ check** whether or not the `Option` variable is `Some` (in which case you can go ahead and extract and use the value contained within), or `None`. |
||||
Anything else, and your program will not compile; the compiler is keeping you safe from `null`. |
||||
|
||||
## Instructions |
||||
|
||||
You're working on implementing a role-playing game. The player's character is represented by the following: |
||||
|
||||
```rust |
||||
pub struct Player { |
||||
health: u32, |
||||
mana: Option<u32>, |
||||
level: u32, |
||||
} |
||||
``` |
||||
|
||||
Players in this game must reach level 10 before they unlock a mana pool so that they can start casting spells. Before that point, the Player's mana is `None`. |
||||
|
||||
You're working on two pieces of functionality in this game, the revive mechanic and the spell casting mechanic. |
||||
|
||||
The `revive` method should check to ensure that the Player is indeed dead (their health has reached 0), and if they are, the method should return a new Player instance with 100 health. |
||||
If the Player's level is 10 or above, they should also be revived with 100 mana. |
||||
If the Player's level is below 10, their mana should be `None`. The `revive` method should preserve the Player's level. |
||||
|
||||
```rust |
||||
let dead_player = Player { health: 0, mana: None, level: 2 }; |
||||
dead_player.revive() |
||||
// Returns Player { health: 100, mana: None, level: 2 } |
||||
``` |
||||
|
||||
If the `revive` method is called on a Player whose health is 1 or above, then the method should return `None`. |
||||
|
||||
```rust |
||||
let alive_player = Player { health: 1, mana: Some(15), level: 11 }; |
||||
alive_player.revive() |
||||
// Returns None |
||||
``` |
||||
|
||||
The `cast_spell` method takes a mutable reference to the Player as well as a `mana_cost` parameter indicating how much mana the spell costs. It returns the amount of damage that the cast spell performs, which will always be two times the mana cost of the spell if the spell is successfully cast. |
||||
|
||||
- If the player does not have access to a mana pool, attempting to cast the spell must decrease their health by the mana cost of the spell. The damage returned must be 0. |
||||
|
||||
```rust |
||||
let not_a_wizard_yet = Player { health: 79, mana: None, level: 9 }; |
||||
assert_eq!(not_a_wizard_yet.cast_spell(5), 0) |
||||
assert_eq!(not_a_wizard_yet.health, 74); |
||||
assert_eq!(not_a_wizard_yet.mana, None); |
||||
``` |
||||
|
||||
- If the player has a mana pool but insufficient mana, the method should not affect the pool, but instead return 0 |
||||
|
||||
```rust |
||||
let low_mana_wizard = Player { health: 93, mana: Some(3), level: 12 }; |
||||
assert_eq!(low_mana_wizard.cast_spell(10), 0); |
||||
assert_eq!(low_mana_wizard.health, 93); |
||||
assert_eq!(low_mana_wizard.mana, Some(3)); |
||||
``` |
||||
|
||||
- Otherwise, the `mana_cost` should be deducted from the Player's mana pool and the appropriate amount of damage should be returned. |
||||
|
||||
```rust |
||||
let wizard = Player { health: 123, mana: Some(30), level: 18 }; |
||||
assert_eq!(wizard.cast_spell(10), 20); |
||||
assert_eq!(wizard.health, 123); |
||||
assert_eq!(wizard.mana, Some(20)); |
||||
``` |
||||
|
||||
Have fun! |
||||
|
||||
## Source |
||||
|
||||
### Created by |
||||
|
||||
- @seanchen1991 |
||||
- @coriolinus |
||||
|
||||
### Contributed to by |
||||
|
||||
- @PaulT89 |
||||
@ -1,38 +0,0 @@
|
||||
// This stub file contains items that aren't used yet; feel free to remove this module attribute
|
||||
// to enable stricter warnings.
|
||||
#![allow(unused)] |
||||
|
||||
pub struct Player { |
||||
pub health: u32, |
||||
pub mana: Option<u32>, |
||||
pub level: u32, |
||||
} |
||||
|
||||
impl Player { |
||||
pub fn revive(&self) -> Option<Player> { |
||||
match self.health { |
||||
0 => { |
||||
let mut new_mana = Some(100); |
||||
if (self.level < 10) { new_mana = None; } |
||||
Some(Player { health: 100, mana: new_mana, level: self.level}) |
||||
}, |
||||
_ => None |
||||
} |
||||
} |
||||
|
||||
pub fn cast_spell(&mut self, mana_cost: u32) -> u32 { |
||||
match self.mana { |
||||
None => { |
||||
self.health = self.health.saturating_sub(mana_cost); |
||||
0 |
||||
}, |
||||
Some(mana) if mana < mana_cost => { |
||||
0 |
||||
}, |
||||
Some(mana) => { |
||||
self.mana = Some(mana - mana_cost); |
||||
mana_cost * 2 |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -1,136 +0,0 @@
|
||||
use role_playing_game::*; |
||||
|
||||
#[test] |
||||
fn test_reviving_dead_player() { |
||||
let dead_player = Player { |
||||
health: 0, |
||||
mana: Some(0), |
||||
level: 34, |
||||
}; |
||||
let revived_player = dead_player |
||||
.revive() |
||||
.expect("reviving a dead player must return Some(player)"); |
||||
assert_eq!(revived_player.health, 100); |
||||
assert_eq!(revived_player.mana, Some(100)); |
||||
assert_eq!(revived_player.level, dead_player.level); |
||||
} |
||||
|
||||
#[test] |
||||
#[ignore] |
||||
fn test_reviving_dead_level9_player() { |
||||
let dead_player = Player { |
||||
health: 0, |
||||
mana: None, |
||||
level: 9, |
||||
}; |
||||
let revived_player = dead_player |
||||
.revive() |
||||
.expect("reviving a dead player must return Some(player)"); |
||||
assert_eq!(revived_player.health, 100); |
||||
assert_eq!(revived_player.mana, None); |
||||
assert_eq!(revived_player.level, dead_player.level); |
||||
} |
||||
|
||||
#[test] |
||||
#[ignore] |
||||
fn test_reviving_dead_level10_player() { |
||||
let dead_player = Player { |
||||
health: 0, |
||||
mana: Some(0), |
||||
level: 10, |
||||
}; |
||||
let revived_player = dead_player |
||||
.revive() |
||||
.expect("reviving a dead player must return Some(player)"); |
||||
assert_eq!(revived_player.health, 100); |
||||
assert_eq!(revived_player.mana, Some(100)); |
||||
assert_eq!(revived_player.level, dead_player.level); |
||||
} |
||||
|
||||
#[test] |
||||
#[ignore] |
||||
fn test_reviving_alive_player() { |
||||
let alive_player = Player { |
||||
health: 1, |
||||
mana: None, |
||||
level: 8, |
||||
}; |
||||
assert!(alive_player.revive().is_none()); |
||||
} |
||||
|
||||
#[test] |
||||
#[ignore] |
||||
fn test_cast_spell_with_enough_mana() { |
||||
const HEALTH: u32 = 99; |
||||
const MANA: u32 = 100; |
||||
const LEVEL: u32 = 100; |
||||
const MANA_COST: u32 = 3; |
||||
|
||||
let mut accomplished_wizard = Player { |
||||
health: HEALTH, |
||||
mana: Some(MANA), |
||||
level: LEVEL, |
||||
}; |
||||
|
||||
assert_eq!(accomplished_wizard.cast_spell(MANA_COST), MANA_COST * 2); |
||||
assert_eq!(accomplished_wizard.health, HEALTH); |
||||
assert_eq!(accomplished_wizard.mana, Some(MANA - MANA_COST)); |
||||
assert_eq!(accomplished_wizard.level, LEVEL); |
||||
} |
||||
|
||||
#[test] |
||||
#[ignore] |
||||
fn test_cast_spell_with_insufficient_mana() { |
||||
let mut no_mana_wizard = Player { |
||||
health: 56, |
||||
mana: Some(2), |
||||
level: 22, |
||||
}; |
||||
|
||||
// we want to clone so we can compare before-and-after effects of casting the spell,
|
||||
// but we don't want to introduce that concept to the student yet, so we have to do it manually
|
||||
let clone = Player { ..no_mana_wizard }; |
||||
|
||||
assert_eq!(no_mana_wizard.cast_spell(3), 0); |
||||
assert_eq!(no_mana_wizard.health, clone.health); |
||||
assert_eq!(no_mana_wizard.mana, clone.mana); |
||||
assert_eq!(no_mana_wizard.level, clone.level); |
||||
} |
||||
|
||||
#[test] |
||||
#[ignore] |
||||
fn test_cast_spell_with_no_mana_pool() { |
||||
const MANA_COST: u32 = 10; |
||||
|
||||
let mut underleveled_player = Player { |
||||
health: 87, |
||||
mana: None, |
||||
level: 6, |
||||
}; |
||||
|
||||
let clone = Player { |
||||
..underleveled_player |
||||
}; |
||||
|
||||
assert_eq!(underleveled_player.cast_spell(MANA_COST), 0); |
||||
assert_eq!(underleveled_player.health, clone.health - MANA_COST); |
||||
assert_eq!(underleveled_player.mana, clone.mana); |
||||
assert_eq!(underleveled_player.level, clone.level); |
||||
} |
||||
|
||||
#[test] |
||||
#[ignore] |
||||
fn test_cast_large_spell_with_no_mana_pool() { |
||||
const MANA_COST: u32 = 30; |
||||
|
||||
let mut underleveled_player = Player { |
||||
health: 20, |
||||
mana: None, |
||||
level: 6, |
||||
}; |
||||
|
||||
assert_eq!(underleveled_player.cast_spell(MANA_COST), 0); |
||||
assert_eq!(underleveled_player.health, 0); |
||||
assert_eq!(underleveled_player.mana, None); |
||||
assert_eq!(underleveled_player.level, 6); |
||||
} |
||||
Loading…
Reference in new issue