| 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) } |
| <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> |
| // 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 | |||||
| # 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) | |||||