7
\$\begingroup\$

I am learning the basics of AnyDice, and have seen it used to accomplish some rather complex algorithms. I'm running into a very rudimentary problem.

Say I want to roll a pool of five ten-sided dice, find the maximum value rolled on a single die in the pool, and then count the number of times this same value appears in the pool (This seems like an odd thing to look for, but it's important as a part of a larger program I want to write.)

For example, If I rolled the values {1,4,8,9,9} on a particular toss, the result would be 2 (The maximum value, 9, appears twice).

I try to accomplish this with the following bit of code:

XROLL: 5d10

XMAX: [highest 1 of XROLL]

output [count XMAX in XROLL]

With these results:

0,59.049

1,32.805

2,7.29

3,0.81

4,0.045

5,0.001

Now, the mere fact that a count of zero appears in the results suggests something is wrong. I suspect that what is happening is that the code takes one particular toss of 5d10 when it calculates XMAX, then tosses again before finding the count of XMAX, which introduced the possibility that the XMAX found in the first toss does not even appear in the second.

What I need is some way to 'freeze' the roll and convert it to a static sequence so I can dissect the specific values found in it, and not re-roll every time I reference XROLL. Can someone confirm that AnyDice is, indeed, re-rolling every time I invoke XROLL, and suggest how to get around this?

I apologize if any of the wording is unclear or I'm not using the right terminology.

\$\endgroup\$
  • \$\begingroup\$ fyi, while this is totally on topic here, you could also post this on SO. Furthermore '>' format is typically used for quotes here, while <code> code tags </code> is used for code snippets (you can also use 4 ens to start one). \$\endgroup\$ – Please stop being evil Mar 9 '15 at 1:48
  • 1
    \$\begingroup\$ @thedarkwanderer just <code></code> is only for inline code like I did just then; our code blocks use <pre><code>.... \$\endgroup\$ – doppelgreener Mar 9 '15 at 4:58
  • 1
    \$\begingroup\$ I'd like to clarify something here: from what I understand of the question, there are two factors important to know. One is the score of the highest dice, the second is how many times it appears. Additionally, these stay separate: you're not interested in finding the odds of your score if you add those maximum dice together (e.g. get 2 10's, your score is 20). Is that all accurate? \$\endgroup\$ – doppelgreener Mar 9 '15 at 5:01
5
\$\begingroup\$

Anydice always works with dice sequences, it doesn't actually "roll" anything. A d6 is actually {1,2,3,4,5,6}. 2d4 are {2,3,3,4,4,4,5,5,5,5,6,6,6,7,7,8} when they are output (they are stored as separate dice before that). XMAX is a sequence with a lot of 10s in it and a diminishing amount of other numbers - each possible combination of 5d10 is considered.

[count XMAX in XROLL] asks anydice how many times every value of XMAX occurs in each set of XROLL. A single value from the XMAX sequence, such as a 10, can occur 0-5 times in a roll of 5d10. More often than not, that single value won't appear in the roll at all, hence the predominant 0s in the final sequence.

That's what your result shows, which is not at all what you want. Except it kind of is, at least it unexpectedly comes close. What you want to find out is how often repeating values will be rolled - it makes no difference to the probabilities if it's 1s or 10s. So we will find the probability of rolling the same value as the first die on 4d10. This line of code should do it:

output 1+[count d10 in 4d10]

In it, d10 can be replaced by a single value such as 10, it won't make a difference. 1 is added to make the output match what your original question asks, as in, how many dice with highest values there will be in a roll.

However, this is an aggregate value and may not be that useful to you. To break it up into individual distributions for each maximum value we'll have to write a bit more code. This code was originally written by the dark wanderer, presented here with some modifications.

output 1@5d10 named "Chances of a particular highest value on 5d10"
\iterate over all possible highest values, starting at 10\
loop MAX over {10,9,8,7,6,5,4,3,2,1}
{output [count MAX in 4dMAX]+1 named "Matches when highest value is [MAX]"}

(run it here)

Since we know (by arbitrarily setting it) the highest value in our roll, MAX, every other roll will be 1..MAX. All we have to do is count the number of times MAX appears in it.

If you want to find the probability of any specific combination of highest value and number of matches you can just multiply the two relevant probabilities together.

\$\endgroup\$
  • \$\begingroup\$ Does this actually work? It doesn't appear to compare the remaining four d10s to each other for matches, only against the first d10. \$\endgroup\$ – SevenSidedDie Mar 8 '15 at 19:11
  • \$\begingroup\$ @SevenSidedDie It works. I have no idea why it works, but it works. (and I'm minoring in Math). I've posted a somewhat more intuitive answer which gets the same results (but is way longer). Not comparing the additional dice doesn't matter because they all need to be equal to the highest rolled number but I'm not sure sure why the additional chance of rolling multiples when the highest die rolled is low cancels out exactly with the lower chance of a low number being the highest number. \$\endgroup\$ – Please stop being evil Mar 9 '15 at 4:58
5
\$\begingroup\$

I suspect that what is happening is that the code takes one particular toss of 5d10 when it calculates XMAX, then tosses again before finding the count of XMAX, which introduced the possibility that the XMAX found in the first toss does not even appear in the second.

Yes, that's exactly what's happening. Basically, a "die" variable in AnyDice represents a certain probability distribution (over numbers, or sequences of numbers). Every time you use the die in an expression, AnyDice treats it as a separate, independent roll with that distribution.

Here's a simple program to demonstrate this:

DIE: 1d6
output DIE - DIE named "you'd think this should be zero, but it's not..."

If DIE represented a specific number rolled using 1d6, then DIE - DIE should always be zero. But it's not, as running the program above will easily demonstrate.

In fact, what's going on is that DIE here is just an alias for 1d6, so DIE - DIE is the same as 1d6 - 1d6; i.e. (the distribution of) the difference between two separate 1d6 rolls.

What I need is some way to 'freeze' the roll and convert it to a static sequence so I can dissect the specific values found in it, and not re-roll every time I reference XROLL. Can someone confirm that AnyDice is, indeed, re-rolling every time I invoke XROLL, and suggest how to get around this?

There is, indeed, a way to do "freeze" a die like this: pass the die to a function that expects a number or a sequence. Like this:

function: test ROLL:n {
  result: ROLL - ROLL
}
output [test 1d6] named "this really is always zero"

Here's the relevant quote from the AnyDice documentation (emphasis mine):

Parameter types

The variables inside a function's name are the parameters it operates on. It is possible to constrain these parameters to a specific type. You do this by following a variable with a colon, then a character indicating its type. Use n for numbers, d for dice, and s for sequences. The behavior of a function depends on what type of value it expects and what type of value it actually receives.

Expecting a number

If a sequence is provided, then the sequence will be summed. If a die is provided, then the function will be invoked for all numbers on the die – or the sums of a collection of dice – and the result will be a new die.

Expecting a die

If a number is provided, then it will be converted to a die that can roll only that number. If a sequence is provided, then the sequence will be summed and treated the same as a number.

Expecting a sequence

If a number is provided, then it will be converted to a sequence containing only that number. If dice are provided, then the function will be invoked for all possible sequences that can be made by rolling those dice. In that case the result will be a new die.

For example, here's how to count how many times the highest number occurs in a set of rolled dice:

function: count highest in ROLL:s {
  MAX: 1@ROLL
  result: ROLL = MAX
}
output [count highest in 5d10]

(A bit of explanation about the function body might be in order. The syntax 1@ROLL gives the first value in the sequence ROLL; AnyDice sorts dice rolls in descending order by default, so this will be the highest number rolled. The comparison ROLL = MAX then counts how many times the number MAX occurs in the sequence ROLL. And yes, I could've just written result: ROLL = 1@ROLL, but that would've been even more cryptic. Anyway, it's all in the documentation, under "Sequences" and "Introspection".)

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.