Thursday 30 July 2015

253: Mathhammer with GNU Octave

Many folk understand how to do basic mathhammer. For example 10 marines shooting bolters at marines (outside 12").

n_shots×prob_hit×prob_wound×prob_not_saved=mean_n_dead

10×(2/3)×(1/2)×(1/3)=1.1

It gets more complicated with things like rending. Still quite possible, but a bit more headscratching is required. Even trickier is shooting at vehicles. To do it properly you need to account for things like multiple immobilised results removing extra hull points.

There is a general method. You get a computer to roll the dice for you, lots of times and keep notes as it goes. This kind of thing is called a Monte Carlo Simulation. An early use was designing nuclear weapons in the second world war.

GNU Octave is a free (open source) maths scripting language. It's quite good for this sort of thing.
 To get octave to roll 10 dice, you can do this.

> rolls=ceil(rand(1,10)*6)
rolls =

   2   6   2   4   2   2   3   3   5   4


rand gives a matrix of 1×10 numbers. They are between 0 and 1, so you have to multiply by 6. We only want whole numbers, and dice don't give zeros, so we round up. This is what ceil (ceiling) does. Next, how many hit?

> passed=sum(rolls>=3)
passed =  6


rolls>=3 returns a matrix of 0s and 1s. As we need 3+ to hit, it gives 1s to represent the hits. sum adds up the hits. Roll some more dice to wound.

> rollstowound=ceil(rand(1,passed)*6)
rollstowound =

   1   2   4   3   4   2


Find out how many wounded

> wounds=sum(rollstowound>=4)
wounds =  2

Time for amour saves

> savingrolls=ceil(rand(1,wounds)*6)
savingrolls =

   4   1


How many die?

> deathtoll=sum(savingrolls<3)
deathtoll =  1


You can combine this lot into a script file ("example.m") that repeats 100 times.

n=100;
totaldead=0;
for i=1:n
    rolls=ceil(rand(1,10)*6);
    passed=sum(rolls>=3);
    rollstowound=ceil(rand(1,passed)*6);
    wounds=sum(rollstowound>=4);
    savingrolls=ceil(rand(1,wounds)*6);
    deathtoll=sum(savingrolls<3)
    totaldead=totaldead+deathtoll;
end
mean_dead=totaldead/n


Run this, and it spits out a number near 1.1. This is more hassle than first calculation, but when it gets more complicated simulations will beat the back of an envelope.

Note that I have put semicolons on the end of some lines. This suppresses output. So this script will just show you the deathtoll each loop, and the mean average at the end.

If there is some interest in the comments, I can expand this into a series of posts. Or, if I have time I can mathhammer on your behalf. My numbers are out of date now (vehicle damage table changed), but I did figure out the most cost effective way of taking down a Heldrake. At that time the highest probability of downing a heldrake in one per point spent that I could find was an Imperial Fist dev squad on a quad gun. The best value hull point stripper was a Stalker (you know, the Rhino chassis AA vehicle).

No comments:

Post a Comment

LinkWithin

Related Posts Plugin for WordPress, Blogger...