Seite 1 von 1

3D6+3

Verfasst: Samstag 1. November 2008, 10:44
von sma
Hatte vor einigen Tagen aus Langeweile das folgende gebaut:

Dies wirft einen n-seitigen Würfel.

Code: Alles auswählen

import random

def d(n, aces=False):
    r = random.randrange(n) + 1
    return r + d(n, aces) if aces and r == n else r
Ist der zweite Parameter `True`, wird bei der höchstmöglichen Augenzahl der Würfel nochmal geworfen. Der Würfelwurf kann "explodieren" - etwas, das man z.B. im Rollenspiel Savage Worlds braucht. Worauf es mir aber eigentlich ankommt ist, einen beliebigen Ausdruck `xdy+z` auswerten zu können:

Code: Alles auswählen

import re
_RE_DICE = re.compile(r"(\d+)?d(\d+)?|(\d+)|([-+])")

def roll(dice, aces=False):
    result = 0; sign = 1
    for m in _RE_DICE.finditer(dice):
        if m.lastindex == 2:
            count = int(m.group(1) or 1)
            sides = int(m.group(2) or 6)
            for i in range(count):
                result += d(sides, aces) * sign
        elif m.lastindex == 3:
            result += int(m.group(3)) * sign
        else:
            sign = +1 if m.group(4) == '+' else -1
    return result
Kann man das noch knapper/eleganter/verständlicher ausdrücken?

Stefan

Re: 3D6+3

Verfasst: Montag 19. Juli 2010, 20:32
von pillmuncher

Code: Alles auswählen

import re
import random
import operator


class Bunch(object):
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)


match = re.compile(
    flags = re.VERBOSE,
    pattern = r"""
        ( (?P<times> \d* )
          (?P<item> d | D )
          (?P<sides> \d* )
          ( (?P<op> \+ | \- )(?P<value> \d+ ) | $ )
          |
          (?P<error> .* )
        )
    """
).match


ops = {'+':operator.add, '-':operator.sub, None:lambda x,_:x}


def roll(dice):
    parsed = Bunch(**match(dice).groupdict())
    if parsed.error:
        raise ValueError('Invalid argument "%s"' % parsed.error)
    times = int(parsed.times or 1)
    sides = int(parsed.sides or 6)
    value = int(parsed.value or 0)
    op = ops[parsed.op]
    return max(
        0, op(sum(random.randint(1, sides) for each in xrange(times)), value)
    )

print roll('12d8-3')
print roll('12d8')
print roll('12d-3')
print roll('12d')
print roll('d19+100')
print roll('d19')
print roll('d')
Wie das mit den aces gehen könnte, weiß ich nicht auf die Schnelle.

Gruß,
Mick.

Re: 3D6+3

Verfasst: Montag 19. Juli 2010, 22:09
von sma
@pillmucher, du kannst beispielsweise kein "d6+d8", ich schon :)

Das Neuwürfeln könntest du implementieren, indem du meine "d"-Funktion statt "random.randint(1, sides)" benutzt.

Stefan

Re: 3D6+3

Verfasst: Dienstag 20. Juli 2010, 07:19
von /me
sma hat geschrieben:@pillmucher, du kannst beispielsweise kein "d6+d8", ich schon :)
Dann wäre jetzt noch Klammern spannend a la 2D6 * (2D10- D6).

Ich habe bei der Realisierung von so etwas mal einen Ansatz gewählt, der die Würfelwerte durch ihr ausgewürfeltes Ergebnis ersetzt hat und dann (evil) eval benutzt hat um das Ergebnis zu berechnen.

Re: 3D6+3

Verfasst: Sonntag 14. November 2010, 22:07
von Darii
sma hat geschrieben:Hatte vor einigen Tagen aus Langeweile das folgende gebaut:

Dies wirft einen n-seitigen Würfel.
Man merkt doch gleich wer Random>>roll: verbrochen hat. ;)

Re: 3D6+3

Verfasst: Montag 15. November 2010, 10:42
von sma
Darii hat geschrieben:Man merkt doch gleich wer Random>>roll: verbrochen hat. ;)
*g*

Leider fanden die Pharo-Leute die Funktion wohl zu unwichtig um sie auch in ihre Squeak-Distribution aufzunehmen :)

Stefan