Exemple #1
0
 def test_op_add_num(self) -> None:
     p_d6 = P(6)
     p_d6_plus = P(H(range(2, 8)))
     p_d8 = P(8)
     p_d8_plus = P(H(range(2, 10)))
     assert 1 + p_d6 == p_d6_plus
     assert p_d8_plus == p_d8 + 1
Exemple #2
0
 def test_op_sub_num(self) -> None:
     p_d6 = P(6)
     p_minus_d6 = P(H(range(0, -6, -1)))
     p_d8 = P(8)
     p_d8_minus = P(H(range(0, 8)))
     assert 1 - p_d6 == p_minus_d6
     assert p_d8_minus == p_d8 - 1
Exemple #3
0
def do_it(_: str) -> None:
    import matplotlib.pyplot

    p_4d6 = 4 @ P(6)
    res1 = p_4d6.h(slice(1, None))
    d6_reroll_first_one = H(6).substitute(lambda h, outcome: H(6)
                                          if outcome == 1 else outcome)
    p_4d6_reroll_first_one = 4 @ P(d6_reroll_first_one)
    res2 = p_4d6_reroll_first_one.h(slice(1, None))
    p_4d6_reroll_all_ones = 4 @ P(H(range(2, 7)))
    res3 = p_4d6_reroll_all_ones.h(slice(1, None))

    matplotlib.pyplot.plot(
        *res1.distribution_xy(),
        marker=".",
        label="Discard lowest",
    )
    matplotlib.pyplot.plot(
        *res2.distribution_xy(),
        marker=".",
        label="Re-roll first 1; discard lowest",
    )
    matplotlib.pyplot.plot(
        *res3.distribution_xy(),
        marker=".",
        label="Re-roll all 1s; discard lowest",
    )
    matplotlib.pyplot.legend()
    # Should match the corresponding img[alt] text
    matplotlib.pyplot.title(r"Comparing various take-three-of-4d6 methods")
Exemple #4
0
 def test_getitem_slice(self) -> None:
     d4n = H(-4)
     d8 = H(8)
     p_3d4n_3d8 = 3 @ P(d4n, d8)
     assert p_3d4n_3d8[:] == p_3d4n_3d8
     assert p_3d4n_3d8[:0] == P()
     assert p_3d4n_3d8[6:] == P()
     assert p_3d4n_3d8[2:4] == P(d4n, d8)
Exemple #5
0
 def test_init_multiple_histograms(self) -> None:
     d6 = H(6)
     p_d6 = P(6)
     p_2d6 = P(d6, d6)
     assert p_2d6.h() == H(sum(v) for v in itertools.product(d6, d6))
     assert P(p_d6, p_d6) == p_2d6
     assert P(p_d6, d6) == p_2d6
     assert P(d6, p_d6) == p_2d6
Exemple #6
0
    def test_op_sub_h(self) -> None:
        d2 = H(2)
        d3 = H(3)
        assert d2 - d3 == {-2: 1, -1: 2, 0: 2, 1: 1}
        assert d3 - d2 == {-1: 1, 0: 2, 1: 2, 2: 1}

        assert d2 - H({}) == d2
        assert H({}) - d3 == -d3
Exemple #7
0
 def test_op_unary(self) -> None:
     p = P(H(-v if v % 2 else v for v in range(10, 20)))
     assert isinstance(+p, type(p))
     assert (+p) == P(H((10, -11, 12, -13, 14, -15, 16, -17, 18, -19)))
     assert isinstance(-p, type(p))
     assert (-p) == P(H((-10, 11, -12, 13, -14, 15, -16, 17, -18, 19)))
     assert isinstance(abs(p), type(p))
     assert abs(p) == P(H((10, 11, 12, 13, 14, 15, 16, 17, 18, 19)))
