Add exercise 364
This commit is contained in:
commit
84e4493060
13
.gitignore
vendored
Normal file
13
.gitignore
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# ---> Rust
|
||||||
|
# Generated by Cargo
|
||||||
|
# will have compiled files and executables
|
||||||
|
debug/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||||
|
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||||
|
Cargo.lock
|
||||||
|
|
||||||
|
# These are backup files generated by rustfmt
|
||||||
|
**/*.rs.bk
|
||||||
|
|
26
LICENSE
Normal file
26
LICENSE
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
Copyright (c) 2022 Emelie Graven. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
may be used to endorse or promote products derived from this software without
|
||||||
|
specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
3
README.md
Normal file
3
README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# Daily Programmer exercises
|
||||||
|
Short exercises from [Daily Programmer](https://libredd.it/r/dailyprogrammer)
|
||||||
|
|
10
e_364/Cargo.toml
Normal file
10
e_364/Cargo.toml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
[package]
|
||||||
|
name = "e_364"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Emelie Graven <emelie@graven.dev>"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rand = "0.8"
|
7
e_364/input.txt
Normal file
7
e_364/input.txt
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
5d12
|
||||||
|
6d4
|
||||||
|
1d2
|
||||||
|
1d8
|
||||||
|
3d6
|
||||||
|
4d20
|
||||||
|
100d100
|
70
e_364/readme.md
Normal file
70
e_364/readme.md
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
# Description
|
||||||
|
|
||||||
|
I love playing D&D with my friends, and my favorite part is creating character sheets \(my DM is notorious for killing us all off by level 3 or so\). One major part of making character sheets is rolling the character's stats. Sadly, I have lost all my dice, so I'm asking for your help to make a dice roller for me to use!
|
||||||
|
|
||||||
|
# Formal Inputs & Outputs
|
||||||
|
|
||||||
|
## Input description
|
||||||
|
|
||||||
|
Your input will contain one or more lines, where each line will be in the form of "NdM"; for example:
|
||||||
|
|
||||||
|
3d6
|
||||||
|
4d12
|
||||||
|
1d10
|
||||||
|
5d4
|
||||||
|
|
||||||
|
If you've ever played D&D you probably recognize those, but for the rest of you, this is what those mean:
|
||||||
|
|
||||||
|
The first number is the number of dice to roll, the d just means "dice", it's just used to split up the two numbers, and the second number is how many sides the dice have. So the above example of "3d6" means "roll 3 6\-sided dice". Also, just in case you didn't know, in D&D, not all the dice we roll are the normal cubes. A d6 is a cube, because it's a 6\-sided die, but a d20 has twenty sides, so it looks a lot closer to a ball than a cube.
|
||||||
|
|
||||||
|
The first number, the number of dice to roll, can be any integer between 1 and 100, inclusive.
|
||||||
|
|
||||||
|
The second number, the number of sides of the dice, can be any integer between 2 and 100, inclusive.
|
||||||
|
|
||||||
|
## Output description
|
||||||
|
|
||||||
|
You should output the sum of all the rolls of that specified die, each on their own line. so if your input is "3d6", the output should look something like
|
||||||
|
|
||||||
|
14
|
||||||
|
|
||||||
|
Just a single number, you rolled 3 6\-sided dice, and they added up to 14.
|
||||||
|
|
||||||
|
# Challenge Input
|
||||||
|
|
||||||
|
5d12
|
||||||
|
6d4
|
||||||
|
1d2
|
||||||
|
1d8
|
||||||
|
3d6
|
||||||
|
4d20
|
||||||
|
100d100
|
||||||
|
|
||||||
|
# Challenge Output
|
||||||
|
|
||||||
|
[some number between 5 and 60, probably closer to 32 or 33]
|
||||||
|
[some number between 6 and 24, probably around 15]
|
||||||
|
[you get the idea]
|
||||||
|
[...]
|
||||||
|
|
||||||
|
# Notes/Hints
|
||||||
|
|
||||||
|
A dice roll is basically the same as picking a random number between 1 and 6 \(or 12, or 20, or however many sides the die has\). You should use some way of randomly selecting a number within a range based off of your input. Many common languages have random number generators available, but at least a few of them will give the same "random" numbers every time you use the program. In my opinion that's not very random. If you run your code 3\+ times with the same inputs and it gives the same outputs, that wouldn't be super useful for a game of D&D, would it? If that happens with your code, try to find a way around that. I'm guessing for some of the newer folks, this might be one of the trickier parts to get correct.
|
||||||
|
|
||||||
|
Don't just multiply your roll by the number of dice, please. I don't know if any of you were thinking about doing that, but I was. The problem is that if you do that, it eliminates a lot of possible values. For example, there's no way to roll 14 from 3d6 if you just roll it once and multiply by 3. Setting up a loop to roll each die is probably your best bet here.
|
||||||
|
|
||||||
|
# Bonus
|
||||||
|
|
||||||
|
In addition to the sum of all dice rolls for your output, print out the result of each roll on the same line, using a format that looks something like
|
||||||
|
|
||||||
|
14: 6 3 5
|
||||||
|
22: 10 7 1 4
|
||||||
|
9: 9
|
||||||
|
11: 3 2 2 1 3
|
||||||
|
|
||||||
|
You could also try setting it up so that you can manually input more rolls. that way you can just leave the program open and every time you want to roll more dice, you just type it in and hit enter.
|
||||||
|
|
||||||
|
# Credit
|
||||||
|
|
||||||
|
This challenge was suggested by user /u/Fishy_Mc_Fish_Face, many thanks!
|
||||||
|
|
||||||
|
Have a good challenge idea? Consider submitting it to [r/dailyprogrammer\_ideas](https://www.reddit.com/r/dailyprogrammer_ideas)
|
177
e_364/src/main.rs
Normal file
177
e_364/src/main.rs
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
/*!
|
||||||
|
# Description
|
||||||
|
|
||||||
|
I love playing D&D with my friends, and my favorite part is creating character sheets \(my DM is notorious for killing us all off by level 3 or so\). One major part of making character sheets is rolling the character's stats. Sadly, I have lost all my dice, so I'm asking for your help to make a dice roller for me to use!
|
||||||
|
|
||||||
|
# Formal Inputs & Outputs
|
||||||
|
|
||||||
|
## Input description
|
||||||
|
|
||||||
|
Your input will contain one or more lines, where each line will be in the form of "NdM"; for example:
|
||||||
|
|
||||||
|
3d6
|
||||||
|
4d12
|
||||||
|
1d10
|
||||||
|
5d4
|
||||||
|
|
||||||
|
If you've ever played D&D you probably recognize those, but for the rest of you, this is what those mean:
|
||||||
|
|
||||||
|
The first number is the number of dice to roll, the d just means "dice", it's just used to split up the two numbers, and the second number is how many sides the dice have. So the above example of "3d6" means "roll 3 6\-sided dice". Also, just in case you didn't know, in D&D, not all the dice we roll are the normal cubes. A d6 is a cube, because it's a 6\-sided die, but a d20 has twenty sides, so it looks a lot closer to a ball than a cube.
|
||||||
|
|
||||||
|
The first number, the number of dice to roll, can be any integer between 1 and 100, inclusive.
|
||||||
|
|
||||||
|
The second number, the number of sides of the dice, can be any integer between 2 and 100, inclusive.
|
||||||
|
|
||||||
|
## Output description
|
||||||
|
|
||||||
|
You should output the sum of all the rolls of that specified die, each on their own line. so if your input is "3d6", the output should look something like
|
||||||
|
|
||||||
|
14
|
||||||
|
|
||||||
|
Just a single number, you rolled 3 6\-sided dice, and they added up to 14.
|
||||||
|
|
||||||
|
# Challenge Input
|
||||||
|
|
||||||
|
5d12
|
||||||
|
6d4
|
||||||
|
1d2
|
||||||
|
1d8
|
||||||
|
3d6
|
||||||
|
4d20
|
||||||
|
100d100
|
||||||
|
|
||||||
|
# Challenge Output
|
||||||
|
|
||||||
|
[some number between 5 and 60, probably closer to 32 or 33]
|
||||||
|
[some number between 6 and 24, probably around 15]
|
||||||
|
[you get the idea]
|
||||||
|
[...]
|
||||||
|
|
||||||
|
# Notes/Hints
|
||||||
|
|
||||||
|
A dice roll is basically the same as picking a random number between 1 and 6 \(or 12, or 20, or however many sides the die has\). You should use some way of randomly selecting a number within a range based off of your input. Many common languages have random number generators available, but at least a few of them will give the same "random" numbers every time you use the program. In my opinion that's not very random. If you run your code 3\+ times with the same inputs and it gives the same outputs, that wouldn't be super useful for a game of D&D, would it? If that happens with your code, try to find a way around that. I'm guessing for some of the newer folks, this might be one of the trickier parts to get correct.
|
||||||
|
|
||||||
|
Don't just multiply your roll by the number of dice, please. I don't know if any of you were thinking about doing that, but I was. The problem is that if you do that, it eliminates a lot of possible values. For example, there's no way to roll 14 from 3d6 if you just roll it once and multiply by 3. Setting up a loop to roll each die is probably your best bet here.
|
||||||
|
|
||||||
|
# Bonus
|
||||||
|
|
||||||
|
In addition to the sum of all dice rolls for your output, print out the result of each roll on the same line, using a format that looks something like
|
||||||
|
|
||||||
|
14: 6 3 5
|
||||||
|
22: 10 7 1 4
|
||||||
|
9: 9
|
||||||
|
11: 3 2 2 1 3
|
||||||
|
|
||||||
|
You could also try setting it up so that you can manually input more rolls. that way you can just leave the program open and every time you want to roll more dice, you just type it in and hit enter.
|
||||||
|
|
||||||
|
# Credit
|
||||||
|
|
||||||
|
This challenge was suggested by user /u/Fishy_Mc_Fish_Face, many thanks!
|
||||||
|
|
||||||
|
Have a good challenge idea? Consider submitting it to [r/dailyprogrammer\_ideas](https://www.reddit.com/r/dailyprogrammer_ideas)
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
use rand::Rng;
|
||||||
|
use std::fmt;
|
||||||
|
use std::fs;
|
||||||
|
use std::num::ParseIntError;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
/// Dice struct for tabletop-style dice use
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// A `3d6` can be represented as the following:
|
||||||
|
/// ```
|
||||||
|
/// Dice {
|
||||||
|
/// count: 3,
|
||||||
|
/// die: 6,
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
struct Dice {
|
||||||
|
count: u32,
|
||||||
|
die: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Error type for the Dice struct
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
enum DiceError {
|
||||||
|
ParseInt(std::num::ParseIntError),
|
||||||
|
ParseFields,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for DiceError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
DiceError::ParseInt(int_error) => write!(f, "Invalid integer: {:?}", int_error),
|
||||||
|
DiceError::ParseFields => write!(f, "Incorrect number of fields"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Dice {
|
||||||
|
type Err = DiceError;
|
||||||
|
fn from_str(s: &str) -> Result<Dice, Self::Err> {
|
||||||
|
// Split string at "d" delimeter, parse elements into Dice struct containing u32s
|
||||||
|
let dice = s
|
||||||
|
.split("d")
|
||||||
|
.map(|x| x.parse::<u32>())
|
||||||
|
.collect::<Result<Vec<u32>, ParseIntError>>();
|
||||||
|
let dice = match dice {
|
||||||
|
Ok(d) => d,
|
||||||
|
Err(e) => return Err(DiceError::ParseInt(e)),
|
||||||
|
};
|
||||||
|
let dice = match dice.as_slice() {
|
||||||
|
[count, die] => Dice {
|
||||||
|
count: *count,
|
||||||
|
die: *die,
|
||||||
|
},
|
||||||
|
_ => return Err(DiceError::ParseFields),
|
||||||
|
};
|
||||||
|
Ok(dice)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dice {
|
||||||
|
/// Takes a `Dice` and rolls them, returning a u32 with the resulting total.
|
||||||
|
fn roll_dice(&self) -> u32 {
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
rng.gen_range(1..=self.die) * self.count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
e_364();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Main exercise loop
|
||||||
|
fn e_364() {
|
||||||
|
let input = fs::read_to_string("input.txt").unwrap();
|
||||||
|
let dice: Result<Vec<Dice>, DiceError> = input.split("\n").map(|x| x.parse()).collect();
|
||||||
|
match dice {
|
||||||
|
Ok(d) => d.iter().for_each(|x| println!("{}", x.roll_dice())),
|
||||||
|
Err(DiceError::ParseInt(e)) => eprintln!("Could not parse integer: {:?}", e),
|
||||||
|
Err(DiceError::ParseFields) => eprintln!("Could not parse dice fields!"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_dice() {
|
||||||
|
assert_eq!(("3d6").parse::<Dice>().unwrap(), Dice { count: 3, die: 6 });
|
||||||
|
assert_eq!(
|
||||||
|
("16d2").parse::<Dice>().unwrap(),
|
||||||
|
Dice { count: 16, die: 2 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_error_handling() {
|
||||||
|
assert!(matches!("3dx".parse::<Dice>(), Err(DiceError::ParseInt(_))));
|
||||||
|
assert_eq!("3d3d3".parse::<Dice>(), Err(DiceError::ParseFields));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue