Created
April 3, 2013 19:29
-
-
Save dmdavis/5304474 to your computer and use it in GitHub Desktop.
Functions for calculating Savage Worlds dice probabilities.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# encoding: utf-8 | |
""" | |
swdiceprob.py | |
Functions for calculating Savage Worlds dice probabilities. | |
Copyright (c) 2012-2013 Dale Davis. All rights reserved. | |
Redistribution and use in source and binary forms, with or without | |
modification, are permitted provided that the following conditions are met: | |
* Redistributions of source code must retain the above copyright notice, this | |
list of conditions and the following disclaimer. | |
* Redistributions in binary form must reproduce the above copyright notice, | |
this list of conditions and the following disclaimer in the documentation | |
and/or other materials provided with the distribution. | |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | |
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
""" | |
__author__ = "Dale Davis" | |
__copyright__ = "Copyright (c) 2012-2013 Dale Davis. All rights reserved." | |
__license__ = "BSD-2-Clause" | |
__version_info__ = (1, 0) | |
__version__ = '.'.join([str(v) for v in __version_info__]) | |
import sys | |
from fractions import Fraction | |
def exploding(target, sides): | |
"""Calculate the probability (as a rational number) of hitting a `target` | |
number with an exploding dice with the given number of `sides`. | |
:param target: The target number the roll is attempting | |
:type target: int | |
:param sides: The number of sides on the dice used | |
:type sides: int | |
:rtype : `fraction.Fraction` | |
""" | |
exact, remainder = divmod(target, sides) | |
exact_roll_prob = Fraction(1, pow(sides, exact)) # 1/n + 1/n + ... | |
last_roll_prob = Fraction(sides - (max(remainder, 1) - 1), sides) | |
return exact_roll_prob * last_roll_prob | |
def wild(target, sides, wild=6): | |
"""Calculate the probability (as a rational number) of hitting a `target` | |
number with an exploding die with the given number of `sides` and an | |
exploding wild die with `wild` sides (default: 6) . | |
:param target: The target number the roll is attempting | |
:type target: int | |
:param sides: The number of sides on the dice used | |
:type sides: int | |
:param wild: The number of sides on the wild die (default: 6) | |
:type wild: int | |
:rtype : `fraction.Fraction` | |
""" | |
a = exploding(target, sides) | |
b = exploding(target, wild) | |
return a + b - (a * b) | |
def print_dice_probabilities(targets, dice, calcprob, title=None): | |
"""Print a tab-delimited table of `dice` probabilities to hit a list of | |
`targets`. | |
:param targets: A list of target numbers | |
:type targets: list of ints | |
:param dice: A list of dice to calculate probabilities for | |
:type dice: list of ints | |
:param calcprob: A callable that takes target and die as args | |
:type calcprob: callable (either `exploding` or `wild`) | |
:param title: A text title to print before the chart (default: `None`) | |
:type title: str or None | |
""" | |
if title is not None: | |
print(title) | |
print('\t'.join(['Target'] + ['d' + str(d) for d in dice])) | |
for t in targets: | |
print('\t'.join([str(t)] + [str(float(calcprob(t, d))) for d in dice])) | |
def main(): # pragma: no cover | |
""" | |
Main method for dice.py | |
""" | |
targets = range(1, 21) | |
dice = [4, 6, 8, 10, 12] | |
print_dice_probabilities(targets, dice, exploding, 'Exploding Die') | |
print_dice_probabilities(targets, dice, wild, 'Wild Die') | |
return 0 | |
if __name__ == '__main__': # pragma: no cover | |
sys.exit(main()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment