As I was developing different calculators for my theoryhammering, I felt some numbers were recurring on a regular basis.. and some techniques felt "the same" with only some minor differences here and there. With maths and programming, you try to discover the general pattern that's being reused all the time so you can formulate it once for all applications.
Looking for such a solution comes paired with the usual frustration of solving any logical puzzle: it seems hard at first, until you find the solution and then you smack yourself on the head for its simplicty. Perhaps the solution was known to you, or perhaps you find yourself annoyed at having to reinvent something "very similar" with every application, like me.
I know some of us like to employ numbers in their research, so I thought I'd share my solution that might help you compute... a pretty big deal of things.
The mathematical explanation
We start with a single example. Suppose we have a character attacking a model, and we have the following scores:
- 0 wounds done: 40% chance
- 1 wound done: 40% chance
- 2 wounds done: 20% chance
We could denote Wx as X wounds done. We can then write our character's score as:
Score_character = (40% W0 + 40% W1 + 20% W2)
Now we want to combine this with a supporting attack from his horse, which has the following scores:
- 0 wounds done: 80% chance
- 1 wound done: 20% chance
Score_horse = (80% W0 + 20% W1)
To combine them both... We simply need to multiply this:
(40% W0 + 40% W1 + 20% W2) * (80% W0 + 20% W1)
= 40% W0 * 80% W0 + 40% W0 * 20% W1 + 40% W1 * 80% W0 + 40% W1 * 20% W1 + 20% W2 * 80% W0 + 20% W2 * 20% W1
But we're not really interested in something this complex. We want to see the combined result, so we consider that "W2 * W0 = W(2+0) = W2" (2 wounds done by the character, 0 by the horse) combines to W2 (2 wounds total).
We get:
32% W0 + 8% W1 + 32% W1 + 8% W2 + 16% W2 + 4% W3
which becomes:
32% W0 + 40% W1 + 24% W2 + 4% W3
And voila. We have 24% chance to get 0 wounds, 40% for 1, 24% for 2 and 4% for 3.
A simple php function (and one to help us)
In programming, we could simply write something like "40% W0 + 40% W1 + 20% W2" as an array, with the wounds" as indexes and the percentages as their respective values. For example, in PHP we could write:
Code: Select all
//php arrays start at index 0, so we can just write:
$score_character = array(0.4, 0.4, 0.2);
$score_horse = array(0.8, 0.2);
print_r($score_character); //prints the scores of the character
print_r($score_horse); //prints the scores of the horse
To multiply these scores, we can write a simple function:
Code: Select all
/**
* multiply_arrays
*
*/
function multiply_arrays($first, $second){
//this iniatilizes the array.. nothing more.
$result = array_fill(min(array_keys($first)) + min(array_keys($second)), max(array_keys($first)) + max(array_keys($second)) - min(array_keys($first)) - min(array_keys($second)) + 1, 0);
// the "multiplication"
forEach($first as $i => $first_chance) {
forEach($second as $j => $second_chance) {
// mind, it -adds- the chance
$result[($i+$j)] += $first_chance * $second_chance;
}
}
return $result;
}
$score_combined = multiply_arrays($score_character,$score_horse);
print_r($score_combined);
/* prints:
Array
(
[0] => 0.32
[1] => 0.4
[2] => 0.24
[3] => 0.04
)
*/
Let's take it one step further. We could have a horde of corsairs fighting empire troopers (WS3, T3, 5+AS). Each attack has a 34.5679% chance of scoring a wound. We have 41 attacks, which we could write as:
(65.4321% W0 + 34.5679 % W1)^41
We don't want to code 41 multiplies, so we use a helper function:
Code: Select all
/**
* array_to_power
*
*/
function array_to_power($base, $power){
$result = array(1);
for($i=0; $i<$power;$i++) {
$result = multiply_arrays($result, $base);
}
return $result;
}
$score_corsair = array(0.65432098765432098765432098765432, 0.34567901234567901234567901234568);
$score_corsair_unit = array_to_power($score_corsair, 41);
print_r($score_corsair_unit); // score breakdown per number of wounds done by the corsair unit
Multiple Wounds and Killing Blow
In previous methods that I used (mostly binomial coefficients) it was hard to combine killing blow and multiple wounds at the same time. No longer.
Now imagine we have a Hero with a lance and the Twillight Cloak charging into warhounds. Those creatures have 2 wounds, so both the multiple wounda and killing blow have a special value. We get:
- 0 wounds: 13.58%
- 1 wound: 23.05% because (8/9 to hit) * (4/6 to wound without killing blow) * (7/6 from murderous prowess) * (1/3 from d3 multiple wounds)
- 2 wounds: 46.091% (from multiple wounds) + 17.284% from killing blow = 63.37%
We have three attacks, so we use our function as follows:
Code: Select all
$score_twillight = array(0.1358, 0.2305 , 0.6337);
$score_character_charge = array_to_power($score_twillight, 3);
print_r($score_character_charge);
/* Prints out:
Array
(
[0] => 0.0025045113192245
[1] => 0.012750239443325
[2] => 0.056699928433573
[3] => 0.13124121579435
[4] => 0.26459966602334
[5] => 0.27767188121019
[6] => 0.254532557776
)
*/
Dice scores
We're not limited to kill scores. For example, a single dice outcome could be written as:
Score_dice = 0% D0 + 1/6 D1 + 1/6 D2 + 1/6 D3 + 1/6 D4 + 1/6 D5 + 1/6 D6
Where Dx denotes the outcome of the dice roll.
Throwing 3 dice then becomes:
Code: Select all
// we begin with 0, because we can't roll "0" on a d6
$score_1d6 = array(0, 1/6, 1/6, 1/6, 1/6, 1/6, 1/6);
$score_3d6 = array_to_power($score_1d6, 3);
print_r($score_3d6);
/* Prints out:
Array
(
[0] => 0
[1] => 0
[2] => 0
[3] => 0.0046296296296296
[4] => 0.013888888888889
[5] => 0.027777777777778
[6] => 0.046296296296296
[7] => 0.069444444444444
[8] => 0.097222222222222
[9] => 0.11574074074074
[10] => 0.125
[11] => 0.125
[12] => 0.11574074074074
[13] => 0.097222222222222
[14] => 0.069444444444444
[15] => 0.046296296296296
[16] => 0.027777777777778
[17] => 0.013888888888889
[18] => 0.0046296296296296
)
*/
And yes, we can calculate the chance for irresistable force too, by calculating the number of 6's we roll. We have 5/6 chance to roll something other than a 6 on a single dice, and 1/6 chance to roll a 6:
Code: Select all
// we begin with 0, because we can't roll "0" on a d6
$sixes_on_1d6 = array(5/6, 1/6);
$sixes_on_3d6 = array_to_power($sixes_on_1d6, 3);
print_r($sixes_on_3d6);
/* Prints out
Array
(
[0] => 0.5787037037037
[1] => 0.34722222222222
[2] => 0.069444444444444
[3] => 0.0046296296296296
)
*/
We can simply add the chance to have 2 or 3 sixes to know our chance on IF or subtract the chances to get 0 or 1 sixes from 100%.
Code: Select all
// Prints 0.074074074074074
print($sixes_on_3d6[2]+$sixes_on_3d6[3]);
// Prints 0.074074074074074
print(1 - $sixes_on_3d6[0] - $sixes_on_3d6[1]);
Final remarks
Some dice strategies, like discarding or adding dice after a throw, are more difficult to model with this formula. But when it comes to our commonly used dice rolls, cast values, kill scores.. this one formula manages to tackle a considerable amount of situations and probably more than I have seen before. In particular, when it comes to combinations of killing blow with multi wound opponents, multiple wound attacks or combinations of both I haven't found many numbers on this at all. This one formula provides the answer I've been looking for, for quite some time.
External sources
The code used in this topic can be checked here:
http://sandbox.onlinephpfunctions.com/c ... ec49290c03