Beispiel #1
0
def plot_opposed_fixed_total(ax, single_die, die_counts, die_name):
    coef = 4.0 * single_die.mean() * single_die.mean() / single_die.variance()

    legend = []

    for die_count in die_counts:
        x = []
        cdf = []
        for die_count_a in range(die_count + 1):
            die_count_b = die_count - die_count_a

            die_bonus_a = numpy.sqrt(
                numpy.maximum(die_count_a * coef - variance_b, 0.0))
            die_bonus_b = numpy.sqrt(
                numpy.maximum(die_count_b * coef - variance_b, 0.0))

            opposed = single_die.repeat_and_sum(
                die_count_a) - single_die.repeat_and_sum(die_count_b)
            p = opposed >= Die.coin()
            x.append(die_bonus_b - die_bonus_a)
            cdf.append(p)

        pmf = (numpy.diff(cdf, prepend=0.0) +
               numpy.diff(cdf, append=1.0)) * 50.0
        marker = marker_map[die_count] if die_count in marker_map else '.'
        ax.plot(x, pmf, marker=marker)
        legend.append('%dd%s' % (die_count, die_name))
    ax.legend(legend, loc='upper right')
    ax.set_xlabel('Bonus disparity after conversion to roll-over')
    ax.set_ylabel('"Chance" (%)')
    ax.grid(which="both")
Beispiel #2
0
def plot_opposed_fixed_side(ax, single_die, die_counts, die_name):
    coef = 4.0 * single_die.mean() * single_die.mean() / single_die.variance()

    legend = []

    for die_count_a in die_counts:
        x = []
        ccdf = []
        for die_count_b in range(0, 100):
            die_bonus_a = numpy.sqrt(
                numpy.maximum(die_count_a * coef - variance_b, 0.0))
            die_bonus_b = numpy.sqrt(
                numpy.maximum(die_count_b * coef - variance_b, 0.0))

            opposed = single_die.repeat_and_sum(
                die_count_a) - single_die.repeat_and_sum(die_count_b)
            p = opposed >= Die.coin()
            # p = (opposed > 0) / ((opposed > 0) + (opposed < 0))
            x.append(die_bonus_b - die_bonus_a)
            ccdf.append(p)

        #pmf = (numpy.diff(cdf, prepend=0.0) + numpy.diff(cdf, append=1.0)) * 50.0
        pmf = -numpy.diff(ccdf, prepend=1.0) * 100.0
        marker = marker_map[die_count_a] if die_count_a in marker_map else '.'
        ax.plot(x + 0.5 * numpy.diff(x, append=x[-1]), pmf, marker=marker)
        legend.append('%dd%s' % (die_count_a, die_name))
    ax.legend(legend, loc='upper right')
    ax.set_xlabel('Bonus disparity after conversion to roll-over')
    ax.set_ylabel('"Chance" (%)')
    ax.grid(which="both")
    ax.set_ylim(bottom=0)
Beispiel #3
0
# Minimize distance on d20 curve.


def objective(sd):
    gaussian = Die.gaussian(10.5, sd)
    return Die.d20.ks_stat(gaussian)


print(
    scipy.optimize.minimize_scalar(objective,
                                   bounds=(5.0, 8.0),
                                   method='bounded'))

d20 = Die.d20

opposed_d20 = d20 - d20 - Die.coin()

figsize = (8, 4.5)
dpi = 150


def make_pmf_plot(die, offset=0, sd=None):
    if sd is None:
        gaussian = Die.gaussian(die)
    else:
        gaussian = Die.gaussian(die.mean(), sd)

    print('Var:', die.variance())
    print('MAD median:', die.mad_median())

    fig = plt.figure(figsize=figsize)
Beispiel #4
0
        fig = plt.figure(figsize=figsize)
        ax = plt.subplot(111)

        ax.plot(g_x, g_ccdf * 100.0, linestyle=':')
        ax.plot(x_ccdf, ccdf * 100.0, marker='.')

        ax.grid()
        ax.set_xlim(left, right)
        ax.set_xlabel('Deviation from mean (SDs)')
        ax.set_ylabel('Chance to hit (%)')
        ax.set_ylim(0, 100.0)
        ax.set_title('%d pool size (KS = %0.2f%%)' % (pool_size, ks * 100.0))
        ccdf_frame_path = 'output/frames/ccdf_%03d.png'
        plt.savefig(ccdf_frame_path % frame_index,
                    dpi = dpi, bbox_inches = "tight")
        plt.close()
    make_webm(pmf_frame_path, 'output/success_pool_roe_%s_pmf.webm' % name)
    make_webm(ccdf_frame_path, 'output/success_pool_roe_%s_ccdf.webm' % name)

