Average Roll Breakdown by Attribute Dice

Well, guess I’ll redo the sheet this week. lol

@Hassurunous FWIW your final formula is exactly the same one I used. I feel a little less dense.

(Also FWIW my function also had the option to return the lower between the result and an arbitrary limit (usually 45), just so I could trim the long tail off the data and make it easier to compare stacked charts.)

@brianfeister HA! Now I feel even less dense. Also wryly resigned to the fact that I will not be able to resist the temptation to losing another night to number-bothering in the near future.

1 Like

@GartLarissa @Hassurunous @Carl, FYI you can see the source for this (most of it isn’t my code, so no poking fun, I just fixed the bug in how the calculations were run) on Github if you like:

2 Likes

So, when I was messing with my own system before I came across Open Legend, I was mainly using d6 that exploded.

I actually did the mathematical permutation to figure out the average roll of a d6 (it was roughly 4.2, I had a more exact number, but I’d have to look it up now). This way I could figure out target numbers and the like.

You can actually figure out the mathematical average, b/c when it comes to averages, even though it can explode to infinity, based on the rarity, it stops affecting the total average after so many.

2 Likes

The actual simple math forumla, to determine the average of an exploding dice, it increases over the expected dice by

N/(N-1) where N is the number of sides.

So a d6 average is 3.5

6/5 * 3.5 = 4.2

Of course, when it comes to having advantage, that can throw into a much more complex calculation. =P

Interestingly, I just found this article that explains it better than me:

now to figure out the math behind advantage.

2 Likes

Ha! I just kind of assumed there was a bug somewhere in mine because I was literally just hacking it together to continue a debate with Bruce :slight_smile:

@Daranar Does yours match the new values from the fix I pushed to the old tool?

Honestly I don’t know. My brain is too occupied with work stuff to get back into the dice-rolling mindspace today :slight_smile: The main issue was exploding all dice and taking highest/lowest vs. only exploding highest/lowest from initial roll, right?

At a glance, I think mine does work that way as it sorts results and drops the lowest on the initial roll, then explodes only the kept results. It doesn’t handle disadvantage at all yet though. You could probably just paste your (or the “official”) code into runkit to get the charts.

The problem with this formula is that it actually only explodes when [highest 2 of 4d6] is at its maximum value (12). This is clear if if you don’t include the d20 in the roll. At that point you’ll notice that both 12 and 13 are values that can’t be hit. If the dice were exploded as we want, both values would be possible. I haven’t yet figured it how to use anydice for the CORRECT open legend mechanic.

@Carl I have a suspicion that it’s not possible. I wonder if Roll20 is built on a derivative formula for handling exploding dice. Anyway, for a plain 'ol javascript example, my updated version does work.

function Dice(die, count) {
    // Roll count D die
    // Called by Roll
    // returns an array
    var total = [];
    var explosions = 0;
    // roll the first set of dice
    for (var i = 0; i < count; i++) {
        total.push( Math.floor(Math.random() * die) + 1 );
    }

    explosions = total.filter( function ( val ) { return val === die } ).length;
    if ( explosions > 0 ) {
        for (var i = 0; i < explosions; i++) {
            total.push(singleRoll(die));
        }
    }

    return total;
}

https://openlegend.github.io/open-legend-stat-gen/index.html

https://github.com/openlegend/open-legend-stat-gen

Thanks for the input @Carl! I’ve since updated to formula to fix just that issue shortly after posting, but forgot to come back and update. New formula should be:

output [explode 1d20] + [explode 2d[highest 2 of 12d6]] named “Advantage 10”

This grabs the highest 2, then explodes each die individually.

Unfortunately, when I increase the number of explosions, it messes up the math somehow, and, for example, Attr. 1 Adv. 10 ends up saying that the average roll is a 74, which is obviously not correct. Still fiddling around to try and figure it out, but so far my best bet is to leave the explosions at default or find the d20 averages and then add those to the averages of the other dice (while still leaving the explosions at default to prevent it from accounting for and unfairly weighting the absolutely insane edge case of a d20 and a d4 both exploding 35 times in a row. lol).

I’ll see what I can figure out.

Alright! I think I finally got the AnyDice formula working as of about 2 minutes ago.

For Attribute Score 5, Advantage 10:
output 1d[explode d20] + [highest 2d[explode d6] of 12d6] named “Advantage 10”

Let’s walk through it real quick (hooray rubber duck debugging which caught the error I just posted in reply to @Carl not 10 minutes ago! Sorry Carl! It’s fixed now, I’m almost positive!)

  1. Roll a d20. It explodes on 20s.
  2. Roll 12d6. Keep the HIGHEST 2, throw out the rest.
  3. Explode 2 1d6 dice individually.
  4. Add those totals together.

