コード例 #1
0
    def roll_one(self, dice, adv: int = 0):
        result = SingleDiceGroup()
        result.rolled = []
        # splits dice and comments
        split = re.match(r'^([^\[\]]*?)\s*(\[.*\])?\s*$', dice)
        dice = split.group(1).strip()
        annotation = split.group(2)
        result.annotation = annotation if annotation is not None else ''
        # Recognizes dice
        obj = re.findall('\d+', dice)
        obj = [int(x) for x in obj]
        numArgs = len(obj)

        ops = []
        if numArgs == 1:
            if not dice.startswith('d'):
                raise errors.InvalidArgument('Please pass in the value of the dice.')
            numDice = 1
            diceVal = obj[0]
            if adv is not 0 and diceVal == 20:
                numDice = 2
                ops = ['k', 'h1'] if adv is 1 else ['k', 'l1']
        elif numArgs == 2:
            numDice = obj[0]
            diceVal = obj[-1]
            if adv is not 0 and diceVal == 20:
                ops = ['k', 'h' + str(numDice)] if adv is 1 else ['k', 'l' + str(numDice)]
                numDice = numDice * 2
        else:  # split into xdy and operators
            numDice = obj[0]
            diceVal = obj[1]
            dice = re.split('(\d+d\d+)', dice)[-1]
            ops = VALID_OPERATORS_2.split(dice)
            ops = [a for a in ops if a is not None]

        # dice repair/modification
        if numDice > 300 or diceVal < 1:
            raise errors.InvalidArgument('Too many dice rolled.')

        result.max_value = diceVal
        result.num_dice = numDice
        result.operators = ops

        for _ in range(numDice):
            try:
                tempdice = SingleDice()
                tempdice.value = random.randint(1, diceVal)
                tempdice.rolls = [tempdice.value]
                tempdice.max_value = diceVal
                tempdice.kept = True
                result.rolled.append(tempdice)
            except:
                result.rolled.append(SingleDice())

        if ops is not None:

            rerollList = []
            reroll_once = []
            keep = None
            to_explode = []
            to_reroll_add = []

            valid_operators = VALID_OPERATORS_ARRAY
            last_operator = None
            for index, op in enumerate(ops):
                if last_operator is not None and op in valid_operators and not op == last_operator:
                    result.reroll(reroll_once, 1)
                    reroll_once = []
                    result.reroll(rerollList)
                    rerollList = []
                    result.keep(keep)
                    keep = None
                    result.reroll(to_reroll_add, 1, keep_rerolled=True, unique=True)
                    to_reroll_add = []
                    result.reroll(to_explode, greedy=True, keep_rerolled=True)
                    to_explode = []
                if op == 'rr':
                    rerollList += parse_selectors([list_get(index + 1, 0, ops)], result, greedy=True)
                if op == 'k':
                    keep = [] if keep is None else keep
                    keep += parse_selectors([list_get(index + 1, 0, ops)], result)
                if op == 'ro':
                    reroll_once += parse_selectors([list_get(index + 1, 0, ops)], result)
                if op == 'mi':
                    _min = list_get(index + 1, 0, ops)
                    for r in result.rolled:
                        if r.value < int(_min):
                            r.update(int(_min))
                if op == 'ma':
                    _max = list_get(index + 1, 0, ops)
                    for r in result.rolled:
                        if r.value > int(_max):
                            r.update(int(_max))
                if op == 'ra':
                    to_reroll_add += parse_selectors([list_get(index + 1, 0, ops)], result)
                if op == 'e':
                    to_explode += parse_selectors([list_get(index + 1, 0, ops)], result, greedy=True)
                if op in valid_operators:
                    last_operator = op
            result.reroll(reroll_once, 1)
            result.reroll(rerollList)
            result.keep(keep)
            result.reroll(to_reroll_add, 1, keep_rerolled=True, unique=True)
            result.reroll(to_explode, greedy=True, keep_rerolled=True)

        return result
