Biểu thức súc sắc phức tạp


23

Lý lịch

Tôi chơi D & D thường xuyên với một số người bạn. Trong khi nói về sự phức tạp của một số hệ thống / phiên bản khi nói đến việc gieo xúc xắc và áp dụng các phần thưởng và hình phạt, chúng tôi đã đùa rằng đã đưa ra một số phức tạp bổ sung cho các biểu thức lăn xúc xắc. Một số trong số chúng quá thái quá (như mở rộng các biểu thức xúc xắc đơn giản như 2d6đối số ma trận 1 ), nhưng phần còn lại tạo nên một hệ thống thú vị.

Các thách thức

Đưa ra một biểu thức xúc xắc phức tạp, đánh giá nó theo các quy tắc sau và đưa ra kết quả.

Quy tắc đánh giá cơ bản

  • Bất cứ khi nào một toán tử mong đợi một số nguyên nhưng nhận được một danh sách cho toán hạng, tổng của danh sách đó được sử dụng
  • Bất cứ khi nào một toán tử mong đợi một danh sách nhưng nhận được một số nguyên cho toán hạng, số nguyên được coi là một danh sách một phần tử có chứa số nguyên đó

Người vận hành

Tất cả các toán tử là toán tử infix nhị phân. Với mục đích giải thích, asẽ là toán hạng bên trái và bsẽ là toán hạng bên phải. Ký hiệu danh sách sẽ được sử dụng cho các ví dụ trong đó các toán tử có thể lấy danh sách làm toán hạng, nhưng các biểu thức thực tế chỉ bao gồm các số nguyên và toán tử dương.

  • d: đầu ra asố nguyên ngẫu nhiên thống nhất độc lập trong phạm vi[1, b]
    • Ưu tiên: 3
    • Cả hai toán hạng đều là số nguyên
    • Ví dụ: 3d4 => [1, 4, 3],[1, 2]d6 => [3, 2, 6]
  • t: lấy các bgiá trị thấp nhất từa
    • Ưu tiên: 2
    • alà một danh sách, blà một số nguyên
    • Nếu b > len(a), tất cả các giá trị được trả về
    • Ví dụ: [1, 5, 7]t1 => [1], [5, 18, 3, 9]t2 => [3, 5],3t5 => [3]
  • T: lấy các bgiá trị cao nhất từa
    • Ưu tiên: 2
    • alà một danh sách, blà một số nguyên
    • Nếu b > len(a), tất cả các giá trị được trả về
    • Ví dụ: [1, 5, 7]T1 => [7], [5, 18, 3, 9]T2 => [18, 9],3T5 => [3]
  • r: nếu có bất kỳ phần tử bnào trong a, hãy chạy lại các phần tử đó, sử dụng bất kỳ dcâu lệnh nào đã tạo ra chúng
    • Ưu tiên: 2
    • Cả hai toán hạng đều là danh sách
    • Việc ghi lại chỉ được thực hiện một lần, do đó có thể vẫn có các yếu tố btrong kết quả
    • Ví dụ: 3d6r1 => [1, 3, 4] => [6, 3, 4], 2d4r2 => [2, 2] => [3, 2],3d8r[1,8] => [1, 8, 4] => [2, 2, 4]
  • R: nếu có bất kỳ phần tử nào ở btrong a, hãy lặp lại các phần tử đó cho đến khi không có phần tử bnào xuất hiện, sử dụng bất kỳ dcâu lệnh nào tạo ra chúng
    • Ưu tiên: 2
    • Cả hai toán hạng đều là danh sách
    • Ví dụ: 3d6R1 => [1, 3, 4] => [6, 3, 4], 2d4R2 => [2, 2] => [3, 2] => [3, 1],3d8R[1,8] => [1, 8, 4] => [2, 2, 4]
  • +: thêm abcùng nhau
    • Ưu tiên: 1
    • Cả hai toán hạng đều là số nguyên
    • Ví dụ: 2+2 => 4, [2]+[2] => 4,[3, 1]+2 => 6
  • -: Trừ btừa
    • Ưu tiên: 1
    • Cả hai toán hạng đều là số nguyên
    • b sẽ luôn luôn ít hơn a
    • Ví dụ: 2-1 => 1, 5-[2] => 3,[8, 3]-1 => 10
  • .: nối abcùng nhau
    • Ưu tiên: 1
    • Cả hai toán hạng đều là danh sách
    • Ví dụ: 2.2 => [2, 2], [1].[2] => [1, 2],3.[4] => [3, 4]
  • _: đầu ra avới tất cả các yếu tố bbị loại bỏ
    • Ưu tiên: 1
    • Cả hai toán hạng đều là danh sách
    • Ví dụ: [3, 4]_[3] => [4], [2, 3, 3]_3 => [2],1_2 => [1]

