1. ## Programming For 40k

So, I'm trying to figure out how to run a simulation of numbers.

Obliterators, in Warhammer 40,000, have really, REALLY random stats. And I want to run a simulation of them shooting at a target, with the randomness accounted for. To do that requires a LOT of manual effort, since there are 27 different combinations possible for their guns.

Does anyone know a quick and easy way to set this up for someone who doesn't know how to code?

Spoiler: More Details
Their Strength can be 7, 8, or 9, and they have a +1 to-wound. This means that they wound the target (a Repulsor in this case) on a 4+, 3+, or 2+.

Their AP can be -1, -2, or -3, meaning the Repulsor gets a 4+, 5+, or 6+ save.

And their Damage can be 1, 2, or 3.

2. ## Re: Programming For 40k

You want to go Monte Carlo. For each one, choose random values of each stat, and then calculate whether that one hit and how much damage it does. And then repeat a whole bunch of times. Don't worry about manually covering every possible combination; let the random number generator take care of that.

3. ## Re: Programming For 40k

Right. How do I do that?

4. ## Re: Programming For 40k

Monte Carlo seems a bit much for only 27 combinations. It should be reasonable to just calculate every outcome. A bit of Python-like pseudo-code:

Code:
```total = 0
count = 0
for strength in 7, 8, 9:
for ap in -1, -2, -3:
for damage in 1, 2, 3:
total += simulate_attack(strength, ap, damage)
count += 1
print('Average:', total / count)```
I don't know how 40K handles attack resolution, so I can't fill in simulate_attack. Assuming a simple dice roll you could again just go through each possibility and average the results. Displaying a bar graph rather than an average is left as an exercise for the reader.

This assume that each value of those three variables is equally likely. If not you would need to calculate a weighted average instead.

5. ## Re: Programming For 40k

Originally Posted by Excession
Code:
```total = 0
count = 0
for strength in 7, 8, 9:
for ap in -1, -2, -3:
for damage in 1, 2, 3:
total += simulate_attack(strength, ap, damage)
count += 1
print('Average:', total / count)```
You forgot the burning incense, sacred unguents and chanting by candle light.

6. ## Re: Programming For 40k

Originally Posted by Brother Oni
You forgot the burning incense, sacred unguents and chanting by candle light.
In addition Excession also forgot to import appease_MachineSpirit and PraiseEmperor, so that program is pretty likely to corrupt your computer :P

7. ## Re: Programming For 40k

Originally Posted by Randuir
In addition Excession also forgot to import appease_MachineSpirit and PraiseEmperor, so that program is pretty likely to corrupt your computer :P
Nah, so long as he doesn't directly call invoke_Slaanesh he'll be fine.

8. ## Re: Programming For 40k

Originally Posted by factotum
Nah, so long as he doesn't directly call invoke_Slaanesh he'll be fine.
Doesn't all programming inherently invoke that function?

9. ## Re: Programming For 40k

Originally Posted by halfeye
Doesn't all programming inherently invoke that function?
Only javascript. Most of the others use tzeentchBlackBox.HopeItWorks(main)

Unless you're using a functional language, COBOL, or FORTRAN. Then it's Khorne for the functionals and usually Nurgle for the other two.

10. ## Re: Programming For 40k

Brute force and determination. And a little cheating.

Okay, step one is either a 3/6, 4/6 or 5/6 chance to wound, evenly distributed. So it's a 4/6, or 2/3, chance, because that's how averages work.

Step two is either a 3/6, 4/6 or 5/6 chance that the reppy fails its save. Again, that means it's a 2/3 chance for the same reason.

Finally, step 3 is an average of 2 wounds.

The chance that you wound is therefore 4/9, so you can expect to do 8/9 of a wound per shot. Alternatively, there's a 4/27 chance each of 1, 2, or 3 wounds, and therefore a 15/27=5/9 chance of no wounds (which you can also work out from the 4/9 chance that you will wound).

11. ## Re: Programming For 40k

Wouldn't a spreadsheet like excel work? No coding required. Just a few columns and then lots of lookup and stuff...

12. ## Re: Programming For 40k

Originally Posted by LordEntrails
Wouldn't a spreadsheet like excel work? No coding required. Just a few columns and then lots of lookup and stuff...
Yes.

But that requires sacrifices to all the known* Chaos Gods.

*and a couple of unknown ones