コード例 #2
0
    def roll(self, rollStr, adv: int = 0, rollFor='', inline=False, double=False, show_blurbs=True, **kwargs):
        try:
            if '**' in rollStr:
                raise errors.InvalidArgument("Exponents are currently disabled.")
            self.parts = []
            # split roll string into XdYoptsSel [comment] or Op
            # set remainder to comment
            # parse each, returning a SingleDiceResult
            dice_set = re.split('([-+*/().=])', rollStr)
            dice_set = [d for d in dice_set if not d in (None, '')]
            log.debug("Found dice set: " + str(dice_set))
            for index, dice in enumerate(dice_set):
                match = DICE_PATTERN.match(dice)
                log.debug("Found dice group: " + str(match.groups()))
                # check if it's dice
                if match.group(1):
                    roll = self.roll_one(dice.replace(match.group(5), ''), adv)
                    self.parts.append(roll)
                # or a constant
                elif match.group(2):
                    self.parts.append(Constant(value=int(match.group(2)), annotation=match.group(4)))
                # or an operator
                elif not match.group(5):
                    self.parts.append(Operator(op=match.group(3), annotation=match.group(4)))

                if match.group(5):
                    self.parts.append(Comment(match.group(5) + ''.join(dice_set[index + 1:])))
                    break

            # calculate total
            crit = self.get_crit()
            try:
                total = self.get_total()
            except SyntaxError:
                raise errors.InvalidArgument("No dice found to roll.")
            rolled = ' '.join(str(res) for res in self.parts if not isinstance(res, Comment))
            if rollFor is '':
                rollFor = ''.join(str(c) for c in self.parts if isinstance(c, Comment))
            # return final solution
            if not inline:
                # Builds end result while showing rolls
                reply = ' '.join(
                    str(res) for res in self.parts if not isinstance(res, Comment)) + '\n**Total:** ' + str(
                    floor(total))
                skeletonReply = reply
                rollFor = rollFor if rollFor is not '' else 'Result'
                reply = '**{}:** '.format(rollFor) + reply
                if show_blurbs:
                    if adv == 1:
                        reply += '\n**Rolled with Advantage**'
                    elif adv == -1:
                        reply += '\n**Rolled with Disadvantage**'
                    if crit == 1:
                        critStr = "\n_**Critical Hit!**_  "
                        reply += critStr
                    elif crit == 2:
                        critStr = "\n_**Critical Fail!**_  "
                        reply += critStr
            else:
                # Builds end result while showing rolls
                reply = ' '.join(str(res) for res in self.parts if not isinstance(res, Comment)) + ' = `' + str(
                    floor(total)) + '`'
                skeletonReply = reply
                rollFor = rollFor if rollFor is not '' else 'Result'
                reply = '**{}:** '.format(rollFor) + reply
                if show_blurbs:
                    if adv == 1:
                        reply += '\n**Rolled with Advantage**'
                    elif adv == -1:
                        reply += '\n**Rolled with Disadvantage**'
                    if crit == 1:
                        critStr = "\n_**Critical Hit!**_  "
                        reply += critStr
                    elif crit == 2:
                        critStr = "\n_**Critical Fail!**_  "
                        reply += critStr
            reply = re.sub(' +', ' ', reply)
            skeletonReply = re.sub(' +', ' ', str(skeletonReply))
            return DiceResult(result=int(floor(total)), verbose_result=reply, crit=crit, rolled=rolled,
                              skeleton=skeletonReply, raw_dice=self)
        except Exception as ex:
            if not isinstance(ex, (SyntaxError, KeyError, errors.AvraeException)):
                log.error('Error in roll() caused by roll {}:'.format(rollStr))
                traceback.print_exc()
            return DiceResult(verbose_result="Invalid input: {}".format(ex))