Quy tắc bổ sung

  • Nếu giá trị cuối cùng của biểu thức là một danh sách, nó được tính tổng trước khi xuất
  • Việc đánh giá các thuật ngữ sẽ chỉ dẫn đến các số nguyên dương hoặc danh sách các số nguyên dương - bất kỳ biểu thức nào dẫn đến một số nguyên không dương hoặc một danh sách chứa ít nhất một số nguyên không dương sẽ có các giá trị đó được thay thế bằng 1s
  • Dấu ngoặc đơn có thể được sử dụng để nhóm các thuật ngữ và chỉ định thứ tự đánh giá
  • Các toán tử được đánh giá theo thứ tự ưu tiên cao nhất đến ưu tiên thấp nhất, với việc tiến hành đánh giá từ trái sang phải trong trường hợp ưu tiên ràng buộc (vì vậy 1d4d4sẽ được đánh giá là (1d4)d4)
  • Thứ tự của các phần tử trong danh sách không thành vấn đề - hoàn toàn chấp nhận được đối với toán tử sửa đổi danh sách để trả về nó với các phần tử theo thứ tự tương đối khác
  • Các thuật ngữ không thể được đánh giá hoặc sẽ dẫn đến một vòng lặp vô hạn (như 1d1R1hoặc 3d6R[1, 2, 3, 4, 5, 6]) không hợp lệ

Các trường hợp thử nghiệm

Định dạng: input => possible output

1d20 => 13
2d6 => 8
4d6T3 => 11
2d20t1 => 13
5d8r1 => 34
5d6R1 => 20
2d6d6 => 23
3d2R1d2 => 3
(3d2R1)d2 => 11
1d8+3 => 10
1d8-3 => 4
1d6-1d2 => 2
2d6.2d6 => 12
3d6_1 => 8
1d((8d20t4T2)d(6d6R1r6)-2d4+1d2).(1d(4d6_3d3)) => 61

Tất cả trừ trường hợp thử nghiệm cuối cùng được tạo ra với việc thực hiện tham chiếu.

Ví dụ làm việc

Biểu hiện: 1d((8d20t4T2)d(6d6R1r6)-2d4+1d2).(1d(4d6_3d3))

  1. 8d20t4T2 => [19, 5, 11, 6, 19, 15, 4, 20]t4T2 => [4, 5, 6, 11]T2 => [11, 6](đầy đủ 1d(([11, 6])d(6d6R1r6)-2d4+1d2).(1d(4d6_3d3)):)
  2. 6d6R1r6 => [2, 5, 1, 5, 2, 3]r1R6 => [2, 5, 3, 5, 2, 3]R6 => [2, 5, 3, 5, 2, 3]( 1d([11, 6]d[2, 5, 3, 5, 2, 3]-2d4+1d2).(1d(4d6_3d3)))
  3. [11, 6]d[2, 5, 3, 5, 2, 3] => 17d20 => [1, 6, 11, 7, 2, 8, 15, 3, 4, 18, 11, 11, 1, 10, 8, 6, 11]( 1d([1, 6, 11, 7, 2, 8, 15, 3, 4, 18, 11, 11, 1, 10, 8, 6, 11]-2d4+1d2).(1d(4d6_3d3)))
  4. 2d4 => 7( 1d([1, 6, 11, 7, 2, 8, 15, 3, 4, 18, 11, 11, 1, 10, 8, 6, 11]-7+1d2).(1d(4d6_3d3)))
  5. 1d2 => 2( 1d([1, 6, 11, 7, 2, 8, 15, 3, 4, 18, 11, 11, 1, 10, 8, 6, 11]-7+2).(1d(4d6_3d3)))
  6. [1, 6, 11, 7, 2, 8, 15, 3, 4, 18, 11, 11, 1, 10, 8, 6, 11]-7+2 => 133-7+2 => 128( 1d128).(1d(4d6_3d3)))
  7. 4d6_3d3 => [1, 3, 3, 6]_[3, 2, 2] => [1, 3, 3, 6, 3, 2, 2]( 1d128).(1d[1, 3, 3, 6, 3, 2, 2]))
  8. 1d[1, 3, 3, 6, 3, 2, 2] => 1d20 => 6( 1d128).(6))
  9. 1d128 => 55( 55.6)
  10. 55.6 => [55, 6]( [55, 6])
  11. [55, 6] => 61 (làm xong)

