Functions & Dragons – Part 6

Refactor time! I did a huge refactor to cut down on the repetitive nature of the code surrounding Save and Skill Proficiencies. This was immensely satisfying and is probably my favorite thing about Elm. I can refactor with confidence even without a single unit test!

All in all I shrank the codebase by 449 lines, or nearly 37%! And while this did cost me a tiny bit of type goodness (the new code uses Dict which introduces Maybe into the equation) the increased conciseness and flexibility (custom skills, anyone?) is a fair trade in my book.

The new module structure with wrapped messages is also a big win. Check out my new update function:

I also started in on the Basic Info module, but didn’t get very far. That’ll be tomorrow’s project. Stay tuned!

Functions & Dragons – Part 5

Today I added the Other Proficiencies & Languages panel.

I started by taking the same approach of enumerating all the languages and providing a drop-down list, but the user experience was kind of sucky. I eventually decided to simply use a text box and allow any string, which cut way down on code repetition.

I think I’m going to propagate this String based approach to cover Skills and possibly even Abilities as well, not so much for flexibility as to simply cut down on code repetition.

Also, the Languages and Proficiencies sections are basically copy-pasted at this point. I should refactor that.

Anyway, with that, the first column is done! Next time, assuming I don’t get entirely lost in refactor land, I’ll implement the basic character info panel.

Functions & Dragons – Part 4

Quite a lot of visual progress today! I added the Skills and Passive Perception modules. Here’s a side-by-side comparison with a reference character sheet and more repetitive type code:

Honestly the repetition is somewhat bothersome. I had to write the entire list of 18 skills a total of 8 times. That’s 144 lines of mindless copy-paste. It feels wrong, but I can’t seem to come up with a way of doing it better without losing the nice guarantees this system gives me.

Ah well. It’s not a huge problem, but it’s going to nag at me, I’m sure. For now, the first column of the character sheet is mostly complete! Next time I’ll finish it up with the Languages and Other Proficiencies box.

Functions & Dragons – Part 3

Much better progress today compared to yesterday. Fixed the proficiency bonus display (wasn’t actually tied to the model value) and successfully modularized the ability scores type and its related functions. As part of this, I reorganized the code and split it up.

I also realized the abilities record type could easily be genericized to support e.g. Bool for saving throw proficiencies. This feels like a huge design win. It’s just so clean. Although I can’t for the life of me figure out what to do about the repetition here:

update : Abilities a -> Ability -> a -> Abilities a
update abilities ability val =
    case ability of
        Strength ->
          { abilities | str = val }

        Dexterity ->
          { abilities | dex = val }

        Constitution ->
          { abilities | con = val }

        Intelligence ->
          { abilities | int = val }

        Wisdom ->
          { abilities | wis = val }

        Charisma ->
          { abilities | cha = val }

I guess I could redefine Abilities a as List (Ability, a) and have value return Maybe a? I’ll give that a try tomorrow and see how it goes.

Oh, I also implemented the saving throws box, complete with proficiency bonus check boxes and modifier calculation.

Which reminds me. I think it would be a good idea to introduce a viewModel : Model -> ViewModel function and type that computes derived values like saving throw bonuses all in one convenient place.

Functions & Dragons – Part 1

I’ve started working on a D&D app in Elm. I’m starting from the character sheet and plan to grow the project outward over time. Today I built the ability scores block.

Currently you can enter values for each ability score and the modifier will be computed automatically. Scores below 0 or above 24 are rejected.

The code is up on GitHub. Enjoy!