And for the record, using either appease_MachineSpirit or PraiseEmperor in conjuction with Obliterators immediately triggers the doExterminatus.Inquisitor(random_value) error and there's just no way to trap or handle that.

13. ## Re: Programming For 40k

So, to complete what's needed...

Spoiler: Psychic
Roll 2d6. If equal to or greater than 7, assign "Yes" to "Reroll 1s" and move to next step. If less than 7, reroll the lower die once. If equal to or less than 6 after reroll, assign "No" to "Reroll 1s".
Roll 2d6, If equal to or greater than 6, assign "Yes" to "+1 Hit" and move on to next step. If less than 6, reroll the lower die once, but only if no reroll was used in the first step. If equal to or less than 5 after reroll, assign "No" to "+1 Hit".

Spoiler: Stat Assignment
Roll 1d3+6, assign to Strength.
Roll 1d3, assign to AP.
Roll 1d3. If equal to 1, reroll once. Assign to Damage.

Spoiler: Shooting
Roll 1d6. If equal to or greater than 3, hit and move to next step. If equal to 1, reroll once, if "Reroll 1s" is "Yes". Add +1 to the roll if "+1 Hit" is "Yes".
Roll 1d6. If Strength equals 7, move on to next step on equal to or greater than 4. If Strength equals 8, move on to the next step on equal to or greater than 3. If Strength equals 9, move on to the next step on equal to or greater than 2. If equal to 1 (regardless of what Strength is), reroll once, if "Reroll 1s" is "Yes".
Roll 1d6. If AP equals 1, move on to the next step if equal to or less than 3. If AP equals 2, move on to the next step if equal to or less than 4. If AP equals 3, move on to the next step if equal to or less than 5.
Assign damage, equal to the Damage value. Once total damage equals 18, stop.

Repeat the entirety of the shooting up to 18 times or whenever damage dealt reaches 18, whichever comes first.

Record total damage dealt.

Spoiler: Endless Cacophony
To do Endless Cacophony, repeat Stat Assignment, but only reroll 1 on Damage if a reroll has not already been used on Damage.

Then, repeat Shooting. If total damage was less than 18, add to existing total and stop at 18. If total damage was 18, repeat shooting with a new total.

Add the two totals together, if there are two totals, to record final damage dealt.

Does this make it clearer how to do it?

14. ## Re: Programming For 40k

Originally Posted by JNAProductions
So, to complete what's needed...

Spoiler: Psychic
Roll 2d6. If equal to or greater than 7, assign "Yes" to "Reroll 1s" and move to next step. If less than 7, reroll the lower die once. If equal to or less than 6 after reroll, assign "No" to "Reroll 1s".
Roll 2d6, If equal to or greater than 6, assign "Yes" to "+1 Hit" and move on to next step. If less than 6, reroll the lower die once, but only if no reroll was used in the first step. If equal to or less than 5 after reroll, assign "No" to "+1 Hit".

Spoiler: Stat Assignment
Roll 1d3+6, assign to Strength.
Roll 1d3, assign to AP.
Roll 1d3. If equal to 1, reroll once. Assign to Damage.

Spoiler: Shooting
Roll 1d6. If equal to or greater than 3, hit and move to next step. If equal to 1, reroll once, if "Reroll 1s" is "Yes". Add +1 to the roll if "+1 Hit" is "Yes".
Roll 1d6. If Strength equals 7, move on to next step on equal to or greater than 4. If Strength equals 8, move on to the next step on equal to or greater than 3. If Strength equals 9, move on to the next step on equal to or greater than 2. If equal to 1 (regardless of what Strength is), reroll once, if "Reroll 1s" is "Yes".
Roll 1d6. If AP equals 1, move on to the next step if equal to or less than 3. If AP equals 2, move on to the next step if equal to or less than 4. If AP equals 3, move on to the next step if equal to or less than 5.
Assign damage, equal to the Damage value. Once total damage equals 18, stop.

Repeat the entirety of the shooting up to 18 times or whenever damage dealt reaches 18, whichever comes first.

Record total damage dealt.

Spoiler: Endless Cacophony
To do Endless Cacophony, repeat Stat Assignment, but only reroll 1 on Damage if a reroll has not already been used on Damage.

Then, repeat Shooting. If total damage was less than 18, add to existing total and stop at 18. If total damage was 18, repeat shooting with a new total.

Add the two totals together, if there are two totals, to record final damage dealt.

