diff --git a/exercises/practice/dnd-character/.meta/example.go b/exercises/practice/dnd-character/.meta/example.go index ec19888f8..0f552b80f 100644 --- a/exercises/practice/dnd-character/.meta/example.go +++ b/exercises/practice/dnd-character/.meta/example.go @@ -1,3 +1,62 @@ package dndcharacter -// TODO: make an actual example that passes the test +import ( + "math" + "math/rand" + "slices" +) + +type CharacterSheet struct { + Strength int + Dexterity int + Constitution int + Intelligence int + Wisdom int + Charisma int + Hitpoints int +} + +// Modifier should calculate the correct modifier for a given score +func Modifier(score int) int { + return int(math.Floor(float64(score-10) / 2.0)) +} + +// Ability should generate the score for a random ability +func Ability() int { + var scores []int + + for i := 0; i < 4; i++ { + roll := RollDice() + scores = append(scores, roll) + } + + return CalculateAbilityScore(scores) +} + +// Character should return a CharacterSheet with valid ability scores +func Character() CharacterSheet { + return CharacterSheet{ + Strength: Ability(), + Dexterity: Ability(), + Constitution: Ability(), + Intelligence: Ability(), + Wisdom: Ability(), + Charisma: Ability(), + Hitpoints: 10 + Modifier(Ability()), + } +} + +// CalculateAbilityScore expects an array of 4 dice scores and returns the sum of the 3 highest numbers +func CalculateAbilityScore(scores []int) int { + var sum int + + for _, score := range scores { + sum += score + } + + return sum - slices.Min(scores) +} + +func RollDice() int { + return rand.Intn(6) + 1 +} diff --git a/exercises/practice/dnd-character/dnd_character.go b/exercises/practice/dnd-character/dnd_character.go index d26e7b6fd..ccb5c2f16 100644 --- a/exercises/practice/dnd-character/dnd_character.go +++ b/exercises/practice/dnd-character/dnd_character.go @@ -1,37 +1,31 @@ -// TODO: -// include a comment in each function briefly explaining what the function should do. This is a bit of quality of life for -// students, to help them know which part of the instructions that function should implement. - -// One thing that slightly annoys me in this exercise is that the instructions mention that to get the value for an ability, -// you should roll 4 dice, discard the worst result and sum the 3 best dice rolls. But with the functions we have currently -// (which are the ones most tracks have), that logic is never enforced or tested anywhere. I think it would make sense to -// make students write a function (which would be included in the skeleton given to them) that should take an array of 4 -// elements, or receive 4 arguments, and return the sum of the 3 biggest ones. -// We could then also write manual tests for this function. - package dndcharacter type CharacterSheet struct { - Strength string - Dexterity string - Constitution string - Intelligence string - Wisdom string - Charisma string - Hitpoints string + Strength int + Dexterity int + Constitution int + Intelligence int + Wisdom int + Charisma int + Hitpoints int } -// Modifier +// Modifier should calculate the correct modifier for a given score func Modifier(score int) int { panic("Please implement the 'Modifier' function") } -// Ability -func Ability() string { +// Ability should generate the score for a random ability +func Ability() int { panic("Please implement the 'Ability' function") } -// Character +// Character should return a CharacterSheet with valid ability scores func Character() CharacterSheet { panic("Please implement the 'Character' function") } + +// CalculateAbilityScore expects an array of 4 dice scores and returns the sum of the 3 highest numbers +func CalculateAbilityScore(scores []int) int { + panic("Please implement the 'CalculateAbilityScore' function") +} diff --git a/exercises/practice/dnd-character/dnd_character_test.go b/exercises/practice/dnd-character/dnd_character_test.go index f9557252b..5d2cae25b 100644 --- a/exercises/practice/dnd-character/dnd_character_test.go +++ b/exercises/practice/dnd-character/dnd_character_test.go @@ -1,4 +1,3 @@ -// TODO: implement test cases package dndcharacter import "testing" @@ -15,11 +14,31 @@ func TestModifier(t *testing.T) { } func TestAbility(t *testing.T) { - + for i := 0; i < 10; i++ { + t.Run("", func(t *testing.T) { + got := Ability() + if !inAcceptedRange(got) { + t.Fatal("Ability score is not within accepted range (3-18)") + } + }) + } } func TestCharacter(t *testing.T) { + t.Run("should generate a character sheet with random ability scores", func(t *testing.T) { + character := Character() + + assertAbilityScoreInRange(t, "Charisma", character.Charisma) + assertAbilityScoreInRange(t, "Strength", character.Strength) + assertAbilityScoreInRange(t, "Dexterity", character.Dexterity) + assertAbilityScoreInRange(t, "Wisdom", character.Wisdom) + assertAbilityScoreInRange(t, "Intelligence", character.Intelligence) + assertAbilityScoreInRange(t, "Constitution", character.Constitution) + if character.Hitpoints < 10 { + t.Fatalf("Character's base hitpoints are incorrect. Got %d", character.Hitpoints) + } + }) } func BenchmarkAbility(b *testing.B) { @@ -39,3 +58,15 @@ func BenchmarkModifier(b *testing.B) { Modifier(i) } } + +func inAcceptedRange(score int) bool { + return score >= 3 && score <= 18 +} + +func assertAbilityScoreInRange(t testing.TB, ability string, score int) { + t.Helper() + + if !inAcceptedRange(score) { + t.Fatalf("%s score is not withing accepted range. Got %d", ability, score) + } +}