Thực hiện tham khảo

Việc triển khai tham chiếu này sử dụng cùng một hạt giống hằng ( 0) để đánh giá từng biểu thức cho các đầu ra nhất quán, có thể kiểm tra được. Nó mong đợi đầu vào trên STDIN, với các dòng mới phân tách từng biểu thức.

#!/usr/bin/env python3

import re
from random import randint, seed
from collections import Iterable
from functools import total_ordering

def as_list(x):
    if isinstance(x, Iterable):
        return list(x)
    else:
        return [x]

def roll(num_sides):
    return Die(randint(1, num_sides), num_sides)

def roll_many(num_dice, num_sides):
    num_dice = sum(as_list(num_dice))
    num_sides = sum(as_list(num_sides))
    return [roll(num_sides) for _ in range(num_dice)]

def reroll(dice, values):
    dice, values = as_list(dice), as_list(values)
    return [die.reroll() if die in values else die for die in dice]

def reroll_all(dice, values):
    dice, values = as_list(dice), as_list(values)
    while any(die in values for die in dice):
        dice = [die.reroll() if die in values else die for die in dice]
    return dice

def take_low(dice, num_values):
    dice = as_list(dice)
    num_values = sum(as_list(num_values))
    return sorted(dice)[:num_values]

def take_high(dice, num_values):
    dice = as_list(dice)
    num_values = sum(as_list(num_values))
    return sorted(dice, reverse=True)[:num_values]

def add(a, b):
    a = sum(as_list(a))
    b = sum(as_list(b))
    return a+b

def sub(a, b):
    a = sum(as_list(a))
    b = sum(as_list(b))
    return max(a-b, 1)

def concat(a, b):
    return as_list(a)+as_list(b)

def list_diff(a, b):
    return [x for x in as_list(a) if x not in as_list(b)]

@total_ordering
class Die:
    def __init__(self, value, sides):
        self.value = value
        self.sides = sides
    def reroll(self):
        self.value = roll(self.sides).value
        return self
    def __int__(self):
        return self.value
    __index__ = __int__
    def __lt__(self, other):
        return int(self) < int(other)
    def __eq__(self, other):
        return int(self) == int(other)
    def __add__(self, other):
        return int(self) + int(other)
    def __sub__(self, other):
        return int(self) - int(other)
    __radd__ = __add__
    __rsub__ = __sub__
    def __str__(self):
        return str(int(self))
    def __repr__(self):
        return "{} ({})".format(self.value, self.sides)

class Operator:
    def __init__(self, str, precedence, func):
        self.str = str
        self.precedence = precedence
        self.func = func
    def __call__(self, *args):
        return self.func(*args)
    def __str__(self):
        return self.str
    __repr__ = __str__

ops = {
    'd': Operator('d', 3, roll_many),
    'r': Operator('r', 2, reroll),
    'R': Operator('R', 2, reroll_all),
    't': Operator('t', 2, take_low),
    'T': Operator('T', 2, take_high),
    '+': Operator('+', 1, add),
    '-': Operator('-', 1, sub),
    '.': Operator('.', 1, concat),
    '_': Operator('_', 1, list_diff),
}

def evaluate_dice(expr):
    return max(sum(as_list(evaluate_rpn(shunting_yard(tokenize(expr))))), 1)

def evaluate_rpn(expr):
    stack = []
    while expr:
        tok = expr.pop()
        if isinstance(tok, Operator):
            a, b = stack.pop(), stack.pop()
            stack.append(tok(b, a))
        else:
            stack.append(tok)
    return stack[0]