Exemple #8
0
 def test_h_flatten(self) -> None:
     r_d6 = range(1, 7)
     r_d8 = range(1, 9)
     d6_d8 = H(sum(v) for v in itertools.product(r_d6, r_d8) if v)
     p_d6 = P(6)
     p_d8 = P(8)
     p_d6_d8 = P(p_d6, p_d8)
     assert p_d6_d8.h() == d6_d8
     assert P().h() == H({})
Exemple #9
0
 def test_len_and_counts(self) -> None:
     d0 = H({})
     d6_d8 = H(6) + H(8)
     assert len(d0) == 0
     assert sum(d0.counts()) == 0
     assert len(d6_d8) == 13  # num distinct values
     assert sum(d6_d8.counts()) == 48  # combinations
     assert len((d6_d8 + d6_d8)) == 25
     assert sum((d6_d8 + d6_d8).counts()) == 2304
Exemple #10
0
    def test_op_add_h(self) -> None:
        d2 = H(2)
        d3 = H(3)
        assert d2 + d3 == {2: 1, 3: 2, 4: 2, 5: 1}
        assert d3 + d2 == {2: 1, 3: 2, 4: 2, 5: 1}
        assert d2 + d3 == d3 + d2

        assert d2 + H({}) == d2
        assert H({}) + d3 == d3
Exemple #11
0
    def test_map(self) -> None:
        d6 = H(6)
        d8 = H(8)
        within_filter = _within(-1, 1)
        d8_v_d6 = d8.map(within_filter, d6)
        assert d8_v_d6 == {-1: 10, 0: 17, 1: 21}

        within_filter = _within(7, 9)
        d6_2_v_7_9 = (2 @ d6).map(within_filter, 0)
        assert d6_2_v_7_9 == {-1: 15, 0: 15, 1: 6}
Exemple #12
0
 def test_op_matmul(self) -> None:
     d6 = H(6)
     d6_2 = d6 + d6
     d6_3 = d6_2 + d6
     assert 0 @ d6 == H({})
     assert H({}) == d6 @ 0
     assert 2 @ d6 == d6_2
     assert d6_2 == d6 @ 2
     assert d6_3 == 3 @ d6
     assert 4 @ d6 == d6 @ 2 @ 2
Exemple #13
0
    def test_getitem_int(self) -> None:
        d4n = H(-4)
        d8 = H(8)
        p_3d4n_3d8 = 3 @ P(d4n, d8)
        assert p_3d4n_3d8[0] == d4n
        assert p_3d4n_3d8[2] == d4n
        assert p_3d4n_3d8[-3] == d8
        assert p_3d4n_3d8[-1] == d8

        with pytest.raises(IndexError):
            _ = p_3d4n_3d8[6]
Exemple #14
0
 def test_format(self) -> None:
     assert H((1, 2, 3, 1, 2, 1)).format(width=115) == os.linesep.join((
         "avg |    1.67",
         "std |    0.75",
         "var |    0.56",
         "  1 |  50.00% |##################################################",
         "  2 |  33.33% |#################################",
         "  3 |  16.67% |################",
     ))
     assert (H((1, 2, 3, 1, 2, 1)).format(
         width=0) == "{avg: 1.67, 1: 50.00%, 2: 33.33%, 3: 16.67%}")
Exemple #15
0
def do_it(_: str) -> None:
    import matplotlib.pyplot

    save_roll = H(20)
    burning_arch_damage = 10 @ H(6) + 10
    pass_save = save_roll.ge(10)
    damage_half_on_save = burning_arch_damage // (pass_save + 1)

    outcomes, probabilities = damage_half_on_save.distribution_xy()
    matplotlib.pyplot.plot(outcomes, probabilities, marker=".")
    # Should match the corresponding img[alt] text
    matplotlib.pyplot.title(
        r"Expected outcomes for attack with saving throw for half damage")
