ArtemGr / Sidekick

Dice and LFG bot for Discord.
MIT License
249 stars 39 forks source link

Count the number of successes #4

Closed ArtemGr closed 8 years ago

ArtemGr commented 8 years ago

There should be a modifier that makes the dice bot return the number of passed rolls instead of the sum of them.

https://www.reddit.com/r/discordapp/comments/4vfbqi/looking_for_a_dice_bot/d780297

=> Note that the number of successes might be negative in some cases. E.g. an oWoD botch.

ArtemGr commented 8 years ago

So I've used Scrivener to brainstorm this. Yikes!

Here's what Scrivener compiled from my notes:


tackle the evaluator

The funny thing about this task is that we don't need the parser. We already has the "> X" parser in place.

What we need is for the "> X" dice to 1) Change the logic (the modifiers have to be applied to every dice roll and not to the sum of them). And for that - we do have to extend the parser! 2) Change the output - to print the number of successes instead of (or in addition to) the sum of the faces.

Chapter One: handle the modifiers differently?

the plan

So "/r 3d6+2>1" should return the number of successes by rolling d6 three times and applying the "+2" modifier to each roll.

Now how do we do that?

In order to be able to parse and handle the modifiers 1) We need the modifiers to be recognized by the parser. This will magically make the parser eat the modifiers instead of leaving them to the outer evaluator. 2) We need the modifiers to be parsed in a way that lets us tackle them when we do the rolls. They should be a part of dice specification maybe. 3) And finally, we need this to happen only if there's a ">1" condition at the end of the line! E.g. "3d6+2" should emit the usual "(d6+d6+d6)+2" whereas "3d6+2>1" should emit "(modified_d6+modified_d6+modified_d6)". 4) Wait, the last one wasn't a final condition even. This one is. Thing is, we should be able to do math with the dice! And it's only logical if we could do the math with the number of successes as well! So, "3d6>1 * 3" should multiply the number of successes by three, for example! At the same time, it would be nice to print the number of successes with the "successes" suffix. Means we should remove this suffix before the outer evaluation.

recognize the modifiers

Make the parser eat the modifiers.

It should chew on "3d6+2".

spew the modifiers

By default the dice evaluator should spew the modifiers unmodified.

E.g. "3d6+2" should evaluate to "(d6+d6+d6)+2".

propagate the success

When we roll, we should look ahead and see if there is a success number condition.

E.g. check if the first Dice::ops is a TargetNumber.

I think we might be conservative here and check only the first Dice::ops. For example, "3d6+2>5" is evaluated as (modified_d6+modified_d6+modified_d6)>5, but "3d6+2 d1 >5"... huh. I don't know how it's evaluated.

Well, shucks, I've checked roll20 and they just ignore the drop in this case. E.g. "/roll 3d6 +2 dl 1" they evaluate to (d6+d6+d6)+2.

I beg to differ there. If we want to drop some rolls then we might as well take the modifiers into account.

The question is... how do we unit test this? Because unit testing all those cases seems more and more important.

One way to unit test the dice is to implement a mock roller. E.g. tell the roller what it should roll instead of a truly random number.

And another nifty thing to have would be unit testing through Discord. E.g. "/r test" should do the unit tests and print the results. Capish?

So... when we roll, we should check ahead and see whether we have any ops on the dice. Because if we have then it doesn't make sense to leave the modifier to the outer evaluator. "3d6 +modifier $any_op" should apply the modifier inline. "3d6 +modifier" should leave the modifier alone (spew it back for the outer evaluator to chew on). Something like that.

Chapter Two: unit tests

discord testing

As a developer or even a curious user I should be able to run the unit tests right from the discord UI with, say, "/r test", to save the hassle of going into a different terminal UI just to run the tests.

Alternatively, I might see the tests being run right after a fresh build, in the editor. This seems even better.

test modifiers working with drops

"/r 3d6 +2 dl 1" should work as follows: roll d6 and modify, thrice, apply drop lowest. E.g. the modifiers should be handled right away.

On the other hand, "/r 3d6 +2" should work as before: roll d6 thrice and then modify.

the real thing

We should test that "/r 3d6+2>5" evaluates to the proper number of successes.

We should test that we can do math on the number of successes. "3d6>5+2" (remember: +2 is not parsed into the dice specification here).

Chapter Three: being successfull

modify the printer

"3d6>5" should print the number of successes.

In order to do this I think it's enough to recognize in the printer that the last op is the TargetNumber op.

If it is, then instead of (d+d+d) we print (x successes).

cleanup

Should replace "(x successes)" with "(x)" before handling it to the outer evaluator.