#make_anim(Die.coin(1/6), 'd6_2plus')
#make_anim(Die.coin(2/6), 'd6_3plus')
make_anim(Die.coin(3/6), 'd6_4plus')
#make_anim(Die.coin(4/6), 'd6_5plus')
#make_anim(Die.coin(5/6), 'd6_6plus')
exalted2e = Die.from_faces([0]*6 + [1]*3 + [2])
owod = Die.from_faces([-1] + [0]*5 + [1]*4)
nwod = Die.from_faces([0]*7 + [1]*3).explode(10, chance=0.1)
#make_anim(exalted2e, 'exalted2e')
#make_anim(owod, 'owod')
#make_anim(nwod, 'nwod')
Beispiel #5
0
        legend.append('%d pips' % (pip_count, ))
    ax.legend(legend, loc='upper right')
    ax.set_xlabel('Roll-over number needed to hit')
    ax.set_ylabel('Chance (%)')
    ax.grid(which="both")


die_counts_simple = [1, 2, 3, 4, 5, 6, 8, 10, 15, 20]
die_counts_standard = die_counts_simple

# coin

fig = plt.figure(figsize=figsize)
ax = plt.subplot(111)

plot_pmf(ax, Die.coin(), die_counts_simple, '(d6>=4)')

ax.set_xlim(left=left, right=right)
ax.set_ylim(bottom=0)
plt.savefig('output/sum_pool_4plus.png', dpi=dpi, bbox_inches="tight")

# 2 plus on d6

fig = plt.figure(figsize=figsize)
ax = plt.subplot(111)

plot_pmf(ax, Die.coin(5 / 6), die_counts_simple, '(d6>=2)')

ax.set_xlim(left=left, right=right)
ax.set_ylim(bottom=0)
plt.savefig('output/sum_pool_2plus.png', dpi=dpi, bbox_inches="tight")
Beispiel #6
0
def test_coin():
    b = Die.bernoulli()
    c = Die.coin()

    assert b.pmf() == pytest.approx([0.5, 0.5])
    assert c.pmf() == pytest.approx([0.5, 0.5])
Beispiel #7
0
    ax.grid(which="both")
    ax.set_ylim(bottom=0)


die_counts_simple = [1, 2, 3, 4, 5, 6, 8, 10, 15, 20]
die_counts_standard = [1, 2, 3, 4, 5, 6]

left = -4
right = 4

# 3+ on d6

fig = plt.figure(figsize=figsize)
ax = plt.subplot(111)

plot_opposed_fixed_side(ax, Die.coin(2 / 3), die_counts_simple, '(d6>=3)')

ax.set_xlim(left=left, right=right)
plt.savefig('output/add_pool_opposed_3plus.png', dpi=dpi, bbox_inches="tight")

# coin

fig = plt.figure(figsize=figsize)
ax = plt.subplot(111)

plot_opposed_fixed_side(ax, Die.coin(), die_counts_simple, '(d6>=4)')

ax.set_xlim(left=left, right=right)
plt.savefig('output/add_pool_opposed_4plus.png', dpi=dpi, bbox_inches="tight")

# 5+ on d6
Beispiel #8
0
def make_anim(die, name):
    coef = 2.0 * die.mean() / die.standard_deviation()
    offset = offset_sd * offset_sd / (coef * coef)
    for frame_index, pool_size_a in enumerate(pool_sizes):
        die_bonus_a = coef * numpy.sqrt(pool_size_a + offset)
        pool_a = die.repeat_and_sum(pool_size_a)
        x = []
        ccdf = []
        for pool_size_b in range(0, 201):
            die_bonus_b = coef * numpy.sqrt(pool_size_b + offset)
            opposed = pool_a - die.repeat_and_sum(pool_size_b)

            p = opposed >= Die.coin()  # Coin flip on ties.
            # p = (opposed > 0) / ((opposed > 0) + (opposed < 0)) # Reroll ties.
            x.append(die_bonus_b - die_bonus_a)
            ccdf.append(p)
        x = numpy.array(x)
        ccdf = numpy.array(ccdf)
        pmf = -numpy.diff(ccdf, prepend=1.0)

        # compute ks
        ks_ccdf = 0.5 * scipy.special.erfc(x / 2.0)
        ks = numpy.max(numpy.abs(ccdf - ks_ccdf))

        # pmf plot
        fig = plt.figure(figsize=figsize)
        ax = plt.subplot(111)
        g_x = numpy.arange(left, right + 0.001, 0.001)
        g_pmf = numpy.exp(-0.5 * numpy.square(g_x / numpy.sqrt(2))) / (
            2.0 * numpy.sqrt(numpy.pi))
        ax.plot(g_x, g_pmf, linestyle=':')
        ax.plot(x + 0.5 * numpy.diff(x, append=x[-1]),
                pmf * pool_a.standard_deviation() * 2.0,
                marker='.')
        ax.grid()
        ax.set_xlim(left, right)
        ax.set_xlabel('Difference in roll-over result')
        ax.set_ylabel('Normalized probability')
        ax.set_ylim(0, 0.3)
        ax.set_title('%d pool size for side A (KS = %0.2f%%)' %
                     (pool_size_a, ks * 100.0))
        pmf_frame_path = 'output/frames/pmf_%03d.png'
        plt.savefig(pmf_frame_path % frame_index, dpi=dpi, bbox_inches="tight")
        plt.close()

        # ccdf plot
        fig = plt.figure(figsize=figsize)
        ax = plt.subplot(111)
        g_x = numpy.arange(left, right + 0.001, 0.001)
        g_ccdf = 50.0 * scipy.special.erfc(g_x / 2.0)
        ax.plot(g_x, g_ccdf, linestyle=':')
        ax.plot(x, ccdf * 100.0, marker='.')
        ax.grid()
        ax.set_xlim(left, right)
        ax.set_xlabel('Side A roll-over disadvantage')
        ax.set_ylabel('Chance for side A to win (%)')
        ax.set_ylim(0, 100.0)
        ax.set_title('%d pool size for side A (KS = %0.2f%%)' %
                     (pool_size_a, ks * 100.0))
        ccdf_frame_path = 'output/frames/ccdf_%03d.png'
        plt.savefig(ccdf_frame_path % frame_index,
                    dpi=dpi,
                    bbox_inches="tight")
        plt.close()

    make_webm(pmf_frame_path,
              'output/success_pool_roe_opposed_%s_pmf.webm' % name)
    make_webm(ccdf_frame_path,
              'output/success_pool_roe_opposed_%s_ccdf.webm' % name)