Does this make it clearer how to do it?
Yeah, I think so. The following piece of python code runs one instance of shooting and prints the damage:
Spoiler

Code:
```from random import *
"""
import Praise_Emperor
import appease_MachineSpirit
"""
"""
psychic
"""
#rerolls
psy1_a=randint(1,6)
psy1_b=randint(1,6)
if psy1_a+psy1_b<7:
use_psy_reroll=1
if psy1_a<psy1_b:
psy1_a=randint(1,6)
else:
psy1_b=randint(1,6)

if psy1_a+psy1_b>=7:
reroll1=1
else:
reroll1=0
else:
use_psy_reroll=0
reroll1=1

#+1 to hit
psy2_a=randint(1,6)
psy2_b=randint(1,6)
if psy2_a+psy2_b<6 and use_psy_reroll==0:
use_psy_reroll=1
if psy2_a<psy2_b:
psy2_a=randint(1,6)
else:
psy2_b=randint(1,6)

if psy2_a+psy2_b<6:
bonus_tohit=0
else:
bonus_tohit=1
elif psy2_a+psy2_b>6:
bonus_tohit=1
else:
bonus_tohit=0

"""
stats
"""
endless=0
use_damage_reroll=0
damage_count=0
damage_count_save=0
while endless<2:
strength=randint(1,3)+6
AP=randint(1,3)
damage=randint(1,3)
if damage==1 and use_damage_reroll==0:
damage=randint(1,3)
use_damage_reroll=1

strength_target=11-strength
AP_target=2+AP

"""
shooting
"""
shot_count=0
while damage_count<18 and shot_count<18:
#hitting
tohit=randint(1,6)
if tohit==1 and reroll1==1:
tohit=randint(1,6)

if tohit+bonus_tohit>=3:
#wounding
wound=randint(1,6)
if wound==1 and reroll1==1:
wound=randint(1,6)

if wound>=strength_target:
#armor_piercing
pierce=randint(1,6)
if pierce>=AP_target:
damage_count+=damage
shot_count+=1
if damage_count>=18:
damage_count_save=damage_count
damage_count=0

endless+=1
print damage_count+damage_count_save```

if you're looking for average damage over long periods of time, use something like this instead:
Spoiler

Code:
```from random import *
"""
import Praise_Emperor
import appease_MachineSpirit
"""
run=0
damage_total=0
while run<10000:
run+=1
"""
psychic
"""
#rerolls
psy1_a=randint(1,6)
psy1_b=randint(1,6)
if psy1_a+psy1_b<7:
use_psy_reroll=1
if psy1_a<psy1_b:
psy1_a=randint(1,6)
else:
psy1_b=randint(1,6)

if psy1_a+psy1_b>=7:
reroll1=1
else:
reroll1=0
else:
use_psy_reroll=0
reroll1=1

#+1 to hit
psy2_a=randint(1,6)
psy2_b=randint(1,6)
if psy2_a+psy2_b<6 and use_psy_reroll==0:
use_psy_reroll=1
if psy2_a<psy2_b:
psy2_a=randint(1,6)
else:
psy2_b=randint(1,6)

if psy2_a+psy2_b<6:
bonus_tohit=0
else:
bonus_tohit=1
elif psy2_a+psy2_b>6:
bonus_tohit=1
else:
bonus_tohit=0

"""
stats
"""
endless=0
use_damage_reroll=0
damage_count=0
damage_count_save=0
while endless<2:
strength=randint(1,3)+6
AP=randint(1,3)
damage=randint(1,3)
if damage==1 and use_damage_reroll==0:
damage=randint(1,3)
use_damage_reroll=1

strength_target=11-strength
AP_target=2+AP

"""
shooting
"""
shot_count=0
while damage_count<18 and shot_count<18:
#hitting
tohit=randint(1,6)
if tohit==1 and reroll1==1:
tohit=randint(1,6)

if tohit+bonus_tohit>=3:
#wounding
wound=randint(1,6)
if wound==1 and reroll1==1:
wound=randint(1,6)

if wound>=strength_target:
#armor_piercing
pierce=randint(1,6)
if pierce>=AP_target:
damage_count+=damage
shot_count+=1
if damage_count>=18:
damage_count_save=damage_count
damage_count=0

endless+=1
damage_total+=damage_count+damage_count_save

print "average damage is ",damage_total/10000.```

#### Posting Permissions

• You may not post new threads
• You may not post replies
• You may not post attachments
• You may not edit your posts
•