Long story short, I had to reverse the “explode” and “highest” logic because I had misread the docs regarding exploding dice individually rather than as a group. This new method performs well within expectations, so I’ll be updating the Average Attribute Rolls with those values today at some point, as well as updating the values for the http://spandox.com/rollopen.htm roller as well now that @brianfeister has updated the code on that roller as well.

I’ll keep you guys posted for the update!

Roll20 assumes most other systems on who they explode, so they offer 2 ways:

d6! or d6!!

I can actually sit down and create an API script that can end up duplicating the way Open Legend Works, and I should be able to take it onto the character sheet. Problem is I have to actually write out the code, and have to time fumble around with it. I found a rough way to do it, but haven’t gotten to sit down with it yet.

Using this as an example, I know it can be done, just need some more time =P

I’ve looked this over in anydice. I think it’s right, but I still don’t believe that it can yield accurate mean values based on the explosion calculation limit. The probabilities for individual rolls should be good, but I would expect the mean to be low.


That percentage change is pretty extreme. A full order of magnitude? Granted, you’re looking at the case I would expect to have the most variation, but still wow.

Looking at some of the lower attribute scores, I see substantially less increase in expected value with advantage with the corrected code than with the old code. For example, an attribute score of 1 with no advantage has an expected value of 14.38. Advantage 5 increases it to 15.99. Advantage 10 bumps it up to 16.94.

A score of 5 with no advantage has an expected value of 19.46. Advantage 5 increases to 22.62. Advantage 10 increases it to 23.94.

Granted, my analysis only looks at expected value (I’m assuming that’s the mean), and advantage will clearly help shield you from lower rolls. However, it looks like the payoff for adding more advantage is a lot lower than under the other system, at least at lower levels.

I don’t want to knee-jerk suggest that the system simply be changed because of this, but is it enough of a change from the progression that we thought it was to merit closer examination?

1 Like

Lol. No, not at all. All it really means is that the tables for “average CR for a given attribute score” are correct as they stand. @Great_Moustache had been pushing for the purported average to be higher. This just indicates that our initial gut reaction was correct there.

The reason this has no seriously dangerous impact on the game is that all of my math was done based on dice rolls without advantage or disadvantage. So the core statistics are untouched. All it means is that aggressive advantage stacking doesn’t have the payoff that was previously assumed.

2 Likes

Glad to hear it. I know I’m not the first to say this, but I absolutely love being able to have a conversation with the game’s developers. :smiley:

4 Likes

Awesome man, glad it means something to you! I do my best and it’s tough, there’s so little time.

1 Like

@Hassurunous FYI, I didn’t update this site:
http://spandox.com/rollopen.htm

Rather, I created a new one here:
https://openlegend.github.io/open-legend-stat-gen/index.html

1 Like

An accurate openlegend function for anydice.com: http://anydice.com/program/cde0

The outputs there default to showing Disadvantage 1 for all attribute levels, but you can change the outputs at the bottom of the script to compare any rolls you want. Click the [Graph] and [At Least] buttons for a good comparative view.

SYNTAX: [openlegend attribute_level {advantage_level}]
where attribute_level is a value 0 - 9
and advantage_level is the number for level of advantage or disadvantage (use negative values for disadvantage)

It was tricky to get the dice rules exactly right since you have to select the dice results before exploding, and if you try something like [explode [highest 1 of 2d20]], then on a 20 the explode function rolls another [highest 1 of 2d20] instead of just another 1d20.

It took me a while to figure out how to pass a sequence of dice results to a function as a parameter. The key is that if the function is expecting a parameter of type Sequence and you pass it a set of dice (eg 3d6), the anydice engine will call your function with every possible sequence of results for those dice, sorted highest to lowest. Then it’s easy to iterate across the correct subset of dice, check for explosions, and sum it all up.

function: openlegendhelper SEQ:s D:n START:n END:n {
 RES: 0
 loop I over {START..END} {
  RES: RES + I@SEQ
  if I@SEQ = D { RES: RES + [explode 1dD] }
 }
 result: RES
}

function: openlegend LEV:n ADV:n {
 N: 1
 if LEV = 0 {
  D: 20
  RES: 0
 }
 else {
  RES: [explode 1d20]
  if LEV > 4 {
   if LEV > 7 { 
    N: 3
    D: (LEV*2)-8
   }
   else { 
    N: 2
    D: (LEV*2)-4
   }
  }
  else { D: (LEV*2)+2 }
 }
 if ADV < 0 {
  N: N-ADV
  START: 1-ADV
  END: N
 }
 else {
  START: 1
  END: N
  N: N+ADV
 }
 result: RES + [openlegendhelper NdD D START END]
}

[Cross-posted from here: Accurate openlegend dice roll function for anydice.com]

2 Likes

This is really cool. I’ll definitely play around with it later.