PDA

View Full Version : Help requested, how to calculate complex dice probabilities



H2SO4
2013-07-14, 08:40 AM
I'm playing in a game that uses all D6 dice.

The system uses 1D6 to 10D6 count total, roll under target number to succeed.
Criticals are handled with triple (or more) ones without any sixes as critical success (regardless of total) and triple (or more) sixes (also regardless of total) as critical failure.

Sometimes the roll is made with drop highest or even drop two highest dice.

How could these crit success / success / fail / crit fail probabilities be computed with anydice.com (or with anything else, for that matter)?

(How I wish I could simply program the computer to go through 1...11 to 6...66 and to tabulate & count the results. Alas, my brain is simply incompatible with computer programming. :\)

-H2SO4

Craft (Cheese)
2013-07-14, 09:22 AM
(How I wish I could simply program the computer to go through 1...11 to 6...66 and to tabulate & count the results. Alas, my brain is simply incompatible with computer programming. :\)

-H2SO4

I took about 5 minutes to write up a (very slow and poorly formatted) ruby script. Note that I made a few assumptions about your system:

- If your roll matches the target number exactly, it counts as a success rather than failure.

- Critical failure requires there be no 1s, just as a critical success requires there be no 6s.

If these assumptions were wrong I can easily edit the code to correct them.


class Distribution
def initialize(h)
@h = h
@h.default = 0
end

def convolute(d,f)
posses = Hash.new
posses.default = 0
@h.each_key do |i|
d.h.each_key do |j|
posses[f.call(i,j)] += @h[i] * d.h[j]
end
end
return Distribution.new(posses)
end

def plus(d)
self.convolute(d,Proc.new {|i,j| i + j})
end

def g_convolute(ary,f)
def pass(a,k)
m = []
for i in a
for j in k
m.push(i.dup.push(j))
end
end
return m
end

ary.unshift(self)
k = []
for i in ary
k.push(i.h.keys)
end
posses = []
m = k.shift
for i in m
posses.push([i])
end
for i in k
posses = pass(posses,i)
end
mn = Hash.new
mn.default = 0
for i in posses
index = f.call(i)
value = 1
for j in Array(0..(i.length-1))
value *= ary[j].h[i[j]]
end
mn[index] += value
end
return Distribution.new(mn)
end

def exactly(n)
s = 0
for i in @h.values
s += i
end

(@h[n] / s.to_f).to_s
end

def self.dice(n,d)
m = Hash.new
for i in Array(1..d)
m.store(i,1)
end
h = Distribution.constant(0)
(n).times do
h = h.plus(Distribution.new(m))
end
return h
end

def self.constant(n)
Distribution.new({n => 1})
end

attr_reader :h
end

def get_proc(target,drop=0)
Proc.new do |ary|
if drop > 0
a = ary.sort.first(ary.size-drop)
else
a = ary
end
s = 0
for i in a
s += i
end
if a.count(1) >= 3 and a.count(6) == 0
2
elsif a.count(1) == 0 and a.count(6) >= 3
-1
elsif s <= target
1
else
0
end
end
end

def get_dist(dice,target,drop=0)
ary = []
(dice-1).times do
ary.push(Distribution.dice(1,6))
end
d = Distribution.dice(1,6).g_convolute(ary,get_proc(ta rget,drop))
puts dice.to_s + "d6, TN " + target.to_s + ", Drop highest " + drop.to_s
puts "Critical Fail - " + d.exactly(-1) + "%"
puts "Fail - " + d.exactly(0) + "%"
puts "Success - " + d.exactly(1) + "%"
puts "Critical Success - " + d.exactly(2) + "%"
end

Just run the get_dist function (first argument is the number of d6 to roll, second argument is the target you want to roll under, third argument is how many dice to drop and is optional). For a large number of dice (more than like 5 or 6) expect the script to take a few minutes to calculate the results: With a brute-force algorithm like this there's not much to be done to fix that.

