Reroll from pools

## Reroll from pools

 Tue Jan 6 18:05:15 2015   by   DCLXVI Hi Torben,Awesome tool you wrote there.I'm trying to check it with WH40K rules, and I can do mostly what I intend to, but I'm stuck on the last part.The principle is a pool of dice, rolled to hit, then hits are rolled to wound, then wounds are rolled for saves.I managed to do that fine.The issue is when I implement rerolls.i.e. I want to include a reroll for dices lower or equal than a value (for missed hits and missed wounds). That would allow to reroll just all ones or all missed.I managed to get something that seems to provide the good average, but that is wrong because the number of outcomes is larger than what is expected.Here is my entry :\ Warhammer 40,000 Unsaved Wounds Calculator including rerolls on hit/wounds\ **** ParametersDICE := 10; \ Set to 10 for 10 attacksTOHIT := 4; \ Set 4 for 4+ to hit TOWOUND := 3; \ Set 3 for 3+ to woundTOSAVE := 6; \ Set 6 for 6+ save (7 is no save)TOREROLLHIT := 1; \ 0 = No reroll for missed hits ; \ X = reroll all that are <= X ; \ i.e. if hit on 4+, reroll all missed is X = 3 ; \ i.e. if reroll only ones then X = 1TOREROLLWOUND := 1; \ 0 = No reroll for missed wounds ;\  X = reroll all that are <= X ;\ i.e. if wounds on 3+, reroll all missed is X = 2 ;\ i.e. if reroll only ones then X = 1\ **** ComputationHIT := count TOHIT <= DICE # d6;RETRYHIT := count TOREROLLHIT >= DICE # d6;REROLLHIT := count TOHIT <= RETRYHIT # d6;TOTALHIT := HIT + REROLLHIT;WOUND := count TOWOUND <= TOTALHIT # d6;RETRYWOUND := count TOREROLLWOUND >= TOTALHIT # d6;REROLLWOUND := count TOWOUND <= RETRYWOUND # d6;TOTALWOUND := WOUND + REROLLWOUND;UNSAVED := count TOSAVE > TOTALWOUND # d6;UNSAVEDThe result should have 10 different outcomes as there can be 1 to 10 hits with those 10 attacks, however I get 40 outcomes.Also everything seems ok when there are no rerollsI suspect that the problem comes from the two + I do with the collections, so I suppose I have to do the whole thing differently, but maybe there is something I missed.Thanks in advance Wed Jan 7 09:35:28 2015   by   Torben The problem seems to be the lines`HIT := count TOHIT <= DICE # d6;RETRYHIT := count TOREROLLHIT >= DICE # d6;REROLLHIT := count TOHIT <= RETRYHIT # d6;TOTALHIT := HIT + REROLLHIT;`Here, you are rolling the same number of dice twice.  What you want is probably to reroll those dice in the first roll that are less than or equal to TOREROLLHIT.  You can do this in this way:`POOL := DICE d6;REROLLS := (count TOREROLLHIT >= POOL) d6;TOTALHIT := count TOHIT <= (POOL U REROLLS);`This assumes that TOREROLLHIT is less than TOHIT, but I expect that to be the case.The same modifications are needed also for the wound roll. Wed Jan 7 11:58:41 2015   by   DCLXVI Thank you Torben for the quick answer.It seems there is a problem though as I get a distribution timeout error after 60 seconds :Distribution error: Time limit exceeded (60001ms)Maybe it's too complex to evaluate.I managed to get the reroll for hits to work thanks to your post :I roll DICE d6 :`HITPOOL := DICE # d6;`From that, I count the number of hits `HITS := count TOHIT <= HITPOOL;`So I know that "count TOREROLLHIT >= HITPOOL" will give me the number that should be rerolled. So I need to count the hits when rolling "(count TOREROLLHIT >= HITPOOL) # d6" :`REROLLHITS := count TOHIT <= (count TOREROLLHIT >= HITPOOL) # d6;`So that gives me the hits from the rerolls, and I can then add that to the previous hits.`TOTALHITS := HITS + REROLLHITS;`So the results seems ok so far. Now, I think it gets too 'exponential' from there when I add the wounds from those hits.Applying the same logic :`WOUNDPOOL := TOTALHITS # d6;`=> gets me the rolls for the totalhits, this gets already very long from here if I display WOUNDPOOL, and can timeout depending on the number of DICE.`WOUNDS := count TOWOUND <= WOUNDPOOL;`=> gets me the wounds from those rolls, oddly, when I display this, this is faster than displaying WOUNDPOOL... ? However with larger number of DICE this times out.`REROLLWOUNDS := count TOWOUND <= (count TOREROLLWOUND >= WOUNDPOOL) # d6;`=> gets me the wounds from rerolling those lower than TOREROLLWOUND`TOTALWOUNDS := WOUNDS + REROLLWOUNDS;`=> gets me the total wounds Wed Jan 7 12:55:27 2015   by   Torben If the total number of dice involved in the calculation is high, calculation can take a long time.  One way to reduce this is by making some of the bindings local.  For example, rewrite the sequence`HITPOOL := DICE # d6;HITS := count TOHIT <= HITPOOL;REROLLHITS := count TOHIT <= (count TOREROLLHIT >= HITPOOL) # d6;TOTALHITS := HITS + REROLLHITS;`to`TOTALHITS :=  (HITPOOL := DICE d6;    HITS := count TOHIT <= HITPOOL;    REROLLHITS := count TOHIT <= (count TOREROLLHIT >= HITPOOL) # d6;    HITS + REROLLHITS);and similarly for the wound calculation.  The point is that you don't need HITPOOL, HITS and REROLLHITS after you have calculated TOTALHITS, and making the definitions local, you an discard these after their use.` Wed Jan 7 17:10:14 2015   by   DCLXVI Thank you very much for the help.It seems that the calculation is ok and works with little pools of dice anyway.However, it seems already too complex starting with 15 dice and gets a timeout from the site.Will try the offline Troll version, however I have issues with the Moscow ML part (compiling issues as no valid compile Linux package) :'( Thu Jan 8 11:39:25 2015   by   Torben There is a Linux package on http://launchpad.net/~kflarsen/+archive/ubuntu/mosmlThis worked fine for me (using Ubuntu).15 dice means 615 combinations, so it should be no surprise that it can take a long time to compute.  There are a few tricks you can try to reduce this.  In addition to using local definitions as explaied above, you can reduce the number of different values on the dice.  You really only need to distinguish if the value is below the reroll limit, between the reroll limit and the to-hit limit or over the to-hit limit.  So if the reroll limit is 1 and to-hit is 4, you can roll a die with one 1, two 3s and three 6s instead of a d6, i.e., replace `d6` by `choose {1,3,3,6,6,6}`.So instead of the line`HITPOOL := DICE d6;`you can write`HITPOOL := DICE # choose {TOREROOLHIT # 1, (TOHIT - TOREROLLHIT -1) # (TOHIT - 1), (7 - TOHIT) # 6};` Thu Jan 8 18:31:13 2015   by   DCLXVI Thank you very much for the feedback, in the mean time I managed to find my way with mosml manually opening a .deb file for Ubuntu and fiddling around as my distribution was rpm-based. :)Yes the complexity added by rerolling even just failed hits is enormous. That's what I did not realize... Not rerolling failed hits/wound is far less complex.I've been trying to calculate the number of combinations for the various cases but my brain melted at some point. I ended up with :- something like or 63xDICE combinations maximum when not rerolling failed hit/wounds, so that's not that much to enumerate for a computer, even with DICE=120- and something like 6DICE6DICE or for just rerolling hits, so, even with DICE=10, this becomes huge,but as my brain melted I'm likely wrong somewhere...So yes, I think I have to try a different way as you suggest, to optimize stuff.I will give it some thinking, and I seriously need to review the theory, so I think a good read of your RPGdice paper may help for a start. :)Thank you for the feedback Mon Jan 12 17:41:51 2015   by   DCLXVI This works awesomely better with your last suggestion.So I got it to work very fast.Thank you very much again.