Beispiel #9
0
from hdroller import Die

result = ''

base_bw_dice = 24
bw_scale = 2

for pbta_bonus in [-1, 0, 1, 2, 3]:
    num_bw_dice = int(bw_scale * pbta_bonus + base_bw_dice)
    bw_die = Die.coin(0.5).repeat_and_sum(num_bw_dice)
    pbta_high_chance = Die.d(2, 6) + pbta_bonus >= 11
    pbta_mid_chance = Die.d(2, 6) + pbta_bonus >= 7

    bw_target = base_bw_dice - (base_bw_dice // 2)
    bw_high_chance = bw_die >= bw_target + int(2 * bw_scale)
    bw_mid_chance = bw_die >= bw_target

    result += '\t'.join(
        str(x) for x in [
            pbta_bonus, num_bw_dice, pbta_mid_chance, bw_mid_chance,
            pbta_high_chance, bw_high_chance
        ])
    result += '\n'

with open('output/pbta_bw.csv', mode='w') as outfile:
    outfile.write(result)
Beispiel #10
0
import matplotlib as mpl
import matplotlib.pyplot as plt

figsize = (8, 4.5)
dpi = 120

def opposed_keep_highest(x, half_life=3):
    attack_ratio = numpy.power(0.5, x / half_life)
    ccdf = attack_ratio / (attack_ratio + 1.0)
    return Die.from_ccdf(ccdf, x[0])

left = -20
right = 20
x = numpy.arange(left * 2, right * 2+1)
okh = opposed_keep_highest(x)
laplace = Die.laplace(half_life=3)  - Die.coin(0.5)
opposed_simple = Die.d(10).explode(3) - Die.d(10).explode(3) - Die.coin(0.5)
exploding = Die.d(10).explode(3) + Die.d(1, 12)
opposed_exploding = exploding - exploding - Die.coin(0.5)

legend = [
    'Logistic, half-life = 3',
    'Opposed d10! + d12',
    'Laplace, half-life = 3',
    'Opposed d10!',
]

# ccdf

fig = plt.figure(figsize=figsize)
ax = plt.subplot(111)
Beispiel #11
0
plt.savefig('output/explode_non_opposed_actual.png', dpi = dpi, bbox_inches = "tight")

# big-small

fig = plt.figure(figsize=figsize)
ax = plt.subplot(111)

ax.set_xlabel('Target number')
ax.set_ylabel('Chance of hitting')
ax.grid(which = "both")
ax.set_title('Big-small')

legend = []

for die_size in die_sizes:
    die = Die.coin(0.5).explode(100) * die_size + Die.d(die_size)
    y = [die >= t for t in numpy.arange(1, 41)]
    ax.semilogy(numpy.arange(1, 41), y)
    legend.append('d{0,1}!*%d+d%d' % (die_size, die_size))

ax.set_xticks(numpy.arange(0,41,5))
ax.set_xlim(left=0, right=40)
ax.set_ylim(top=1, bottom=1e-2)
ax.legend(legend, loc = 'lower left')
plt.savefig('output/explode_non_opposed_big_small.png', dpi = dpi, bbox_inches = "tight")

# ratio

fig = plt.figure(figsize=figsize)
ax = plt.subplot(111)
Beispiel #12
0
def test_mix_mixed():
    die = Die.mix(Die.d4, Die.d6, mix_weights=Die.coin())
    assert die.pmf() == pytest.approx([5 / 24] * 4 + [2 / 24] * 2)