Some example output:


6d6, TN 20, Drop highest 1
Critical Fail - 0.005679869684499314%
Fail - 0.09349279835390946%
Success - 0.8444358710562414%
Critical Success - 0.05639146090534979%

4d6, TN 15, Drop highest 0
Critical Fail - 0.013117283950617283%
Fail - 0.32253086419753085%
Success - 0.6512345679012346%
Critical Success - 0.013117283950617283%

Knaight
2013-07-14, 10:13 AM
The website Anydice can cover this well enough.

Craft (Cheese)
2013-07-14, 10:34 AM
The website Anydice can cover this well enough.

Probably, but I know of no way to account for crit successes/failures under the system the OP described without complicated scripts, and Anydice's scripting system sucks serious donkey.

TheStranger
2013-07-14, 11:01 AM
I don't have an answer to OP's question, but I have a related one of my own, for the more statistically-inclined denizens of the playground.

Suppose I have a system that uses both dice pools and opposed rolls. So let's say player A is rolling 8d10, and player B is rolling 6d10, and we're counting number of successes (for the sake of argument, let's say success is 7+). How do you figure out the odds of each player winning the opposed roll? Is there a simple (or not so simple) formula that can be applied to different dice pool sizes and different success criteria? I'm more interested in having such a formula, rather than the answer to my specific example, as I would like to be able to tweak the variables later.

Craft (Cheese)
2013-07-14, 11:11 AM
I don't have an answer to OP's question, but I have a related one of my own, for the more statistically-inclined denizens of the playground.

Suppose I have a system that uses both dice pools and opposed rolls. So let's say player A is rolling 8d10, and player B is rolling 6d10, and we're counting number of successes (for the sake of argument, let's say success is 7+). How do you figure out the odds of each player winning the opposed roll? Is there a simple (or not so simple) formula that can be applied to different dice pool sizes and different success criteria? I'm more interested in having such a formula, rather than the answer to my specific example, as I would like to be able to tweak the variables later.

This one's pretty easy to do with anydice (http://anydice.com/program/266a). Substitute the dice pool sizes and the die shapes as necessary. (On a 7+ there's a 40% chance of success and 60% chance of failure, so my die shape here is {0,0,0,1,1}. If you wanted to do an 8+ target, then the die size would be {0,0,0,0,0,0,0,1,1,1}, 30% chance of success and 70% chance of failure.)

TheStranger
2013-07-14, 11:23 AM
This one's pretty easy to do with anydice (http://anydice.com/program/266a). Substitute the dice pool sizes and the die shapes as necessary. (On a 7+ there's a 40% chance of success and 60% chance of failure, so my die shape here is {0,0,0,1,1}. If you wanted to do an 8+ target, then the die size would be {0,0,0,0,0,0,0,1,1,1}, 30% chance of success and 70% chance of failure.)

I guess that works, thanks. Out of curiosity, do you know how to do the actual math for a problem of this type? I'd like to not have to brute force it every time I want to change a variable.

I also ask because I've had similar problems come up in non-RPG settings (like fantasy baseball), where the probability of success wasn't such a conveniently round number (though I suppose it can always be expressed with a large enough number of ones and zeroes).

warty goblin
2013-07-14, 11:30 AM
I don't have an answer to OP's question, but I have a related one of my own, for the more statistically-inclined denizens of the playground.