def shunting_yard(tokens):
    outqueue = []
    opstack = []
    for tok in tokens:
        if isinstance(tok, int):
            outqueue = [tok] + outqueue
        elif tok == '(':
            opstack.append(tok)
        elif tok == ')':
            while opstack[-1] != '(':
                outqueue = [opstack.pop()] + outqueue
            opstack.pop()
        else:
            while opstack and opstack[-1] != '(' and opstack[-1].precedence > tok.precedence:
                outqueue = [opstack.pop()] + outqueue
            opstack.append(tok)
    while opstack:
        outqueue = [opstack.pop()] + outqueue
    return outqueue

def tokenize(expr):
    while expr:
        tok, expr = expr[0], expr[1:]
        if tok in "0123456789":
            while expr and expr[0] in "0123456789":
                tok, expr = tok + expr[0], expr[1:]
            tok = int(tok)
        else:
            tok = ops[tok] if tok in ops else tok
        yield tok

if __name__ == '__main__':
    import sys
    while True:
        try:
            dice_str = input()
            seed(0)
            print("{} => {}".format(dice_str, evaluate_dice(dice_str)))
        except EOFError:
            exit()

[1]: Định nghĩa của chúng tôi về các adbđối số ma trận là cuộn AdXcho từng Xtrong a * b, ở đâu A = det(a * b). Rõ ràng đó là quá vô lý cho thử thách này.



Với sự đảm bảo về -điều đó bsẽ luôn luôn ít hơn atôi thấy không có cách nào để có được số nguyên không tích cực, vì vậy quy tắc bổ sung thứ hai dường như vô nghĩa. OTOH, _có thể dẫn đến một danh sách trống, có vẻ hữu ích trong các trường hợp tương tự nhưng điều đó có nghĩa là gì khi cần một số nguyên? Thông thường tôi sẽ nói tổng là 0...
Christian Sievers

@ChristianSievers 1) Tôi đã thêm ghi chú bổ sung về số nguyên không tích cực cho rõ ràng. 2) Tổng của một danh sách trống là 0. Theo quy tắc không tích cực, nó sẽ được đánh giá là a 1.
Mego

Được rồi, nhưng nó có ổn như kết quả trung gian không? Vậy [1,2]_([1]_[1])[1,2]sao?
Christian Sievers

@ChristianSievers Không. Điều đó sẽ dẫn đến [2], bởi vì [1]_[1] -> [] -> 0 -> 1 -> [1].
Mego

Câu trả lời:


9

Python 3, 803 788 753 749 744 748 745 740 700 695 682 byte

exec(r'''from random import*
import re
class k(int):
 p=0;j=Xl([d(randint(1,int(b)),b)Zrange(a)]);__mul__=Xl(sorted(Y)[:b]);__matmul__=Xl(sorted(Y)[-b:]);__truediv__=Xl([d(randint(1,int(_.i)),_.i)if _==b else _ ZY]);__sub__=Xk(max(1,int.__sub__(a,b)))
 def __mod__(a,b):
  x=[]
  while x!=Y:x=Y;a=a/b
  Wl(x)
 def V:
  if b.p:p=b.p;del b.p;Wl(Y+b.l)if~-p else l([_ZY if~-(_ in b.l)])
  Wk(int.V)
 def __neg__(a):a.p+=1;Wa
def l(x):a=k(sum(x)or 1);Y=x;Wa
def d(v,i):d=k(v);d.i=i;Wd
lambda a:eval(re.sub("(\d+)","(k(\\1))",a).translate({100:".j",116:"*",84:"@",114:"/",82:"%",46:"+--",95:"+-"}))'''.translate({90:" for _ in ",89:"a.l",88:"lambda a,b:",87:"return ",86:"__add__(a,b)"}))

-5 byte nhờ Mr.Xcoder

-5 byte nữa nhờ NGN

-about 40 byte nhờ Jonathan Pháp

