from typing import Dict
from dicetables.dieevents import ProtoDie
from dicetables.dicepool import DicePool
[docs]class DicePoolCollection(ProtoDie):
"""
The abstract class for all DicePoolCollection objects. A DicePoolCollection creates a new die by selecting from a
DicePool. Select determines how many rolls are selected from the pool of total rolls.
Different implementations determine which particular rolls to select.
"""
def __init__(self, pool: DicePool, select: int):
"""
:param pool: the dice pool to select from
:param select: int <= `pool.size`. How many dice to select from the pool.
"""
self._dice_pool = pool
if select > self._dice_pool.size:
raise ValueError('you cannot select more dice than the pool_size.')
self._select = select
self._dict = self._generate_dict()
super(DicePoolCollection, self).__init__()
def _generate_dict(self):
raise NotImplementedError
[docs] def get_pool(self) -> DicePool:
return self._dice_pool
[docs] def get_select(self) -> int:
return self._select
def get_dict(self) -> Dict[int, int]:
return self._dict.copy()
def get_size(self) -> int:
return self._dice_pool.die.get_size() * self._select
def get_weight(self) -> int:
return self._dice_pool.die.get_weight() * self._select
def weight_info(self):
input_die = self._dice_pool.die
original_weight_info = input_die.weight_info().replace(str(input_die), 'input_die info:')
return '{}\n{}'.format(self, original_weight_info)
def multiply_str(self, number):
return '{}({})'.format(number, self)
def __str__(self):
descriptor = self.__class__.__name__.replace('OfDicePool', '')
return '{} {} of {}'.format(descriptor, self._select, self._dice_pool.die.multiply_str(self._dice_pool.size))
def __repr__(self):
return '{}({!r}, {})'.format(
self.__class__.__name__, self._dice_pool, self._select
)
[docs]class BestOfDicePool(DicePoolCollection):
"""
Take the best [select] rolls from a DicePool of [pool_size] * [input_die].
BestOfDicePool(DicePool(Die(6), 4), 3) is the best 3 rolls from four six-sided dice.
"""
def __init__(self, pool: DicePool, select: int):
super().__init__(pool, select)
def _generate_dict(self):
ordered_combinations = self._dice_pool.rolls
start_at = self._dice_pool.size - self._select
stop_before = self._dice_pool.size
return generate_events_dict(ordered_combinations, start_at, stop_before)
[docs]class WorstOfDicePool(DicePoolCollection):
"""
Take the worst [select] rolls from a DicePool of [pool_size] * [input_die].
WorstOfDicePool(DicePool(Die(6), 4), 3) is the worst 3 rolls from four six-sided dice.
"""
def __init__(self, pool: DicePool, select: int):
super().__init__(pool, select)
def _generate_dict(self):
ordered_combinations = self._dice_pool.rolls
start_at = 0
stop_before = self._select
return generate_events_dict(ordered_combinations, start_at, stop_before)
[docs]class UpperMidOfDicePool(DicePoolCollection):
"""
Take the middle [select] rolls from a DicePool of [pool_size] * [input_die].
UpperMidOfDicePool(DicePool(Die(6), 5), 3) is the middle 3 rolls from five six-sided dice.
If there is no perfect middle, take the higher of two choices. For five dice that roll
(1, 1, 2, 3, 4), select=3 takes (1, 2, 3) and select=2 takes (2, 3).
"""
def __init__(self, pool: DicePool, select: int):
super().__init__(pool, select)
def _generate_dict(self):
ordered_combinations = self._dice_pool.rolls
end_slice, extra = divmod(self._dice_pool.size - self._select, 2)
start_at = end_slice + extra
stop_before = self._dice_pool.size - end_slice
return generate_events_dict(ordered_combinations, start_at, stop_before)
[docs]class LowerMidOfDicePool(DicePoolCollection):
"""
Take the middle [select] rolls from a DicePool of [pool_size] * [input_die].
LowerMidOfDicePool(DicePool(Die(6), 5), 3) is the middle 3 rolls from five six-sided dice.
If there is no perfect middle, take the lower of two choices. For five dice that roll
(1, 1, 2, 3, 4), select=3 takes (1, 2, 3) and select=2 takes (1, 2).
"""
def __init__(self, pool: DicePool, select: int):
super().__init__(pool, select)
def _generate_dict(self):
ordered_combinations = self._dice_pool.rolls
end_slice, extra = divmod(self._dice_pool.size - self._select, 2)
start_at = end_slice
stop_before = self._dice_pool.size - (end_slice + extra)
return generate_events_dict(ordered_combinations, start_at, stop_before)
def generate_events_dict(ordered_combinations, start_at, stop_before) -> Dict[int, int]:
master_dict = {}
for key, val in ordered_combinations.items():
master_key = sum(key[start_at:stop_before])
master_dict[master_key] = master_dict.get(master_key, 0) + val
return master_dict