| @@ -0,0 +1,31 @@ | |||
| module DndCharacter | |||
| open System | |||
| let random = Random() | |||
| let diceRoll = (random.Next 5) + 1 | |||
| let modifier x = int (floor (float (x - 10) / 2.0)) | |||
| let ability () = | |||
| List.sum (List.take 3 (List.sortDescending [ for i in 1 .. 4 -> diceRoll ])) | |||
| type Character = | |||
| { Strength: int | |||
| Dexterity: int | |||
| Constitution: int | |||
| Intelligence: int | |||
| Wisdom: int | |||
| Charisma: int | |||
| Hitpoints: int } | |||
| let createCharacter () = | |||
| let constitution = ability () | |||
| { Strength = ability () | |||
| Dexterity = ability () | |||
| Constitution = constitution | |||
| Intelligence = ability () | |||
| Wisdom = ability () | |||
| Charisma = ability () | |||
| Hitpoints = (10 + modifier constitution) } | |||
| @@ -0,0 +1,21 @@ | |||
| <Project Sdk="Microsoft.NET.Sdk"> | |||
| <PropertyGroup> | |||
| <TargetFramework>netcoreapp3.0</TargetFramework> | |||
| <IsPackable>false</IsPackable> | |||
| </PropertyGroup> | |||
| <ItemGroup> | |||
| <Compile Include="DndCharacter.fs" /> | |||
| <Compile Include="DndCharacterTests.fs" /> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" /> | |||
| <PackageReference Include="xunit" Version="2.4.1" /> | |||
| <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" /> | |||
| <PackageReference Include="FsUnit.xUnit" Version="3.8.1" /> | |||
| </ItemGroup> | |||
| </Project> | |||
| @@ -0,0 +1,110 @@ | |||
| // This file was auto-generated based on version 1.1.0 of the canonical data. | |||
| module DndCharacterTests | |||
| open FsUnit.Xunit | |||
| open Xunit | |||
| open DndCharacter | |||
| [<Fact>] | |||
| let ``Ability modifier for score 3 is -4`` () = | |||
| modifier 3 |> should equal -4 | |||
| [<Fact>] | |||
| let ``Ability modifier for score 4 is -3`` () = | |||
| modifier 4 |> should equal -3 | |||
| [<Fact>] | |||
| let ``Ability modifier for score 5 is -3`` () = | |||
| modifier 5 |> should equal -3 | |||
| [<Fact>] | |||
| let ``Ability modifier for score 6 is -2`` () = | |||
| modifier 6 |> should equal -2 | |||
| [<Fact>] | |||
| let ``Ability modifier for score 7 is -2`` () = | |||
| modifier 7 |> should equal -2 | |||
| [<Fact>] | |||
| let ``Ability modifier for score 8 is -1`` () = | |||
| modifier 8 |> should equal -1 | |||
| [<Fact>] | |||
| let ``Ability modifier for score 9 is -1`` () = | |||
| modifier 9 |> should equal -1 | |||
| [<Fact>] | |||
| let ``Ability modifier for score 10 is 0`` () = | |||
| modifier 10 |> should equal 0 | |||
| [<Fact>] | |||
| let ``Ability modifier for score 11 is 0`` () = | |||
| modifier 11 |> should equal 0 | |||
| [<Fact>] | |||
| let ``Ability modifier for score 12 is +1`` () = | |||
| modifier 12 |> should equal 1 | |||
| [<Fact>] | |||
| let ``Ability modifier for score 13 is +1`` () = | |||
| modifier 13 |> should equal 1 | |||
| [<Fact>] | |||
| let ``Ability modifier for score 14 is +2`` () = | |||
| modifier 14 |> should equal 2 | |||
| [<Fact>] | |||
| let ``Ability modifier for score 15 is +2`` () = | |||
| modifier 15 |> should equal 2 | |||
| [<Fact>] | |||
| let ``Ability modifier for score 16 is +3`` () = | |||
| modifier 16 |> should equal 3 | |||
| [<Fact>] | |||
| let ``Ability modifier for score 17 is +3`` () = | |||
| modifier 17 |> should equal 3 | |||
| [<Fact>] | |||
| let ``Ability modifier for score 18 is +4`` () = | |||
| modifier 18 |> should equal 4 | |||
| [<Fact>] | |||
| let ``Random ability is within range`` () = | |||
| for i in 1 .. 10 do | |||
| let ability = ability() | |||
| ability |> should be (greaterThanOrEqualTo 3) | |||
| ability |> should be (lessThanOrEqualTo 18) | |||
| [<Fact>] | |||
| let ``Random character is valid`` () = | |||
| for i in 1 .. 10 do | |||
| let character = createCharacter() | |||
| character.Strength |> should be (greaterThanOrEqualTo 3) | |||
| character.Strength |> should be (lessThanOrEqualTo 18) | |||
| character.Dexterity |> should be (greaterThanOrEqualTo 3) | |||
| character.Dexterity |> should be (lessThanOrEqualTo 18) | |||
| character.Constitution |> should be (greaterThanOrEqualTo 3) | |||
| character.Constitution |> should be (lessThanOrEqualTo 18) | |||
| character.Intelligence |> should be (greaterThanOrEqualTo 3) | |||
| character.Intelligence |> should be (lessThanOrEqualTo 18) | |||
| character.Wisdom |> should be (greaterThanOrEqualTo 3) | |||
| character.Wisdom |> should be (lessThanOrEqualTo 18) | |||
| character.Charisma |> should be (greaterThanOrEqualTo 3) | |||
| character.Charisma |> should be (lessThanOrEqualTo 18) | |||
| character.Hitpoints |> should equal (10 + modifier(character.Constitution)) | |||
| [<Fact>] | |||
| let ``Each ability is only calculated once`` () = | |||
| for i in 1 .. 10 do | |||
| let character = createCharacter() | |||
| character.Strength |> should equal character.Strength | |||
| character.Dexterity |> should equal character.Dexterity | |||
| character.Constitution |> should equal character.Constitution | |||
| character.Intelligence |> should equal character.Intelligence | |||
| character.Wisdom |> should equal character.Wisdom | |||
| character.Charisma |> should equal character.Charisma | |||
| character.Hitpoints |> should equal character.Hitpoints | |||
| @@ -0,0 +1,53 @@ | |||
| # D&D Character | |||
| 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]. | |||
| [DND]: https://en.wikipedia.org/wiki/Dungeons_%26_Dragons | |||
| [Troll]: http://hjemmesider.diku.dk/~torbenm/Troll/ | |||
| ## Running the tests | |||
| To run the tests, run the command `dotnet test` from within the exercise directory. | |||
| ## Autoformatting the code | |||
| F# source code can be formatted with the [Fantomas](https://github.com/fsprojects/fantomas) tool. | |||
| After installing it with `dotnet tool restore`, run `dotnet fantomas .` to format code within the current directory. | |||
| ## Further information | |||
| For more detailed information about the F# track, including how to get help if | |||
| you're having trouble, please visit the exercism.io [F# language page](http://exercism.io/languages/fsharp/resources). | |||
| ## Source | |||
| Simon Shine, Erik Schierboom [https://github.com/exercism/problem-specifications/issues/616#issuecomment-437358945](https://github.com/exercism/problem-specifications/issues/616#issuecomment-437358945) | |||