Skip to content

Commit

Permalink
implement Modifier
Browse files Browse the repository at this point in the history
  • Loading branch information
rootulp committed May 9, 2024
1 parent ac8b725 commit cb8554c
Show file tree
Hide file tree
Showing 8 changed files with 376 additions and 0 deletions.
21 changes: 21 additions & 0 deletions go/dnd-character/.exercism/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"authors": ["jesse-kroon"],
"contributors": ["andrerfcsantos"],
"files": {
"solution": [
"dnd_character.go"
],
"test": [
"dnd_character_test.go"
],
"editor": [
"cases_test.go"
],
"example": [
".meta/example.go"
]
},
"blurb": "Randomly generate Dungeons & Dragons characters.",
"source": "Simon Shine, Erik Schierboom",
"source_url": "https://github.com/exercism/problem-specifications/issues/616#issuecomment-437358945"
}
1 change: 1 addition & 0 deletions go/dnd-character/.exercism/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"track":"go","exercise":"dnd-character","id":"717a81ad216c4bc59e90d083c5d10517","url":"https://exercism.org/tracks/go/exercises/dnd-character","handle":"rootulp","is_requester":true,"auto_approve":false}
41 changes: 41 additions & 0 deletions go/dnd-character/HELP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Help

## Running the tests

To run the tests run the command `go test` from within the exercise directory.

If the test suite contains benchmarks, you can run these with the `--bench` and `--benchmem`
flags:

go test -v --bench . --benchmem

Keep in mind that each reviewer will run benchmarks on a different machine, with
different specs, so the results from these benchmark tests may vary.

## Submitting your solution