コード例 #3
0
ファイル: dice.py プロジェクト: thomasmckay/avrae
    def roll_one(self, dice, adv: int = 0):
        # splits dice and annotation
        split = re.match(r'^([^\[\]]*?)\s*(\[.*\])?\s*$', dice)
        dice = split.group(1).strip()
        annotation = split.group(2)

        # Recognizes dice
        obj = re.findall('\d+', dice)
        obj = [int(x) for x in obj]
        numArgs = len(obj)

        # prepare dice and operators
        ops = []
        if numArgs == 1:
            if not dice.startswith('d'):
                raise errors.InvalidArgument(
                    'Please pass in the value of the dice.')
            numDice = 1
            dice_size = obj[0]
            if adv is not 0 and dice_size == 20:
                numDice = 2
                ops = ['k', 'h1'] if adv is 1 else ['k', 'l1']
        elif numArgs == 2:
            numDice = obj[0]
            dice_size = obj[-1]
            if adv is not 0 and dice_size == 20:
                ops = ['k', 'h' + str(numDice)
                       ] if adv is 1 else ['k', 'l' + str(numDice)]
                numDice = numDice * 2
        else:  # split into xdy and operators
            numDice = obj[0]
            dice_size = obj[1]
            dice = re.split('(\d+d\d+)', dice)[-1]
            ops = VALID_OPERATORS_2.split(dice)
            ops = [a for a in ops if a is not None]

        # ensure limits
        if numDice > 300 or dice_size < 1:
            raise errors.InvalidArgument('Too many dice rolled.')

        # prepare output
        result = SingleDiceGroup(num_dice=numDice,
                                 max_value=dice_size,
                                 annotation=annotation or '',
                                 operators=ops)

        # roll dice
        for _ in range(numDice):
            try:
                tempdice = SingleDice(value=random.randint(1, dice_size),
                                      max_value=dice_size)
                result.rolled.append(tempdice)
            except:  # ?
                result.rolled.append(SingleDice())

        # define operators
        def _op_rr(buf):
            self._rerolls += result.reroll(buf, greedy=True)

        def _op_k(buf):
            result.keep(buf)

        def _op_ro(buf):
            self._rerolls += result.reroll(buf, once=True)

        def _op_ra(buf):
            result.reroll(buf, once=True, keep_rerolled=True, unique=True)

        def _op_e(buf):
            self._rerolls += result.reroll(buf,
                                           greedy=True,
                                           keep_rerolled=True)

        # run operators
        if ops is not None:
            buffer = list()
            operation = None
            last_operator = None

            for index, op in enumerate(ops):
                if self._rerolls > MAX_REROLLS:
                    raise OverflowError("Tried to reroll too many dice.")

                if operation is not None and op in VALID_OPERATORS_ARRAY and not op == last_operator:
                    operation(buffer)
                    buffer = list()
                    operation = None

                if op == 'rr':
                    buffer += parse_selectors([list_get(index + 1, 0, ops)],
                                              result,
                                              greedy=True)
                    operation = _op_rr
                elif op == 'k':
                    buffer += parse_selectors([list_get(index + 1, 0, ops)],
                                              result)
                    operation = _op_k
                elif op == 'p':
                    buffer += parse_selectors([list_get(index + 1, 0, ops)],
                                              result,
                                              inverse=True)
                    operation = _op_k
                elif op == 'ro':
                    buffer += parse_selectors([list_get(index + 1, 0, ops)],
                                              result)
                    operation = _op_ro
                elif op == 'mi':
                    _min = list_get(index + 1, 0, ops)
                    for r in result.rolled:
                        if r.value < int(_min):
                            r.update(int(_min))
                elif op == 'ma':
                    _max = list_get(index + 1, 0, ops)
                    for r in result.rolled:
                        if r.value > int(_max):
                            r.update(int(_max))
                elif op == 'ra':
                    buffer += parse_selectors([list_get(index + 1, 0, ops)],
                                              result)
                    operation = _op_ra
                elif op == 'e':
                    buffer += parse_selectors([list_get(index + 1, 0, ops)],
                                              result,
                                              greedy=True)
                    operation = _op_e

                if op in VALID_OPERATORS_ARRAY:
                    last_operator = op

            if self._rerolls > MAX_REROLLS:
                raise OverflowError("Tried to reroll too many dice.")
            if operation is not None:
                operation(buffer)

        return result