-
Notifications
You must be signed in to change notification settings - Fork 519
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
Add D&D Character exercise #1666
base: main
Are you sure you want to change the base?
Changes from 14 commits
6a9f81d
bd24a13
6e69740
b75d4e6
62570bb
88fb1c4
a93d31a
912b761
23bbd89
81fce76
f49433e
20f9f83
004db46
2e25f85
d3843c4
fd9a12c
c2bdc3b
2d99477
5ac82f2
dceaa30
5ec087e
ed1112a
226a0e7
66e74eb
82e2081
1336170
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 |
---|---|---|
@@ -1,7 +1,6 @@ | ||
#[test] | ||
#[ignore] | ||
fn ${description}$() { | ||
|
||
assert_eq!(${property}$(${input}$), ${expected}$); | ||
let expected = "${expected}$"; | ||
assert_eq!(${property}$(${input}$), expected); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# Instructions | ||
|
||
For a game of [Dungeons & Dragons][dnd], each player starts by generating a character they can play with. | ||
This character has, among other things, six abilities; strength, dexterity, constitution, intelligence, wisdom and charisma. | ||
These six abilities have scores that are determined randomly. | ||
You do this by rolling four 6-sided dice and record the sum of the largest three dice. | ||
You do this six times, once for each ability. | ||
|
||
Your character's initial hitpoints are 10 + your character's constitution modifier. | ||
You find your character's constitution modifier by subtracting 10 from your character's constitution, divide by 2 and round down. | ||
|
||
Write a random character generator that follows the rules above. | ||
|
||
For example, the six throws of four dice may look like: | ||
|
||
- 5, 3, 1, 6: You discard the 1 and sum 5 + 3 + 6 = 14, which you assign to strength. | ||
- 3, 2, 5, 3: You discard the 2 and sum 3 + 5 + 3 = 11, which you assign to dexterity. | ||
- 1, 1, 1, 1: You discard the 1 and sum 1 + 1 + 1 = 3, which you assign to constitution. | ||
- 2, 1, 6, 6: You discard the 1 and sum 2 + 6 + 6 = 14, which you assign to intelligence. | ||
- 3, 5, 3, 4: You discard the 3 and sum 5 + 3 + 4 = 12, which you assign to wisdom. | ||
- 6, 6, 6, 6: You discard the 6 and sum 6 + 6 + 6 = 18, which you assign to charisma. | ||
|
||
Because constitution is 3, the constitution modifier is -4 and the hitpoints are 6. | ||
|
||
## Notes | ||
|
||
Most programming languages feature (pseudo-)random generators, but few programming languages are designed to roll dice. | ||
One such language is [Troll][troll]. | ||
|
||
[dnd]: https://en.wikipedia.org/wiki/Dungeons_%26_Dragons | ||
[troll]: https://di.ku.dk/Ansatte/?pure=da%2Fpublications%2Ftroll-a-language-for-specifying-dicerolls(84a45ff0-068b-11df-825d-000ea68e967b)%2Fexport.html |
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,20 @@ | ||
{ | ||
"authors": [ | ||
"dem4ron" | ||
], | ||
"files": { | ||
"solution": [ | ||
"src/lib.rs", | ||
"Cargo.toml" | ||
], | ||
"test": [ | ||
"tests/dnd-character.rs" | ||
], | ||
"example": [ | ||
".meta/example.rs" | ||
] | ||
}, | ||
"blurb": "Randomly generate Dungeons & Dragons characters.", | ||
"source": "Simon Shine, Erik Schierboom", | ||
"source_url": "https://github.com/exercism/problem-specifications/issues/616#issuecomment-437358945" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
use rand::prelude::*; | ||
|
||
pub fn modifier(ability_score: u8) -> f32 { | ||
((ability_score as i8 - 10) as f32 / 2.0).floor() | ||
} | ||
|
||
pub struct Character { | ||
strength: u8, | ||
dexterity: u8, | ||
constitution: u8, | ||
intelligence: u8, | ||
wisdom: u8, | ||
charisma: u8, | ||
hitpoints: u8, | ||
} | ||
|
||
impl Character { | ||
pub fn new() -> Self { | ||
let constitution = Character::calculate_ability_score(Character::roll_four_dice()); | ||
Character { | ||
strength: Character::calculate_ability_score(Character::roll_four_dice()), | ||
dexterity: Character::calculate_ability_score(Character::roll_four_dice()), | ||
constitution, | ||
intelligence: Character::calculate_ability_score(Character::roll_four_dice()), | ||
wisdom: Character::calculate_ability_score(Character::roll_four_dice()), | ||
charisma: Character::calculate_ability_score(Character::roll_four_dice()), | ||
hitpoints: 10 + modifier(constitution) as u8, | ||
} | ||
} | ||
|
||
pub fn roll_four_dice() -> [u8; 4] { | ||
let mut rng = thread_rng(); | ||
let mut rolls = [0; 4]; | ||
for i in 0..4 { | ||
rolls[i] = rng.gen_range(1..=4) | ||
} | ||
rolls | ||
} | ||
|
||
pub fn calculate_ability_score(ability_dice_rolls: [u8; 4]) -> u8 { | ||
let mut ability_dice_rolls = ability_dice_rolls; | ||
ability_dice_rolls.sort(); | ||
ability_dice_rolls[1..].iter().sum() | ||
} | ||
|
||
pub fn strength(&self) -> u8 { | ||
self.strength | ||
} | ||
|
||
pub fn dexterity(&self) -> u8 { | ||
self.dexterity | ||
} | ||
|
||
pub fn constitution(&self) -> u8 { | ||
self.constitution | ||
} | ||
|
||
pub fn intelligence(&self) -> u8 { | ||
self.intelligence | ||
} | ||
|
||
pub fn wisdom(&self) -> u8 { | ||
self.wisdom | ||
} | ||
|
||
pub fn charisma(&self) -> u8 { | ||
self.charisma | ||
} | ||
|
||
pub fn hitpoints(&self) -> u8 { | ||
self.hitpoints | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# This is an auto-generated file. | ||
# | ||
# Regenerating this file via `configlet sync` will: | ||
# - Recreate every `description` key/value pair | ||
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications | ||
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) | ||
# - Preserve any other key/value pair | ||
# | ||
# As user-added comments (using the # character) will be removed when this file | ||
# is regenerated, comments can be added via a `comment` key. | ||
|
||
[1e9ae1dc-35bd-43ba-aa08-e4b94c20fa37] | ||
description = "ability modifier -> ability modifier for score 3 is -4" | ||
|
||
[cc9bb24e-56b8-4e9e-989d-a0d1a29ebb9c] | ||
description = "ability modifier -> ability modifier for score 4 is -3" | ||
|
||
[5b519fcd-6946-41ee-91fe-34b4f9808326] | ||
description = "ability modifier -> ability modifier for score 5 is -3" | ||
|
||
[dc2913bd-6d7a-402e-b1e2-6d568b1cbe21] | ||
description = "ability modifier -> ability modifier for score 6 is -2" | ||
|
||
[099440f5-0d66-4b1a-8a10-8f3a03cc499f] | ||
description = "ability modifier -> ability modifier for score 7 is -2" | ||
|
||
[cfda6e5c-3489-42f0-b22b-4acb47084df0] | ||
description = "ability modifier -> ability modifier for score 8 is -1" | ||
|
||
[c70f0507-fa7e-4228-8463-858bfbba1754] | ||
description = "ability modifier -> ability modifier for score 9 is -1" | ||
|
||
[6f4e6c88-1cd9-46a0-92b8-db4a99b372f7] | ||
description = "ability modifier -> ability modifier for score 10 is 0" | ||
|
||
[e00d9e5c-63c8-413f-879d-cd9be9697097] | ||
description = "ability modifier -> ability modifier for score 11 is 0" | ||
|
||
[eea06f3c-8de0-45e7-9d9d-b8cab4179715] | ||
description = "ability modifier -> ability modifier for score 12 is +1" | ||
|
||
[9c51f6be-db72-4af7-92ac-b293a02c0dcd] | ||
description = "ability modifier -> ability modifier for score 13 is +1" | ||
|
||
[94053a5d-53b6-4efc-b669-a8b5098f7762] | ||
description = "ability modifier -> ability modifier for score 14 is +2" | ||
|
||
[8c33e7ca-3f9f-4820-8ab3-65f2c9e2f0e2] | ||
description = "ability modifier -> ability modifier for score 15 is +2" | ||
|
||
[c3ec871e-1791-44d0-b3cc-77e5fb4cd33d] | ||
description = "ability modifier -> ability modifier for score 16 is +3" | ||
|
||
[3d053cee-2888-4616-b9fd-602a3b1efff4] | ||
description = "ability modifier -> ability modifier for score 17 is +3" | ||
|
||
[bafd997a-e852-4e56-9f65-14b60261faee] | ||
description = "ability modifier -> ability modifier for score 18 is +4" | ||
|
||
[4f28f19c-2e47-4453-a46a-c0d365259c14] | ||
description = "random ability is within range" | ||
|
||
[385d7e72-864f-4e88-8279-81a7d75b04ad] | ||
description = "random character is valid" | ||
|
||
[2ca77b9b-c099-46c3-a02c-0d0f68ffa0fe] | ||
description = "each ability is only calculated once" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
[package] | ||
name = "dnd_character" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
rand = "0.8.5" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
pub fn modifier(_ability_score: u8) -> f32 { | ||
unimplemented!("Implement a utility function that calculates the ability modifier for a given ability score") | ||
} | ||
|
||
pub struct Character {} | ||
|
||
impl Character { | ||
pub fn new() -> Self { | ||
unimplemented!("Create a function that generates a new random character with the following ability scores and hitpoints") | ||
} | ||
|
||
pub fn roll_four_dice() -> [u8; 4] { | ||
unimplemented!("Create a utility function that rolls four dice") | ||
} | ||
|
||
pub fn calculate_ability_score(_ability_dice_rolls: [u8; 4]) -> u8 { | ||
unimplemented!("Calculate the ability score from the given rolled dice") | ||
} | ||
|
||
pub fn strength(&self) -> u8 { | ||
unimplemented!("Return the strength score of the character") | ||
} | ||
|
||
pub fn dexterity(&self) -> u8 { | ||
unimplemented!("Return the dexterity score of the character") | ||
} | ||
|
||
pub fn constitution(&self) -> u8 { | ||
unimplemented!("Return the constitution score of the character") | ||
} | ||
|
||
pub fn intelligence(&self) -> u8 { | ||
unimplemented!("Return the intelligence score of the character") | ||
} | ||
|
||
pub fn wisdom(&self) -> u8 { | ||
unimplemented!("Return the wisdom score of the character") | ||
} | ||
|
||
pub fn charisma(&self) -> u8 { | ||
unimplemented!("Return the charisma score of the character") | ||
} | ||
|
||
pub fn hitpoints(&self) -> u8 { | ||
unimplemented!("Return the hitpoints of the character") | ||
} | ||
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. I'm slightly torn whether these methods are a good or a bad idea.
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. true about the downside, but I think it is challenging to avoid boilerplate code in this exercise, given its classic object-oriented nature. I personally enjoy having these getter methods, as it's allowing me to access attributes like on the other hand it is a perfect spot to write a macro, as I just did in the updated example file. 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. I'll let @petertseng weigh in. The methods seem like overkill to me over regular struct access, but 🤷 |
||
} |
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.
Did you consider having just one
random_ability
/generate_ability
/random_ability_score
function?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.
These functions could also be moved outside of the
Character
'simpl
, as they don't rely on the character.