Skip to content
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

Open
wants to merge 26 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
6a9f81d
Merge branch 'exercism:main' into main
dem4ron Mar 14, 2023
bd24a13
Merge branch 'exercism:main' into main
dem4ron Mar 14, 2023
6e69740
Merge branch 'exercism:main' into main
dem4ron Apr 1, 2023
b75d4e6
Add difficulty as int, further format fn name
dem4ron Apr 3, 2023
62570bb
Add util fn to escape double quotes
dem4ron Apr 3, 2023
88fb1c4
Simplify escape double quotes algo
dem4ron Apr 3, 2023
a93d31a
Add missing end line
dem4ron Apr 3, 2023
912b761
Add dnd character exercise
dem4ron Apr 4, 2023
23bbd89
Change wording
dem4ron Apr 5, 2023
81fce76
Remove first ignore
dem4ron Apr 5, 2023
f49433e
Format example, improve one test
dem4ron Apr 5, 2023
20f9f83
Better parameters
dem4ron Apr 5, 2023
004db46
Same for stub file
dem4ron Apr 5, 2023
2e25f85
Improve valid char test case
dem4ron Apr 5, 2023
d3843c4
Merge branch 'exercism:main' into main
dem4ron Apr 7, 2023
fd9a12c
Merge branch 'main' into add-dnd-character
dem4ron Apr 7, 2023
c2bdc3b
Improve exemplar solution
dem4ron Apr 7, 2023
2d99477
Rename macro
dem4ron Apr 7, 2023
5ac82f2
Improve last test, add missing end line
dem4ron Apr 7, 2023
dceaa30
Merge branch 'exercism:main' into main
dem4ron Apr 7, 2023
5ec087e
Simplify exercise
dem4ron Apr 7, 2023
ed1112a
Merge branch 'main' of https://github.com/exercism/rust
dem4ron Apr 7, 2023
226a0e7
Merge branch 'main' of https://github.com/dem4ron/rust-exercism
dem4ron Apr 7, 2023
66e74eb
Merge branch 'main' into add-dnd-character
dem4ron Apr 7, 2023
82e2081
Fill in struct details in stub file
dem4ron Apr 7, 2023
1336170
Fix exemplar's struct
dem4ron Apr 8, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -1515,6 +1515,15 @@
"practices": [],
"prerequisites": [],
"difficulty": 1
},
{
"slug": "dnd-character",
"name": "D&D Character",
"uuid": "8f52127a-ad81-46a2-b734-a76117138aae",
"practices": [],
"prerequisites": [],
"difficulty": 1,
"topics":["structs", "randomness"]
}
],
"foregone": [
Expand Down
31 changes: 31 additions & 0 deletions exercises/practice/dnd-character/.docs/instructions.md
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
8 changes: 8 additions & 0 deletions exercises/practice/dnd-character/.gitignore
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
20 changes: 20 additions & 0 deletions exercises/practice/dnd-character/.meta/config.json
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"
}
45 changes: 45 additions & 0 deletions exercises/practice/dnd-character/.meta/example.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use rand::prelude::*;

pub fn modifier(ability_score: u8) -> f32 {
((ability_score as i8 - 10) as f32 / 2.0).floor()
}

pub struct Character {
pub strength: u8,
pub dexterity: u8,
pub constitution: u8,
pub intelligence: u8,
pub wisdom: u8,
pub charisma: u8,
pub 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()
}
Comment on lines +31 to +44
Copy link
Member

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?

Copy link
Member

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's impl, as they don't rely on the character.

}
67 changes: 67 additions & 0 deletions exercises/practice/dnd-character/.meta/tests.toml
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"
9 changes: 9 additions & 0 deletions exercises/practice/dnd-character/Cargo.toml
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"
27 changes: 27 additions & 0 deletions exercises/practice/dnd-character/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
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 {
pub strength: u8,
pub dexterity: u8,
pub constitution: u8,
pub intelligence: u8,
pub wisdom: u8,
pub charisma: u8,
pub hitpoints: u8,
Comment on lines +6 to +12
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Much cleaner!

}

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")
}
}
Loading