Exemple #16
0
 def test_op_truediv_h(self) -> None:
     d2 = H(2)
     d3n = H(-3)
     p_d2 = P(d2)
     p_d3n = P(d3n)
     d2_truediv_d3n = d2 / d3n
     d3n_truediv_d2 = d3n / d2
     assert p_d2 / p_d3n == d2_truediv_d3n
     assert p_d2 / d3n == d2_truediv_d3n
     assert d2 / p_d3n == d2_truediv_d3n
     assert p_d3n / p_d2 == d3n_truediv_d2
     assert p_d3n / d2 == d3n_truediv_d2
     assert d3n / p_d2 == d3n_truediv_d2
     assert p_d2 / p_d3n != p_d3n / p_d2
Exemple #17
0
def do_it(_: str) -> None:
    import matplotlib.pyplot

    p_2d6 = 2 @ P(H(6))
    outcomes, probabilities = p_2d6.h(0).distribution_xy()
    matplotlib.pyplot.bar(
        [v - 0.125 for v in outcomes],
        probabilities,
        alpha=0.75,
        width=0.5,
        label="Lowest",
    )

    outcomes, probabilities = p_2d6.h(-1).distribution_xy()
    matplotlib.pyplot.bar(
        [v + 0.125 for v in outcomes],
        probabilities,
        alpha=0.75,
        width=0.5,
        label="Highest",
    )

    matplotlib.pyplot.legend()
    # Should match the corresponding img[alt] text
    matplotlib.pyplot.title(r"Taking the lowest or highest die of 2d6")
Exemple #18
0
 def test_display_burst_outer(self):
     _, ax = dyce_plt.matplotlib.pyplot.subplots()
     d6_2 = 2 @ H(6)
     dyce_plt.display_burst(ax, d6_2, dyce_plt.labels_cumulative(d6_2))
     wedge_labels = [
         w.get_label() for w in ax.get_children()[:22]
         if isinstance(w, matplotlib.patches.Wedge)
     ]
     assert len(wedge_labels) == 22
     assert wedge_labels == [
         "2 2.78%; ≥2.78%; ≤100.00%",
         "3 5.56%; ≥8.33%; ≤97.22%",
         "4 8.33%; ≥16.67%; ≤91.67%",
         "5 11.11%; ≥27.78%; ≤83.33%",
         "6 13.89%; ≥41.67%; ≤72.22%",
         "7 16.67%; ≥58.33%; ≤58.33%",
         "8 13.89%; ≥72.22%; ≤41.67%",
         "9 11.11%; ≥83.33%; ≤27.78%",
         "10 8.33%; ≥91.67%; ≤16.67%",
         "11 5.56%; ≥97.22%; ≤8.33%",
         "12 2.78%; ≥100.00%; ≤2.78%",
         "2",
         "3",
         "4",
         "5",
         "6",
         "7",
         "8",
         "9",
         "10",
         "11",
         "12",
     ]
Exemple #19
0
 def test_display_burst(self):
     _, ax = dyce_plt.matplotlib.pyplot.subplots()
     d6_2 = 2 @ H(6)
     dyce_plt.display_burst(ax, d6_2)
     wedge_labels = [
         w.get_label() for w in ax.get_children()[:22]
         if isinstance(w, matplotlib.patches.Wedge)
     ]
     assert len(wedge_labels) == 22
     assert wedge_labels == [
         "2.78%",
         "5.56%",
         "8.33%",
         "11.11%",
         "13.89%",
         "16.67%",
         "13.89%",
         "11.11%",
         "8.33%",
         "5.56%",
         "2.78%",
         "2",
         "3",
         "4",
         "5",
         "6",
         "7",
         "8",
         "9",
         "10",
         "11",
         "12",
     ]