You can submit your solution using the `exercism submit dnd_character.go` 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 [Go track's documentation](https://exercism.org/docs/tracks/go)
- The [Go track's programming category on the forum](https://forum.exercism.org/c/programming/go)
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)

Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.

To get help if you're having trouble, you can use one of the following resources:

- [How to Write Go Code](https://golang.org/doc/code.html)
- [Effective Go](https://golang.org/doc/effective_go.html)
- [Go Resources](http://golang.org/help)
- [StackOverflow](http://stackoverflow.com/questions/tagged/go)
62 changes: 62 additions & 0 deletions go/dnd-character/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# D&D Character

Welcome to D&D Character on Exercism's Go Track.
If you need help running the tests or submitting your code, check out `HELP.md`.

## Introduction

After weeks of anticipation, you and your friends get together for your very first game of [Dungeons & Dragons][dnd] (D&D).
Since this is the first session of the game, each player has to generate a character to play with.
The character's abilities are determined by rolling 6-sided dice, but where _are_ the dice?
With a shock, you realize that your friends are waiting for _you_ to produce the dice; after all it was your idea to play D&D!
Panicking, you realize you forgot to bring the dice, which would mean no D&D game.
As you have some basic coding skills, you quickly come up with a solution: you'll write a program to simulate dice rolls.

[dnd]: https://en.wikipedia.org/wiki/Dungeons_%26_Dragons

## 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 recording 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 above rules.

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.

~~~~exercism/note
Most programming languages feature (pseudo-)random generators, but few programming languages are designed to roll dice.
One such language is [Troll][troll].
[troll]: https://di.ku.dk/Ansatte/?pure=da%2Fpublications%2Ftroll-a-language-for-specifying-dicerolls(84a45ff0-068b-11df-825d-000ea68e967b)%2Fexport.html
~~~~

[dnd]: https://en.wikipedia.org/wiki/Dungeons_%26_Dragons

## Source

### Created by

- @jesse-kroon

### Contributed to by

- @andrerfcsantos

### Based on

Simon Shine, Erik Schierboom - https://github.com/exercism/problem-specifications/issues/616#issuecomment-437358945
145 changes: 145 additions & 0 deletions go/dnd-character/cases_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package dndcharacter

// This is an auto-generated file. Do not change it manually. Run the generator to update the file.
// See https://github.com/exercism/go#synchronizing-tests-and-instructions
// Source: exercism/problem-specifications
// Commit: 02209d7 Reimplement test case in DnD Character (#2338)

type modifierTestInput struct {
Score int
}

var modifierTests = []struct {
description string
input modifierTestInput
expected int
}{

{
description: "ability modifier for score 3 is -4",
input: modifierTestInput{
Score: 3,
},
expected: -4,
},

{
description: "ability modifier for score 4 is -3",
input: modifierTestInput{
Score: 4,
},
expected: -3,
},

{
description: "ability modifier for score 5 is -3",
input: modifierTestInput{
Score: 5,
},
expected: -3,
},

{
description: "ability modifier for score 6 is -2",
input: modifierTestInput{
Score: 6,
},
expected: -2,
},

{
description: "ability modifier for score 7 is -2",
input: modifierTestInput{
Score: 7,
},
expected: -2,
},

{
description: "ability modifier for score 8 is -1",
input: modifierTestInput{
Score: 8,
},
expected: -1,
},

{
description: "ability modifier for score 9 is -1",
input: modifierTestInput{
Score: 9,
},
expected: -1,
},

{
description: "ability modifier for score 10 is 0",
input: modifierTestInput{
Score: 10,
},
expected: 0,
},

{
description: "ability modifier for score 11 is 0",
input: modifierTestInput{
Score: 11,
},
expected: 0,
},

{
description: "ability modifier for score 12 is +1",
input: modifierTestInput{
Score: 12,
},
expected: 1,
},

{
description: "ability modifier for score 13 is +1",
input: modifierTestInput{
Score: 13,
},
expected: 1,
},

{
description: "ability modifier for score 14 is +2",
input: modifierTestInput{
Score: 14,
},
expected: 2,
},

{
description: "ability modifier for score 15 is +2",
input: modifierTestInput{
Score: 15,
},
expected: 2,
},

{
description: "ability modifier for score 16 is +3",
input: modifierTestInput{
Score: 16,
},
expected: 3,
},

{
description: "ability modifier for score 17 is +3",
input: modifierTestInput{
Score: 17,
},
expected: 3,
},

{
description: "ability modifier for score 18 is +4",
input: modifierTestInput{
Score: 18,
},
expected: 4,
},
}
28 changes: 28 additions & 0 deletions go/dnd-character/dnd_character.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package dndcharacter

import "math"

type Character struct {
Strength int
Dexterity int
Constitution int
Intelligence int
Wisdom int
Charisma int
Hitpoints int
}

// Modifier calculates the ability modifier for a given ability score
func Modifier(score int) int {
return int(math.Floor(float64(score-10) / 2))
}

// Ability uses randomness to generate the score for an ability
func Ability() int {
panic("Please implement the Ability() function")
}

// GenerateCharacter creates a new Character with random scores for abilities
func GenerateCharacter() Character {
panic("Please implement the GenerateCharacter() function")
}
75 changes: 75 additions & 0 deletions go/dnd-character/dnd_character_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package dndcharacter

import "testing"

func TestModifier(t *testing.T) {
for _, tc := range modifierTests {
t.Run(tc.description, func(t *testing.T) {
actual := Modifier(tc.input.Score)
if actual != tc.expected {
t.Fatalf("Modifier(%d) = %d, want %d", tc.input.Score, actual, tc.expected)
}
})
}
}

func TestAbility(t *testing.T) {
t.Run("should generate ability score within accepted range", func(t *testing.T) {
for i := 0; i < 1000; i++ {
got := Ability()
if !inAcceptedRange(got) {
t.Fatalf("Ability() returned a score for an ability outside the accepted range. Got %d, expected a value between 3 and 18 inclusive.", got)
}
}
})
}

func TestGenerateCharacter(t *testing.T) {
t.Run("should generate a character with random ability scores", func(t *testing.T) {
for i := 0; i < 1000; i++ {
character := GenerateCharacter()

assertCharacterAbilityScoreInRange(t, "Charisma", character.Charisma)
assertCharacterAbilityScoreInRange(t, "Strength", character.Strength)
assertCharacterAbilityScoreInRange(t, "Dexterity", character.Dexterity)
assertCharacterAbilityScoreInRange(t, "Wisdom", character.Wisdom)
assertCharacterAbilityScoreInRange(t, "Intelligence", character.Intelligence)
assertCharacterAbilityScoreInRange(t, "Constitution", character.Constitution)

expectedHitpoints := 10 + Modifier(character.Constitution)
if character.Hitpoints != expectedHitpoints {
t.Fatalf("Got %d hitpoints for a character with %d constitution, expected %d hitpoints", character.Hitpoints, character.Constitution, expectedHitpoints)
}
}
})
}

func inAcceptedRange(score int) bool {
return score >= 3 && score <= 18
}

func assertCharacterAbilityScoreInRange(t *testing.T, ability string, score int) {
t.Helper()

if !inAcceptedRange(score) {
t.Fatalf("GenerateCharacter() created a character with a %s score of %d, but the score for an ability is expected to be between 3 and 18 inclusive", ability, score)
}
}

func BenchmarkModifier(b *testing.B) {
for i := 0; i < b.N; i++ {
Modifier(i)
}
}

func BenchmarkAbility(b *testing.B) {
for i := 0; i < b.N; i++ {
Ability()
}
}

func BenchmarkCharacter(b *testing.B) {
for i := 0; i < b.N; i++ {
GenerateCharacter()
}
}
3 changes: 3 additions & 0 deletions go/dnd-character/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module dnd-character

go 1.18

0 comments on commit cb8554c

Please sign in to comment.