3D6+3

Code-Stücke können hier veröffentlicht werden.
Antworten
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Samstag 1. November 2008, 10:44

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
Benutzeravatar
pillmuncher
User
Beiträge: 1093
Registriert: Samstag 21. März 2009, 22:59
Wohnort: München

Montag 19. Juli 2010, 20:32

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.
In specifications, Murphy's Law supersedes Ohm's.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Montag 19. Juli 2010, 22:09

@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
Benutzeravatar
/me
User
Beiträge: 3188
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Dienstag 20. Juli 2010, 07:19

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.
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Sonntag 14. November 2010, 22:07

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. ;)
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Montag 15. November 2010, 10:42

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
Antworten