Exemple #20
0
    def test_rolls_with_counts_take_homogeneous_dice_vs_known_correct(
            self) -> None:
        p_df = P(H((-1, 0, 1)))
        p_4df = 4 @ p_df

        for which in (
                # All outcomes
                slice(None),
                slice(0, 4),
        ):
            karonen, multinomial_coefficient = _rwc_validation_helper(
                p_4df, which)
            karonen.assert_not_called()
            multinomial_coefficient.assert_called()

        for which in (
                # 1 Outcome
                slice(0, 1),
                slice(1, 2),
                slice(2, 3),
                slice(3, 4),
        ):
            karonen, multinomial_coefficient = _rwc_validation_helper(
                p_4df, which)
            karonen.assert_called()
            multinomial_coefficient.assert_not_called()

        for which in (
                # No outcomes
                slice(0, 0), ):
            karonen, multinomial_coefficient = _rwc_validation_helper(
                p_4df, which)
            karonen.assert_not_called()
            multinomial_coefficient.assert_not_called()
Exemple #21
0
    def test_h_take_homogeneous_dice_vs_known_correct(self) -> None:
        # Use the brute-force mechanism to validate our harder-to-understand
        # implementation
        p_df = P(H((-1, 0, 1)))
        p_4df = 4 @ p_df

        for which in (
                slice(0, 0),
                slice(2, 3),
                slice(1, 2),
                slice(0, 1),
        ):
            assert p_4df.h(which) == H(
                (sum(roll), count)
                for roll, count in _brute_force_combinations_with_counts(
                    tuple(p_4df), which))
Exemple #22
0
 def test_op_truediv_num(self) -> None:
     p_d10 = P(10)
     p1 = P(H(range(100, 0, -10)))
     assert p_d10 == p1 / 10
     assert (2 * 2 * 2 * 3 * 3 * 5 * 7) / p_d10 == H({
         252.0: 1,
         280.0: 1,
         315.0: 1,
         360.0: 1,
         420.0: 1,
         504.0: 1,
         630.0: 1,
         840.0: 1,
         1260.0: 1,
         2520.0: 1,
     })
def do_it(style: str) -> None:
    import matplotlib.pyplot

    single_attack = 2 @ H(6) + 5

    def gwf(h: H, outcome):
        return h if outcome in (1, 2) else outcome

    great_weapon_fighting = 2 @ (H(6).substitute(gwf)) + 5

    fig = matplotlib.pyplot.figure()
    fig.set_size_inches(10, 10, forward=True)
    plot_ax = matplotlib.pyplot.subplot2grid((2, 2), (0, 0), colspan=2)
    sa_burst_ax = matplotlib.pyplot.subplot2grid((2, 2), (1, 0), colspan=1)
    gwf_burst_ax = matplotlib.pyplot.subplot2grid((2, 2), (1, 1), colspan=1)
    sa_label = "Normal attack"
    plot_ax.plot(
        *single_attack.distribution_xy(),
        color="lightgreen" if style == "dark" else "tab:green",
        label=sa_label,
        marker=".",
    )
    gwf_label = "“Great Weapon Fighting”"
    plot_ax.plot(
        *great_weapon_fighting.distribution_xy(),
        color="lightblue" if style == "dark" else "tab:blue",
        label=gwf_label,
        marker=".",
    )
    plot_ax.legend()
    # Should match the corresponding img[alt] text
    plot_ax.set_title(r"Comparing a normal attack to an enhanced one")
    display_burst(
        sa_burst_ax,
        single_attack,
        desc=sa_label,
        graph_color="RdYlGn_r",
        text_color="white" if style == "dark" else "black",
    )
    display_burst(
        gwf_burst_ax,
        great_weapon_fighting,
        desc=gwf_label,
        graph_color="RdYlBu_r",
        text_color="white" if style == "dark" else "black",
    )
Exemple #24
0
 def test_variance(self) -> None:
     h = H((i, i) for i in range(10))
     assert math.isclose(
         h.variance(),
         statistics.pvariance(
             itertools.chain(*(itertools.repeat(outcome, count)
                               for outcome, count in h.items()))),
     )
