diff --git a/config.json b/config.json
index 3ad25420c..e1a1d56f5 100644
--- a/config.json
+++ b/config.json
@@ -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": [
diff --git a/exercises/practice/dnd-character/.docs/instructions.md b/exercises/practice/dnd-character/.docs/instructions.md
new file mode 100644
index 000000000..b0a603591
--- /dev/null
+++ b/exercises/practice/dnd-character/.docs/instructions.md
@@ -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
diff --git a/exercises/practice/dnd-character/.gitignore b/exercises/practice/dnd-character/.gitignore
new file mode 100644
index 000000000..e24ae5981
--- /dev/null
+++ b/exercises/practice/dnd-character/.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/practice/dnd-character/.meta/config.json b/exercises/practice/dnd-character/.meta/config.json
new file mode 100644
index 000000000..592afd784
--- /dev/null
+++ b/exercises/practice/dnd-character/.meta/config.json
@@ -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"
+}
diff --git a/exercises/practice/dnd-character/.meta/example.rs b/exercises/practice/dnd-character/.meta/example.rs
new file mode 100644
index 000000000..6c1ce8909
--- /dev/null
+++ b/exercises/practice/dnd-character/.meta/example.rs
@@ -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()
+    }
+}
diff --git a/exercises/practice/dnd-character/.meta/tests.toml b/exercises/practice/dnd-character/.meta/tests.toml
new file mode 100644
index 000000000..2b04dd335
--- /dev/null
+++ b/exercises/practice/dnd-character/.meta/tests.toml
@@ -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"
diff --git a/exercises/practice/dnd-character/Cargo.toml b/exercises/practice/dnd-character/Cargo.toml
new file mode 100644
index 000000000..cd42fb7c2
--- /dev/null
+++ b/exercises/practice/dnd-character/Cargo.toml
@@ -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"
diff --git a/exercises/practice/dnd-character/src/lib.rs b/exercises/practice/dnd-character/src/lib.rs
new file mode 100644
index 000000000..e3bd995ac
--- /dev/null
+++ b/exercises/practice/dnd-character/src/lib.rs
@@ -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,
+}
+
+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")
+    }
+}
diff --git a/exercises/practice/dnd-character/tests/dnd-character.rs b/exercises/practice/dnd-character/tests/dnd-character.rs
new file mode 100644
index 000000000..9248c1df6
--- /dev/null
+++ b/exercises/practice/dnd-character/tests/dnd-character.rs
@@ -0,0 +1,183 @@
+use dnd_character::*;
+
+#[test]
+fn test_ability_modifier_for_score_3_is_4() {
+    let input = 3;
+    let expected: f32 = -4.0;
+    assert_eq!(modifier(input), expected);
+}
+
+#[test]
+#[ignore]
+fn test_ability_modifier_for_score_4_is_3() {
+    let input = 4;
+    let expected: f32 = -3.0;
+    assert_eq!(modifier(input), expected);
+}
+
+#[test]
+#[ignore]
+fn test_ability_modifier_for_score_5_is_3() {
+    let input = 5;
+    let expected: f32 = -3.0;
+    assert_eq!(modifier(input), expected);
+}
+
+#[test]
+#[ignore]
+fn test_ability_modifier_for_score_6_is_2() {
+    let input = 6;
+    let expected: f32 = -2.0;
+    assert_eq!(modifier(input), expected);
+}
+
+#[test]
+#[ignore]
+fn test_ability_modifier_for_score_7_is_2() {
+    let input = 7;
+    let expected: f32 = -2.0;
+    assert_eq!(modifier(input), expected);
+}
+
+#[test]
+#[ignore]
+fn test_ability_modifier_for_score_8_is_1() {
+    let input = 8;
+    let expected: f32 = -1.0;
+    assert_eq!(modifier(input), expected);
+}
+
+#[test]
+#[ignore]
+fn test_ability_modifier_for_score_9_is_1() {
+    let input = 9;
+    let expected: f32 = -1.0;
+    assert_eq!(modifier(input), expected);
+}
+
+#[test]
+#[ignore]
+fn test_ability_modifier_for_score_10_is_0() {
+    let input = 10;
+    let expected: f32 = 0.0;
+    assert_eq!(modifier(input), expected);
+}
+
+#[test]
+#[ignore]
+fn test_ability_modifier_for_score_11_is_0() {
+    let input = 11;
+    let expected: f32 = 0.0;
+    assert_eq!(modifier(input), expected);
+}
+
+#[test]
+#[ignore]
+fn test_ability_modifier_for_score_12_is_1() {
+    let input = 12;
+    let expected: f32 = 1.0;
+    assert_eq!(modifier(input), expected);
+}
+
+#[test]
+#[ignore]
+fn test_ability_modifier_for_score_13_is_1() {
+    let input = 13;
+    let expected: f32 = 1.0;
+    assert_eq!(modifier(input), expected);
+}
+
+#[test]
+#[ignore]
+fn test_ability_modifier_for_score_14_is_2() {
+    let input = 14;
+    let expected: f32 = 2.0;
+    assert_eq!(modifier(input), expected);
+}
+
+#[test]
+#[ignore]
+fn test_ability_modifier_for_score_15_is_2() {
+    let input = 15;
+    let expected: f32 = 2.0;
+    assert_eq!(modifier(input), expected);
+}
+
+#[test]
+#[ignore]
+fn test_ability_modifier_for_score_16_is_3() {
+    let input = 16;
+    let expected: f32 = 3.0;
+    assert_eq!(modifier(input), expected);
+}
+
+#[test]
+#[ignore]
+fn test_ability_modifier_for_score_17_is_3() {
+    let input = 17;
+    let expected: f32 = 3.0;
+    assert_eq!(modifier(input), expected);
+}
+
+#[test]
+#[ignore]
+fn test_ability_modifier_for_score_18_is_4() {
+    let input = 18;
+    let expected: f32 = 4.0;
+    assert_eq!(modifier(input), expected);
+}
+
+#[test]
+#[ignore]
+fn test_random_ability_is_within_range() {
+    let score = Character::calculate_ability_score(Character::roll_four_dice());
+    assert!((3..=18).contains(&score));
+}
+
+#[test]
+#[ignore]
+fn test_random_character_is_valid() {
+    let character = Character::new();
+    assert!((3..=18).contains(&character.strength));
+    assert!((3..=18).contains(&character.dexterity));
+    assert!((3..=18).contains(&character.constitution));
+    assert!((3..=18).contains(&character.intelligence));
+    assert!((3..=18).contains(&character.wisdom));
+    assert!((3..=18).contains(&character.charisma));
+    assert_eq!(
+        character.hitpoints,
+        10 + modifier(character.constitution) as u8
+    );
+}
+
+#[test]
+#[ignore]
+fn test_dice_are_rolled_for_each_stat() {
+    // there is a low chance that this might be equal
+    let character = Character::new();
+    assert_ne!(
+        (
+            character.strength,
+            character.dexterity,
+            character.constitution,
+            character.intelligence,
+            character.wisdom,
+            character.charisma
+        ),
+        (
+            character.strength,
+            character.strength,
+            character.strength,
+            character.strength,
+            character.strength,
+            character.strength
+        )
+    );
+}
+
+#[test]
+#[ignore]
+fn test_each_ability_is_only_calculated_once() {
+    let character = Character::new();
+    assert_eq!(character.strength, character.strength);
+}