Yuck, thật là một bùn! Điều này hoạt động bằng cách sử dụng một biểu thức chính quy để bọc tất cả các số trong klớp của tôi và chuyển đổi tất cả các toán tử thành toán tử python hiểu, sau đó sử dụng các phương thức ma thuật của klớp để xử lý toán học. Các +-+--vào cuối cho ._là một hack để giữ được ưu tiên đúng. Tương tự như vậy, tôi không thể sử dụng **toán tử cho d vì làm như vậy sẽ 1d4d4được phân tích cú pháp như 1d(4d4). Thay vào đó, tôi bọc tất cả các số trong một tập hợp các parens bổ sung và thực hiện .j, vì các lệnh gọi phương thức có độ ưu tiên cao hơn các toán tử. Dòng cuối cùng đánh giá là một hàm ẩn danh để đánh giá biểu thức.


def __mod__(a, b)... Tại sao không gian giữa a,b?
Ông Xcoder


@ Mr.Xcoder Tôi nghĩ bạn có thể tiết kiệm một byte bằng cách xóa một khoảng trống không cần thiết : ; __sub__. Và cũng có thể ở đây : lambda a,b: l(.
Jonathan Frech

1
Bạn có thể lưu một số byte bằng cách gói toàn bộ mã của bạn trong một exec("""...""".replace("...","..."))câu lệnh và thay thế các chuỗi xảy ra thường xuyên (như return ) bằng một ký tự. Tuy nhiên, với tôi, chiến lược execluôn có vẻ hơi không hợp lý ...
Jonathan Frech

các cơ quan của __mod____add__không cần phải nhiều thụt lề
NGN

3

APL (Dyalog Classic) , 367 byte

d←{(⊢⍪⍨1+?)⍉⍪⊃⍴/⊃¨+/¨⍺⍵}⋄r←{z←⊣⌿⍺⋄((m×?n)+z×~m←z∊⊣⌿⍵)⍪n←⊢⌿⍺}⋄R←{⍬≡⊃∩/⊣⌿¨⍺⍵:⍺⋄⍵∇⍨⍺r⍵}
u←{⍺[;((⊃+/⍵)⌊≢⍉⍺)↑⍺⍺⊣⌿⍺]}⋄t←⍋u⋄T←⍒u⋄A←+/,⋄S←+/,∘-⋄C←,⋄D←{⍺/⍨~⊃∊/⊣⌿¨⍺⍵}
hv←⍬⋄o'drRtT+-._'f←{8<io⍳⊃⍵:0v⊢←(¯2v),(⍎i'drRtTASCD')/¯2v}
{⊃⍵∊⎕d:v,←⊂⍪2↑⍎⍵⋄'('=⍵:h,←⍵⋄')'=⍵:h↑⍨←i-1f¨⌽h↓⍨i←+/∨\⌽h='('⋄h,←⍵⊣h↓⍨←-i⊣f¨⌽h↑⍨-i←+/\⌽≤/(1 4 4 1/⌽⍳4)[o⍳↑⍵,¨h]}¨'\d+' '.'s'&'⊢⍞
f¨⌽h1⌈+/⊣⌿⊃v

Hãy thử trực tuyến!

Đây là thuật toán sân shunting từ việc thực hiện tham chiếu được hợp nhất với evaluate_dice(), mà không có sự vô nghĩa của hành trình và hướng đối tượng. Chỉ có hai ngăn xếp được sử dụng: hcho các toán tử và vcho các giá trị. Phân tích cú pháp và đánh giá được xen kẽ.

Kết quả trung gian được biểu diễn dưới dạng ma trận 2 × N trong đó hàng đầu tiên là giá trị ngẫu nhiên và hàng thứ hai là số cạnh trên con súc sắc đã tạo ra chúng. Khi một kết quả không được tạo bởi toán tử "d" ném xúc xắc, hàng thứ hai chứa các số tùy ý. Một giá trị ngẫu nhiên duy nhất là ma trận 2 × 1 và do đó không thể phân biệt được với danh sách 1 phần tử.


3

Python 3: 723 722 714 711 707 675 653 665 byte

import re
from random import*
S=re.subn
e=eval
r=randint
s=lambda a:sum(g(e(a)))or 1
g=lambda a:next(zip(*a))
def o(m):a,o,b=m.groups();A=sorted(e(a));t=g(e(b));return str(o in"rR"and([([v,(r(1,d)*(o>"R")or choice([n+1for n in range(d)if~-(n+1in t)]))][v in t],d)for(v,d)in A])or{"t":A[:s(b)],"T":A[-s(b):],"+":[(s(a)+s(b),0)],"-":[(s(a)-s(b),0)],".":e(a)+e(b),"_":[t for t in e(a)if~-(t[0]in g(e(b)))]}[o])
def d(m):a,b=map(s,m.groups());return str([(r(1,b),b)for _ in" "*a])
p=r"(\[[^]]+\])"
def E(D):
 D,n=S(r"(\d+)",r"[(\1,0)]",D)
 while n:
  n=0
  for e in[("\(("+p+")\)",r"\1"),(p+"d"+p,d),(p+"([tTrR])"+p,o),(p+"(.)"+p,o)]:
   if n<1:D,n=S(*e,D)
 return s(D)

Điểm vào là E. Điều này áp dụng các biểu thức chính quy lặp đi lặp lại. Đầu tiên, nó thay thế tất cả các số nguyên xbằng một bộ danh sách đơn [(x,0)]. Sau đó, biểu thức chính quy đầu tiên thực hiện dthao tác, bằng cách thay thế tất cả [(x,0)]d[(b,0)]bằng biểu diễn chuỗi của một mảng các bộ dữ liệu như thế nào [(1,b),(2,b),(3,b)]. Phần tử thứ hai của mỗi bộ là toán hạng thứ hai d. Sau đó, các biểu thức chính quy tiếp theo thực hiện từng toán tử khác. Có một regex đặc biệt để loại bỏ parens khỏi các biểu thức được tính toán đầy đủ.


3

Clojure, 731 720 byte

(khi dòng mới bị xóa)

Cập nhật: thực hiện ngắn hơn F.

(defn N[i](if(seq? i)(apply + i)i))
(defn g[i](let[L(fn[i](let[v(g i)](if(seq? v)v(list v))))R remove T take](if(seq? i)(let[[o a b :as A]i](if(some symbol? A)(case o d(repeatedly(N(g a))(fn[](inc(rand-int(N(g b))))))t(T(N(g b))(sort(g a)))T(T(N(g b))(sort-by -(g a)))r(for[i(L a)](if((set(L b))i)(nth(L a)0)i))R(T(count(L a))(R(set(L b))(for[_(range)i(L a)]i)))+(+(N(g a))(N(g b)))-(-(N(g a))(N(g b))).(into(L a)(L b))_(R(set(L b))(g a)))A))i)))
(defn F[T](if(seq? T)(if(next T)(loop[[s & S]'[_ . - + R r T t d]](let[R reverse[b a](map R(split-with(comp not #{s})(R T)))a(butlast a)](if a(cons s(map F[a b]))(recur S))))(F(first T)))T))
(defn f[i](N(g(F(read-string(clojure.string/replace(str"("i")")#"[^0-9]"" $0 "))))))

Điều này bao gồm bốn phần chính:

  • N: ép buộc một danh sách thành một số
  • g: đánh giá một cây cú pháp trừu tượng (biểu thức S có 3 mục)
  • F: chuyển đổi một AST kết hợp thành ký hiệu tiền tố (biểu thức S), cũng áp dụng quyền ưu tiên thứ tự toán hạng
  • f: sử dụng read-stringđể chuyển đổi một chuỗi thành một chuỗi các số và ký hiệu lồng nhau (infix AST), dẫn chúng qua F -> g -> N, trả về số kết quả.

Tôi không chắc chắn làm thế nào để kiểm tra kỹ lưỡng điều này, có thể thông qua các bài kiểm tra thống kê đối với việc triển khai tham chiếu? Ít nhất AST và đánh giá của nó là tương đối dễ theo dõi.

Ví dụ biểu thức S từ 1d((8d20t4T2)d(6d6R1r6)-2d4+1d2).(1d(4d6_3d3)):

(. (d 1 (- (d (T (t (d 8 20) 4) 2)
              (R (d 6 6) (r 1 6)))
           (+ (d 2 4)
              (d 1 2))))
   (d 1 (_ (d 4 6) (d 3 3))))

Ít chơi golf hơn với các kết quả và bài kiểm tra thực tập:

(def f #(read-string(clojure.string/replace(str"("%")")#"[^0-9]"" $0 ")))

(defn F [T]
  (println {:T T})
  (cond
    (not(seq? T))T
    (symbol?(first T))T
    (=(count T)1)(F(first T))
    1(loop [[s & S] '[_ . - + R r T t d]]
      (let[[b a](map reverse(split-with(comp not #{s})(reverse T)))
           _ (println [s a b])
           a(butlast a)]
        (cond
          a(do(println {:s s :a a :b b})(cons s(map F[a b])))
          S(recur S))))))


(->> "3d6" f F)
(->> "3d6t2" f F)
(->> "3d2R1" f F)
(->> "1d4d4" f F)
(->> "2d6.2d6" f F)
(->> "(3d2R1)d2" f F)
(->> "1d((8d20t4T2)d(6d6R1r6)-2d4+1d2).(1d(4d6_3d3))" f F)

(defn N[i](if(seq? i)(apply + i)i))

(defn g[i]
  (let[L(fn[i](let[v(g i)](if(seq? v)v(list v))))]
    (if(seq? i)
      (let[[o a b :as A] i]
        (println {:o o :a a :b b :all A})
        (if(every? number? A)(do(println{:A A})A)
           (case o
            d (repeatedly(N (g a))(fn[](inc(rand-int(N (g b))))))
            t (take(N (g b))(sort(g a)))
            T (take(N (g b))(sort-by -(g a)))
            r (for[i(L a)](if((set(L b))i)(nth(L a)0)i))
            R (take(count(g a))(remove(set(L b))(for[_(range)i(g a)]i)))
            + (+(N (g a))(N (g b)))
            - (-(N (g a))(N (g b)))
            . (into(L a)(L b))
            _ (remove(set(L b))(g a)))))
      (do(println {:i i})i))))


(g '(. (d 3 5) (d 4 3)))
(g '(. 1 (2 3)))
(g '(+ 1 (2 3)))
(g '(R (d 10 5) (d 1 3)))
(g '(T (d 5 20) 3))
(g '(t (d 5 20) 3))
(g '(d (d 3 4) 10))
(g '(d 4 3))
(g '(_ (d 4 6) (d 3 3)))

(->> "1d(4d6_3d3)" f F g)
(->> "1r6" f F g)
(->> "(8d20t4T2)d(6d6R1r6)" f F g)
(->> "(8d20t4T2)d(6d6R1r6)-2d4+1d2).(1d(4d6_3d3)" f F g)
(->> "1d((8d20t4T2)d(6d6R1r6)-2d4+1d2).(1d(4d6_3d3))" f F g))

2

Python 3, 695 byte

import random,tatsu
A=lambda x:sum(x)or 1
H=lambda x:[[d,D(d.s)][d in x[2]]for d in x[0]]
R=lambda x:R([H(x)]+x[1:])if{*x[0]}&{*x[2]}else x[0]
class D(int):
 def __new__(cls,s):o=super().__new__(cls,random.randint(1,s));o.s = s;return o
class S:
 o=lambda s,x:{'+':[A(x[0])+A(x[2])],'-':[A(x[0])-A(x[2])],'.':x[0]+x[2],'_':[d for d in x[0]if d not in x[2]]}[x[1]]
 f=lambda s,x:{'r':H(x),'R':R(x),'t':sorted(x[0])[:A(x[2])],'T':sorted(x[0])[-A(x[2]):]}[x[1]]
 d=lambda s,x:[D(A(x[2]))for _ in' '*A(x[0])]
 n=lambda s,x:[int(x)]
 l=lambda s,x:sum(x,[])
lambda i:tatsu.parse("s=e$;e=o|t;o=e/[-+._]/t;t=f|r;f=t/[rRtT]/r;r=d|a;d=r/d/a;a=n|l|p;n=/\d+/;l='['@:','.{n}']';p='('@:e')';",i,semantics=S())

Một trình thông dịch được xây dựng bằng cách sử dụng tatsu, một thư viện trình phân tích cú pháp PEG. Đối số đầu tiên tatsu.parser()là ngữ pháp PEG.

class D(cho Die) các lớp con được xây dựng theo intkiểu. Giá trị của nó là kết quả của một cuộn. Thuộc tính .slà số cạnh trên khuôn.

class S có các hành động ngữ nghĩa cho trình phân tích cú pháp và thực hiện trình thông dịch.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.