Exemple #25
0
    def test_op_sub_h(self) -> None:
        d2 = H(2)
        d3n = H(-3)
        p_d2 = P(d2)
        p_d3n = P(d3n)
        d2_sub_d3n = d2 - d3n
        d3n_sub_d2 = d3n - d2
        assert p_d2 - p_d3n == d2_sub_d3n
        assert p_d2 - d3n == d2_sub_d3n
        assert d2 - p_d3n == d2_sub_d3n
        assert p_d3n - p_d2 == d3n_sub_d2
        assert p_d3n - d2 == d3n_sub_d2
        assert d3n - p_d2 == d3n_sub_d2
        assert p_d2 - p_d3n != p_d3n - p_d2

        assert p_d2 - P() == p_d2
        assert P() - p_d2 == -p_d2
        assert P() - P() == P()
Exemple #26
0
    def test_op_floordiv_h(self) -> None:
        d2 = H(2)
        d3n = H(-3)
        p_d2 = P(d2)
        p_d3n = P(d3n)
        d2_floordiv_d3n = d2 // d3n
        d3n_floordiv_d2 = d3n // d2
        assert p_d2 // p_d3n == d2_floordiv_d3n
        assert p_d2 // d3n == d2_floordiv_d3n
        assert d2 // p_d3n == d2_floordiv_d3n
        assert p_d3n // p_d2 == d3n_floordiv_d2
        assert p_d3n // d2 == d3n_floordiv_d2
        assert d3n // p_d2 == d3n_floordiv_d2
        assert p_d2 // p_d3n != p_d3n // p_d2

        assert p_d2 // P() == P()
        assert P() // p_d2 == P()
        assert P() // P() == P()
Exemple #27
0
    def test_op_mod_h(self) -> None:
        d2 = H(2)
        d3n = H(-3)
        p_d2 = P(d2)
        p_d3n = P(d3n)
        d2_mod_d3n = d2 % d3n
        d3n_mod_d2 = d3n % d2
        assert p_d2 % p_d3n == d2_mod_d3n
        assert p_d2 % d3n == d2_mod_d3n
        assert d2 % p_d3n == d2_mod_d3n
        assert p_d3n % p_d2 == d3n_mod_d2
        assert p_d3n % d2 == d3n_mod_d2
        assert d3n % p_d2 == d3n_mod_d2
        assert p_d2 % p_d3n != p_d3n % p_d2

        assert p_d2 % P() == P()
        assert P() % p_d2 == P()
        assert P() % P() == P()
Exemple #28
0
    def test_op_pow_h(self) -> None:
        d2 = H(2)
        d3 = H(3)
        p_d2 = P(d2)
        p_d3 = P(d3)
        d2_pow_d3 = d2**d3
        d3_pow_d2 = d3**d2
        assert p_d2**p_d3 == d2_pow_d3
        assert p_d2**d3 == d2_pow_d3
        assert d2**p_d3 == d2_pow_d3
        assert p_d3**p_d2 == d3_pow_d2
        assert p_d3**d2 == d3_pow_d2
        assert d3**p_d2 == d3_pow_d2
        assert p_d2**p_d3 != p_d3**p_d2

        assert p_d2**P() == P()
        assert P()**p_d2 == P()
        assert P()**P() == P()
Exemple #29
0
def do_it(_: str) -> None:
    import matplotlib.pyplot

    res = (10 @ P(H(10).explode(max_depth=3))).h(slice(-3, None))

    matplotlib.pyplot.plot(*res.distribution_xy(), marker=".")
    # Should match the corresponding img[alt] text
    matplotlib.pyplot.title(
        r"Modeling taking the three highest of ten exploding d10s")
Exemple #30
0
    def test_substitute_never_expand(self) -> None:
        def never_expand(
            d: H,  # pylint: disable=unused-argument
            outcome: float,
        ) -> Union[float, H]:
            return outcome

        d20 = H(20)
        assert d20.substitute(never_expand) == d20
        assert d20.substitute(never_expand, operator.add, 20) == d20