Suppose I have a system that uses both dice pools and opposed rolls. So let's say player A is rolling 8d10, and player B is rolling 6d10, and we're counting number of successes (for the sake of argument, let's say success is 7+). How do you figure out the odds of each player winning the opposed roll? Is there a simple (or not so simple) formula that can be applied to different dice pool sizes and different success criteria? I'm more interested in having such a formula, rather than the answer to my specific example, as I would like to be able to tweak the variables later.

This one's actually not particularly difficult conceptually. Both player A and player B's successes will follow binomial distributions with a number of trials equal to their dice pool, and a probability of success...equal to their probability of success.

To determine the probability that A beats B, you want P(A > B), which is just the sum of all events where A is greater than B, which is just the double sum (a = 1 through n_a) (b = 0 through a - 1) P(A = a)P(B = b).

I don't think there's a particularly convenient closed form for this beyond what I gave, but programming it up in R or any other programming language should take approximately zero time for a really crappy double iterative algorithm.

TheStranger
2013-07-14, 11:57 AM
...programming it up in R or any other programming language should take approximately zero time for a really crappy double iterative algorithm.

Me programming anything more complex than my DVR will take approximately infinite time, so that, unfortunately, is not an option for me. I appreciate the thought, though. I was hoping that there was a quick and dirty formula, but if there's not, there's not. Alternately, does anybody know if there's a way to make Excel do this for me, short of brute-forcing it?

Ionbound
2013-07-14, 12:02 PM
For the OP. It seems like the easiest thing to do would be to find a program that figures out all the possible combinations or permutations that the dice could have, and then calculate a percentage of critical success or failure from that.

Craft (Cheese)
2013-07-14, 12:22 PM
I guess that works, thanks. Out of curiosity, do you know how to do the actual math for a problem of this type? I'd like to not have to brute force it every time I want to change a variable.

Let's say you have 3 dice with a 0.4 probability of success (and a 0.6 probability of failure).

For each possible result (0-3, in our case), figure out how many ways there are to get that number, then sum the probability of each way of getting that result.

There's only 1 way to get a 0, and that's that we get a 0 on all three dice. The probability of this is 0.6^3, or about 0.216.

There's 3 ways to get a 1: Success on a single dice, and two on both others. The probability of this is 3*0.4*0.6^2, or about 0.432.

There's 3 ways to get a 2: Success on two dice, and failure on the third. The probability of this is 3*0.4^2*0.6, or about 0.288.

There's only 1 way to get a 3: Success on all three dice. The chance of this is 0.4^3, or about 0.064.

In general, the probability of getting K successes with N dice with X probability of success on each die (and each die independent) is n!/((n-k)!k!) * x^k * (1-x)^(n-k).


Unfortunately figuring out the probability of the convolution of two of these dice pools is a bit harder, and it's something I don't know how to do in closed form with an easy combinatoric formula, but the general procedure is the same.

Let's say you have two dice pools that are opposing one another. Let's say player 1 is rolling 3 dice with X=0.4, and player 2 is rolling 2 dice with X=0.4. We'll assume that player 1 only wins if they get at least 1 more success than player 2. We'll also assume that we only care about player 1 for simplicity's sake: You can just as easily reverse them if you want to calculate from player 2's perspective.

You take all the combinations, multiply the probability that each combination occurs, and sum each probability into the same bin. As player 1 has a range of 0-3 and player 2 has a range of 0-2, there are only 6 possible ways for the player 1 to win: 1:0, 2:0, 3:0, 2:1, 3:1, 3:2.

The probability of 1:0 is 0.432*0.36, or ~0.156.

The probability of 2:0 is 0.288*0.36, or ~0.104.

The probability of 3:0 is 0.064*0.36, or ~0.023.

The probability of 2:1 is 0.288*0.48, or ~0.138.

The probability of 3:1 is 0.064*0.48, or ~0.031.

The probability of 3:2 is 0.064*0.16, or ~0.010.

The total probability of all these combinations (with rounding) is 0.462, and checking our work with anydice (http://anydice.com/program/266b) says that the result is 0.4614. Pretty close!


Someone with a better understanding of statistics and combinatorics probably can give you a plug-and-chug formula that can do this, but you could write a computer program to do it for you fairly easily.

EDIT: Thinking about it some more, this is probably as close to a closed form formula I'm gonna get:

http://i.imgur.com/HlGD5qy.png

n is the size of P1's dice pool, m is the size of P2's dice pool, x is the probability of success per die for P1, y is the probability of success per die for P2 (you can probably simplify the formula a bit if x=y).

meschlum
2013-07-14, 12:53 PM
Of course there is a trick! Well, sometimes.

You are dealing with opposed rolls. If the probability of success is equal to the probability of failure (6+ on a d10, 4+ on a d6, etc.), then you can treat the opposed dice as negative dice for you.

A negative die is a simple die with a -1 penalty. So if it's a success, it adds 0 to your total and if it's a failure it subtracts 1 from your total. Since success and failure have the same likelihood in this case, this behavior matches what you get from an opposed die (if the opponent succeeds, you get -1, if the opponent fails, you get 0).

This means that 8 dice on your side versus 6 dice for the opponent turns into 14 dice total, with a -6 penalty to successes. And the math for that is fairly simple, especially since the probability of success and failure are the same.

The probability of getting exactly N with k dice is C(N, k)/2^k, which is a function you can find in Excel (combinatorial, or some variation on the word). In the case of 14 dice, you get:

0: 1 combination / 2^14 cases
1: 14 combinations / 2^14 cases (= 1 * 14 / 1)
2: 91 combinations / 2^14 cases (= 14 * 13 / 2)
3: 364 combinations / 2^14 cases (= 91 * 12 / 3)
4: 1001 combinations / 2^14 cases (= 364 * 11 / 4)
5: 2002 combinations / 2^14 cases (= 1001 * 10 / 5)
6: 3003 combinations / 2^14 cases (= 2002 * 9 / 6)

And you can stop there.

The total likelihood of a negative result (your 6 die opponent wins) is 3473 combinations out of 16384 total - a bit less than 20%.

The likelihood of a tie (exactly 6 successes on 14 dice) is 3003 combinations out of 16384 total - somewhat less than the odds of your opponent winning.

The rest of the time, you win!


If the dice are not fair, then your opponent's pool cannot be treated as negative dice on your side (unless they have a different and exactly matching probability of success too), so the math gets harder.

Your chance of getting N successes on k dice, where each die succeeds with probability p, is:

C(N, k) * p^N * (1-p)^(k - N)

When p = 1/2, you see that the second part becomes 1/2^k.

Fortunately, you can recycle a bit of the math.

0: 1 combination (8 dice) and 1 combination (6 dice)
1: 8 combinations (1 * 8 / 1) and 6 combinations (1 * 6 / 1)
2: 28 combinations (8 * 7 / 2) and 15 combinations (6 * 5 / 2)
3: 56 combinations (28 * 6 / 3) and 20 combinations (15 * 4 / 3)
4: 70 combinations (56 * 5 / 4) and 15 combinations (20 * 3 / 4 = result for 2)
5: 56 combinations (result for 3) and 6 combinations (result for 1)
6: 28 combinations (result for 2) and 1 combination (result for 0)
7: 8 combinations (result for 1) and 0 combinations (6 dice)
8: 1 combinations (result for 0) and 0 combinations (6 dice)

Then you mix in the probabilities and compare, using the lower number of dice as your baseline.

6: win (1 * p^8 + 8 * p^7 * (1-p)) * 1 * p^6 (you get 7 or 8, other gets 6)
tie 28 * p^6 * (1-p)^2 * 1 * p^6 (you both get 6)
lose (1 - 1 * p^8 - 8 * p^7 * (1-p) - 28 * p^6 * (1-p)^2) * 1 * p^6 (you get less than 6, other gets 6)
5: win (1 * p^8 + 8 * p^7 * (1-p) + 28 * p^6 * (1-p)^2) * 6 * p^5 * (1-p) (you get 6 to 8, other gets 5)
tie 56 * p^5 * (1-p)^3 * 6 * p^5 * (1-p) (you both get 5)
lose (1 - 1 * p^8 - 8 * p^7 * (1-p) - 28 * p^6 * (1-p)^2 - 56 * p^5 * (1-p)^3) * 6 * p^5 * (1-p) (you get less than 5, other gets 5)
4: win (1 * p^8 - 8 * p^7 * (1-p) + 28 * p^6 * (1-p)^2 + 56 * p^5 * (1-p)^3) * 15 * p^4 * (1-p)^2 (you get 5 or more, other gets 4)
tie 70 * p^4 * (1-p)^4 * 15 * p^4 * (1-p)^2 (you both get 4)
lose (1 * (1-p)^8 + 8 * p * (1-p)^7 + 28 * p^2 * (1-p)^6 + 56 * p^3 * (1-p)^5) * 15 * p^4 * (1-p)^2 (you get 0 to 3, other gets 4 - the equations switch here so losing is easier to represent than winning)
3 win (1 - 1 * (1-p)^8 - 8 * p * (1-p)^7 - 28 * p^2 * (1-p)^6 - 56 * p^3 * (1-p)^5) * 20 * p^3 * (1-p)^3 (you do not get 0 to 3, other gets 3)
tie 56 * p^3 * (1-p)^5 * 20 * p^3 * (1-p)^3 (you both get 3)
lose (1 * (1-p)^8 + 8 * p * (1-p)^7 + 28 * p^2 * (1-p)^6) * 20 * p^3 * (1-p)^3 (you get 0, 1 or 2, other gets 3)
2 win (1 - 1 * (1-p)^8 - 8 * p * (1-p)^7 - 28 * p^2 * (1-p)^6) * 15 * p^2 * (1-p)^4 (you do not get 0, 1 or 2, other gets 2)
tie 28 * p^2 * (1-p)^6 * 15 * p^2 * (1-p)^4 (you both get 2)
lose (1 * (1-p)^8 + 8 * p * (1-p)^7) * 15 * p^2 * (1-p)^4 (you get 0 or 1, other gets 2)
1 win (1 - 1 * (1-p)^8 - 8 * p * (1-p)^7) * 6 * p * (1-p)^5 (you do not get 0 or 1, other gets 1)
tie 8 * p * (1-p)^7 * 6 * p * (1-p)^5 (you both get 1)
lose 1 * (1-p)^8 * 6 * p * (1-p)^5 (you get 0, other gets 1)
0win (1 - 1 * (1-p)^8) * 1 * (1-p)^6 (you do not get 0, other gets 0)
tie 1 * (1-p)^8 * 1 * (1-p)^6 (you both get 0)
lose 0 (you always get 0 or more)

So it's messy, but there are a lot of recurring terms you can shuffle around in Excel to make things cleaner. General forms for arbitrary numbers of dice get painful, though.

meschlum
2013-07-14, 01:51 PM
I'm playing in a game that uses all D6 dice.

The system uses 1D6 to 10D6 count total, roll under target number to succeed.
Criticals are handled with triple (or more) ones without any sixes as critical success (regardless of total) and triple (or more) sixes (also regardless of total) as critical failure.

Sometimes the roll is made with drop highest or even drop two highest dice.

How could these crit success / success / fail / crit fail probabilities be computed with anydice.com (or with anything else, for that matter)?

(How I wish I could simply program the computer to go through 1...11 to 6...66 and to tabulate & count the results. Alas, my brain is simply incompatible with computer programming. :\)

-H2SO4

So this one is a bit different. My understanding of the way this is done is:

- Roll up to 10 dice.
- Any rolls at or below target number are successes
- Possibly drop the higher dice
- Count the total number of successes
- If there are 3+ ones and 0 sixes, critical success
- If there are 0 ones and 3+ sixes, critical failure


Since critical success and failure are independent of the rest of the process (except dice dropping), we'll deal with that first.

With k (k >=3) dice, you have a chance of critical success or failure. They both have the same likelihood, since they use the same mechanics.

Your odds of getting N ones on k dice are

C(N, k) * 5^(k - N) / 6^k

Since you got N ones on k dice, you have k-N dice left which are ranging from 2 to 6, and none of them can be sixes.

Each die that is not a 1 has a 1/5 chance of being a 6, so a 4/5 chance of not being a 6.

Therefore, if you get N ones, your chance of a critical is (4/5)^(k - N)


Thus, your odds of getting a 'critical' (no sixes) with N ones are:

C(N, k) * 4^(k-N) / 6^k

To be a real critical, you need to have N >= 3, and you can work from there.

3 dice: 1 * 4^0 / 6^3 = 1 / 216 (triple one)
4 dice: (1 * 4^0 + 4 * 4) / 6^4 = 17 / 1296 (~3 times more often than with 3 dice)
5 dice: (1 * 4^0 + 5 * 4 + 10 * 4^2) / 6^5 = 181 / 7776 (a bit less than 2 times as often as with 4 dice)
6 dice: (1 * 4^0 + 6 * 4 + 15 * 4^2 + 20 * 4^3) / 6^6 = 1545 / 6^6 (a bit less than one and a half times as often as with 5 dice)
7 dice: (1 * 4^0 + 7 * 4 + 21 * 4^2 + 35 * 4^3 + 35 * 4^4) / 6^7 = 11565 / 6^7 (about 20% more often than with 6 dice)

etc.

This ignores dropping dice. Do note that as your dice pool increases, your odds of a critical failure go up (as do the odds of a critical success). And, given the rate of growth, it's possible that for very high dice pools your odds of a critical success will go down with more dice, as the "no sixes" condition becomes more important.

If you drop high dice, the main effect for criticals is that you need more than one six to get a critical failure. And, potentially, more than 3 ones (on 3 dice)
to get a critical success.

If you're dropping 1 die, you need 2 or more sixes to get a critical failure. So you can't get a critical failure on 3 or 4 dice.

Your odds of getting 0 sixes on k-N dice without ones are (4/5)^(k-N), as before. Your odds of getting 1 six on (k-N) dice without ones are (k-N) * (4/5)^(k - N - 1) * 1 / 5

So the total likelihood of getting a 'critical' success (1 or fewer sixes) with N ones is (4^(k-N) + 4^(k - N - 1) * (k - N)) / 5 ^ (k - N)

This means that the chance of a critical success with N ones is:

C(N, k) * (4^(k-N) + 4^(k-N-1)) / 6^k

4 dice: (1 * 4^0 + 4 * (4 + 1)) / 6^4 (either 4 ones, or 3 ones and the last die could be a six, as it is dropped) = 21 / 1296
5 dice: (1 * 4^0 + 5 * (4 + 1) + 10 * (16 + 2 * 4)) / 6^5 (5 ones, 4 ones and the last die does not matter, or 3 ones and anything but 2 sixes) = 266 / 7776 (a lot more common)

etc.

You can extend the math to allow for dropping 2 dice.

If you must drop dice even if they are successes, you only have a problem with 3 dice (where criticals are no longer possible since you have only 2 dice), as with 4 or more dice you still get a critical success if you roll 3 or more ones - you can drop the 4th die whether it's a one or not and it won't affect your critical.



The success / failure criterion is simple on its own: the probability of getting N successes on k dice, with each die being a success with probability p is:

C(N, k) * p^N * (1-p)^(k-N)

And you just add them as required.

If your target number is 5, the probability of success is p = 5/6. If it's 3, the probability is p = 3/6 = 1/2. And so forth.


Dropping one die means that if you were to get k successes, you now have one less. If you were to have less than k successes, you have one less failure, so your total number of successes does not change. Therefore, the probability of getting k successes is zero, and the probability of getting k-1 successes is incremented by the probability of getting k successes.

Dropping two dice works more or less the same way: k successes become k - 2 successes, k-1 successes becomes k-2 successes as well (dropping one success and one failure), k-2 or less successes are not changed.

H2SO4
2013-07-14, 02:17 PM
I took about 5 minutes to write up a (very slow and poorly formatted) ruby script.

Wow, thanks.



Note that I made a few assumptions about your system:

- If your roll matches the target number exactly, it counts as a success rather than failure.

- Critical failure requires there be no 1s, just as a critical success requires there be no 6s.


The dice are summed together. Under or exact counts as success yes, but for crit fail you only need three sixes, ones don't help. This makes high-dice throws quite risky.

The system was made by our GM. In it, the number of dice represents the difficulty of the task.



Just run the get_dist function (first argument is the number of d6 to roll, second argument is the target you want to roll under, third argument is how many dice to drop and is optional). For a large number of dice (more than like 5 or 6) expect the script to take a few minutes to calculate the results: With a brute-force algorithm like this there's not much to be done to fix that.


How do I run this, do I need specific software or ... I'll try Googling it. :smallsmile:

Craft (Cheese)
2013-07-14, 08:35 PM
Under or exact counts as success yes, but for crit fail you only need three sixes, ones don't help.

Alright, that's a simple one-line fix.


How do I run this, do I need specific software or ... I'll try Googling it. :smallsmile:

To get it to work on your computer, you'll need a Ruby environment. If you just wanna run it and see what it does though you can use a website like codepad (http://codepad.org) to run it for you, but unfortunately codepad seems to be using an outdated version of Ruby and breaks under my code, so I had to modify it a bit to make it work:


class Array
def count(n)
s = 0
for i in self
if i == n
s += 1
end
end
return s
end
end

class Distribution
def initialize(h)
@h = h
@h.default = 0
end

def convolute(d,f)
posses = Hash.new
posses.default = 0
@h.each_key do |i|
d.h.each_key do |j|
posses[f.call(i,j)] += @h[i] * d.h[j]
end
end
return Distribution.new(posses)
end

def plus(d)
self.convolute(d,Proc.new {|i,j| i + j})
end

def g_convolute(ary,f)
def pass(a,k)
m = []
for i in a
for j in k
m.push(i.dup.push(j))
end
end
return m
end

ary.unshift(self)
k = []
for i in ary
k.push(i.h.keys)
end
posses = []
m = k.shift
for i in m
posses.push([i])
end
for i in k
posses = pass(posses,i)
end
mn = Hash.new
mn.default = 0
for i in posses
index = f.call(i)
value = 1
for j in Array(0..(i.length-1))
value *= ary[j].h[i[j]]
end
mn[index] += value
end
return Distribution.new(mn)
end

def exactly(n)
s = 0
for i in @h.values
s += i
end

(@h[n] / s.to_f).to_s
end

def self.dice(n,d)
m = Hash.new
for i in Array(1..d)
m.store(i,1)
end
h = Distribution.constant(0)
(n).times do
h = h.plus(Distribution.new(m))
end
return h
end

def self.constant(n)
Distribution.new({n => 1})
end

attr_reader :h
end

def get_proc(target,drop=0)
Proc.new do |ary|
if drop > 0
a = ary.sort.first(ary.size-drop)
else
a = ary
end
s = 0
for i in a
s += i
end
if a.count(1) >= 3 and a.count(6) == 0
2
elsif a.count(6) >= 3
-1
elsif s <= target
1
else
0
end
end
end

def get_dist(dice,target,drop=0)
ary = []
(dice-1).times do
ary.push(Distribution.dice(1,6))
end
d = Distribution.dice(1,6).g_convolute(ary,get_proc(ta rget,drop))
puts dice.to_s + "d6, TN " + target.to_s + ", Drop highest " + drop.to_s
puts "Critical Fail - " + d.exactly(-1) + "%"
puts "Fail - " + d.exactly(0) + "%"
puts "Success - " + d.exactly(1) + "%"
puts "Critical Success - " + d.exactly(2) + "%"
end

get_dist(6,20,1)

You can find the code here (http://codepad.org/uJ0hxu9m). Modify those last three numbers in the get_dist function to modify the output (the change to how critical failures work has already been put in).