11:20 AM - Initial Idea
1:05 PM - Basic setup complete
- New git project (and github remote project)
- Copy an existing project, pare down to basics, rename things
- Set up Maven for project
- Get project running in Dropwizard
- Eat lunch (important!)
- Set up basic Postman call to test running service
- Set up a Lambda proxy to avoid dealing with SSL
- Create new skill configuration
- Post on forums about misleading wording for new skills
- Test out basic request
- Fight with port forwarding on home router until tests start working
One annoying thing I found out is that you can't define an intent schema containing only the Amazon built-in intents. To get up and running, I wanted to work with only the launch intent and built-ins, but that fails to save. So, I added a garbage intent that I won't implement server-side, and now things are up and running, so I can start building out the skill.
2:50 PM - Crawling along
4:05 PM - That was easy
Anyhow, to this point everything has been fair dice. Now to make things cheater friendly.
6:45 PM - Cheater code completed
- I wanted the level of skew to be configurable/tunable
- I wanted it to skew fairly evenly, instead of clustering on specific numbers
- I wanted the entirety of the range to stay in play (i.e. don't want to eliminate rolling a 1 on a d20).
- A new instance of the CoefficientDiceSkewStrategy is created, including a float parameter between -1 and 1, inclusive. This value is referred to as the coefficientModifier. A value of 0 means don't skew, -1 is skew heavily downward, and 1 is skew heavily upward.
- A random number is generated within the range of the die I'm rolling.
- The number generated, and its max possible value, are passed to the skew strategy.
- The skew strategy checks to see if the value even has room to skew. If not, it returns early.
- A random float is generated and multiplied by the coefficientModifier and by the maxValue, and then rounded to an int. This gives us the value to add to our roll. Depending on the modifier used, it can be any integer between maxValue and negative maxValue, inclusive.
- This new value is added to our original roll.
- If this new sum ends up out of bounds, we keep the original roll but throw away the coefficient's random value and generate another.
- Step 7 is repeated up to a set number of times, currently set to 100, at which point we just use the original input from the roll.
- The newly skewed roll is returned. Success!
- While I picked a strategy with some very strict rules, the point of the interface was to make these things swappable or configurable in the future - maybe even by the user. I could see a possible strategy where it's fairly hands off, except to occasionally trigger additional 20s (or 1s) on a d20, for example.
- We could've avoided the retry loop by only allowing the coefficient to go from 0 to (boundary - roll), but that would've made it so that in some cases skew was impossible. For example, with a coefficient of .09, and a roll of 19 on a d20, there's no way to make that jump up to 20.
- Alternately, we could have avoided rerolls by just rounding to the boundary whenever we escaped it. That would've resulted in artificially stacking on min and max values, though.
- The reason we had to limit the reruns is because there's an asymptotic situation that happens when you have a roll that is very close to the boundary on a very large max value. Take for example a roll of 65534 with a max of 65535. Even with a small coefficient, the odds of the skewed roll being out of bounds are incredibly high, and so it's possible to get in a near-endless loop trying to capture that last point of skew.
8:00 PM - Easy peasy
9:30 PM - Listening, testing, and breaks (Oh my!)
That's nothing compared to the testing process, though. Right now I have 25 utterances that should work, and 22 of them should work across three different requests patterns (active session, "ask dice bot", "tell dice bot"). That's 66 manual test cases that have to be done any time the utterances or schema change (and it will change, when I tack on some branding stuff). We've harped on this before, but I can't stress enough how much (lack of) testability is a hindrance right now.
10:30 PM - Finishing up
There were also a bunch of fit-and-finish items to work through. For example, when a user says roll 1d10, we want to use the words "die" and "value" instead of "dice" and "values".
We may also choose to tackle a few additional features, such as:
- Storing user data and letting users configure their coefficient modifier
- The ability to append roll sets (think: "Roll 2d10 and 4d6 for me")
- Additional DiceSkewStrategies (like the crit/crit-fail one talked about above)