जटिल पासा रोलिंग अभिव्यक्तियाँ


23

पृष्ठभूमि

मैं कुछ दोस्तों के साथ नियमित आधार पर डी एंड डी खेलता हूं। जबकि कुछ प्रणालियों / संस्करणों की जटिलता के बारे में बात करते हुए जब यह पासा को लुढ़काने और बोनस और दंड लागू करने की बात आती है, तो हम मजाक में पासा रोलिंग अभिव्यक्तियों के लिए कुछ अतिरिक्त जटिलता के साथ आए। उनमें से कुछ बहुत ही अपमानजनक थे (जैसे 2d6कि मैट्रिक्स तर्कों 1 की तरह सरल पासा के भावों का विस्तार करना ), लेकिन बाकी एक दिलचस्प प्रणाली के लिए बनाते हैं।

चुनौती

एक जटिल पासा अभिव्यक्ति को देखते हुए, निम्नलिखित नियमों के अनुसार इसका मूल्यांकन करें और परिणाम का उत्पादन करें।

बुनियादी मूल्यांकन नियम

  • जब भी कोई ऑपरेटर एक पूर्णांक की उम्मीद करता है, लेकिन एक ऑपरेंड के लिए एक सूची प्राप्त करता है, तो उस सूची का योग उपयोग किया जाता है
  • जब भी कोई ऑपरेटर एक सूची की उम्मीद करता है, लेकिन एक ऑपरेंड के लिए एक पूर्णांक प्राप्त करता है, तो पूर्णांक को उस पूर्णांक की एक-तत्व सूची के रूप में माना जाता है

ऑपरेटर्स

सभी ऑपरेटर बाइनरी इन्फिक्स ऑपरेटर हैं। स्पष्टीकरण के उद्देश्य के aलिए, बाएं ऑपरेंड bहोगा , और सही ऑपरेंड होगा। सूची संकेतन का उपयोग उन उदाहरणों के लिए किया जाएगा जहां ऑपरेटर ऑपरेंड के रूप में सूची ले सकते हैं, लेकिन वास्तविक अभिव्यक्तियों में केवल सकारात्मक पूर्णांक और ऑपरेटर होते हैं।

  • d: aरेंज में स्वतंत्र वर्दी रैंडम पूर्णांक आउटपुट[1, b]
    • वरीयता: ३
    • दोनों ऑपरेंड पूर्णांक हैं
    • उदाहरण: 3d4 => [1, 4, 3],[1, 2]d6 => [3, 2, 6]
  • t: bसबसे कम मान लेंa
    • वरीयता: २
    • aएक सूची है, bएक पूर्णांक है
    • यदि b > len(a), सभी मान वापस कर दिए जाते हैं
    • उदाहरण: [1, 5, 7]t1 => [1], [5, 18, 3, 9]t2 => [3, 5],3t5 => [3]
  • T: bउच्चतम मान लेंa
    • वरीयता: २
    • aएक सूची है, bएक पूर्णांक है
    • यदि b > len(a), सभी मान वापस कर दिए जाते हैं
    • उदाहरण: [1, 5, 7]T1 => [7], [5, 18, 3, 9]T2 => [18, 9],3T5 => [3]
  • r: यदि कोई तत्व अंदर bहैं a, तो उन तत्वों को फिर से सींचें, जो कुछ भी dबयान उन्हें उत्पन्न करता है
    • वरीयता: २
    • दोनों ऑपरेंड लिस्ट हैं
    • रीरोलिंग केवल एक बार किया जाता है, इसलिए bपरिणाम में अभी भी तत्व होना संभव है
    • उदाहरण: 3d6r1 => [1, 3, 4] => [6, 3, 4], 2d4r2 => [2, 2] => [3, 2],3d8r[1,8] => [1, 8, 4] => [2, 2, 4]
  • R: यदि कोई भी तत्व अंदर bहैं a, तो उन तत्वों को बार-बार तब तक रेरॉल करें जब तक कि कोई भी तत्व bमौजूद न हो, जो भी dकथन ने उन्हें उत्पन्न किया है
    • वरीयता: २
    • दोनों ऑपरेंड लिस्ट हैं
    • उदाहरण: 3d6R1 => [1, 3, 4] => [6, 3, 4], 2d4R2 => [2, 2] => [3, 2] => [3, 1],3d8R[1,8] => [1, 8, 4] => [2, 2, 4]
  • +: जोड़ें aऔर bएक साथ
    • वरीयता: १
    • दोनों ऑपरेंड पूर्णांक हैं
    • उदाहरण: 2+2 => 4, [2]+[2] => 4,[3, 1]+2 => 6
  • -: घटाना bसेa
    • वरीयता: १
    • दोनों ऑपरेंड पूर्णांक हैं
    • b हमेशा से कम होगी a
    • उदाहरण: 2-1 => 1, 5-[2] => 3,[8, 3]-1 => 10
  • .: समवर्ती aऔर bएक साथ
    • वरीयता: १
    • दोनों ऑपरेंड लिस्ट हैं
    • उदाहरण: 2.2 => [2, 2], [1].[2] => [1, 2],3.[4] => [3, 4]
  • _: निकाले गए aसभी तत्वों के साथ आउटपुटb
    • वरीयता: १
    • दोनों ऑपरेंड लिस्ट हैं
    • उदाहरण: [3, 4]_[3] => [4], [2, 3, 3]_3 => [2],1_2 => [1]

अतिरिक्त नियम

  • यदि किसी अभिव्यक्ति का अंतिम मूल्य एक सूची है, तो इसे आउटपुट से पहले संक्षेपित किया जाता है
  • शर्तों का मूल्यांकन केवल सकारात्मक पूर्णांक या सकारात्मक पूर्णांक की सूची के परिणामस्वरूप होगा - कोई भी अभिव्यक्ति जिसके परिणामस्वरूप गैर-सकारात्मक पूर्णांक या कम से कम एक गैर-सकारात्मक पूर्णांक वाली सूची में उन मानों को 1s द्वारा प्रतिस्थापित किया जाएगा।
  • कोष्ठक का उपयोग समूह की शर्तों और मूल्यांकन के आदेश को निर्दिष्ट करने के लिए किया जा सकता है
  • संचालकों का मूल्यांकन सबसे कम पूर्वता से सबसे कम पूर्वता के क्रम में किया जाता है, मूल्यांकन के साथ बंधी हुई स्थिति के मामले में बाएं से दाएं कार्यवाही होती है (इसलिए 1d4d4इसका मूल्यांकन किया जाएगा (1d4)d4)
  • सूचियों में तत्वों का क्रम मायने नहीं रखता है - यह एक ऑपरेटर के लिए पूरी तरह से स्वीकार्य है जो एक सूची को अपने तत्वों के साथ एक अलग क्रम में वापस करने के लिए संशोधित करता है
  • जिन शर्तों का मूल्यांकन नहीं किया जा सकता है या जिनके परिणामस्वरूप अनंत लूप (जैसे 1d1R1या 3d6R[1, 2, 3, 4, 5, 6]) मान्य नहीं होंगे

परीक्षण के मामलों

प्रारूप: 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

सभी लेकिन अंतिम परीक्षण मामला संदर्भ कार्यान्वयन के साथ उत्पन्न हुआ था।

काम किया उदाहरण

अभिव्यक्ति: 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](पूर्ण: 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 (किया हुआ)

संदर्भ कार्यान्वयन

यह संदर्भ कार्यान्वयन 0परीक्षण योग्य, सुसंगत आउटपुट के लिए प्रत्येक अभिव्यक्ति के मूल्यांकन के लिए एक ही निरंतर बीज ( ) का उपयोग करता है । यह एसटीडीआईएन पर इनपुट की उम्मीद करता है, जिसमें प्रत्येक अभिव्यक्ति को अलग करने वाली नई रूपरेखाएँ हैं।

#!/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()

[१]: adbमैट्रिक्स तर्कों के लिए हमारी परिभाषा AdXप्रत्येक Xमें a * b, जहाँ, के लिए रोल करने की थी A = det(a * b)। जाहिर है कि इस चुनौती के लिए बहुत बेतुका है।



इस बात की गारंटी के साथ -कि मैं bहमेशा aगैर-सकारात्मक पूर्णांक प्राप्त करने का कोई रास्ता नहीं देखूंगा, इसलिए दूसरा अतिरिक्त नियम निरर्थक लगता है। OTOH, _एक रिक्त सूची में परिणाम कर सकता है, जो समान मामलों में उपयोगी लगता है लेकिन जब पूर्णांक की आवश्यकता होती है तो इसका क्या अर्थ है? आम तौर पर मैं कहूंगा कि योग है 0...
क्रिश्चियन सेवर्स

@ChristianSievers 1) मैंने स्पष्टता के लिए गैर-सकारात्मक पूर्णांकों के बारे में अतिरिक्त नोट जोड़ा। 2) एक खाली सूची का योग है 0। नॉन-पॉज़िटिव नियम द्वारा, इसका मूल्यांकन ए के रूप में किया जाएगा 1
मेगो

ठीक है, लेकिन क्या यह मध्यवर्ती परिणाम के रूप में ठीक है? तो [1,2]_([1]_[1])है [1,2]?
क्रिश्चियन सिवर्स

@ क्रिसटनसिवर्स नं। इसके परिणामस्वरूप [2], क्योंकि [1]_[1] -> [] -> 0 -> 1 -> [1]
मेगो

जवाबों:


9

पायथन 3, 803 788 753 749 744 748 745 740 700 695 682 बाइट्स

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 बाइट्स Mr.Xcoder के लिए धन्यवाद

एनजीएन को -5 और बाइट्स धन्यवाद

-जोनाथन फ्रेंच के लिए 40 बाइट्स धन्यवाद

हाँ, क्या एक कीचड़ है! यह मेरी kकक्षा में सभी नंबरों को लपेटने के लिए एक नियमित अभिव्यक्ति का उपयोग करके काम करता है , और सभी संचालकों को ऑपरेटरों में परिवर्तित करके अजगर समझता है, फिर kगणित को संभालने के लिए कक्षा के जादुई तरीकों का उपयोग करता है । +-और +--के लिए अंत में .और _पूर्वता सही रखने के लिए एक हैक कर रहे हैं। इसी तरह, मैं **डी के लिए ऑपरेटर का उपयोग नहीं कर सकता क्योंकि ऐसा करने 1d4d4से पार्स हो जाएगा 1d(4d4)। इसके बजाय, मैं सभी नंबरों को एक अतिरिक्त सेट ऑफ परेंस में लपेटता हूं और डी के रूप में करता हूं .j, क्योंकि मेथड कॉल की उच्च प्रवृत्ति है जो ऑपरेटर्स की है। अंतिम पंक्ति एक अनाम फ़ंक्शन के रूप में मूल्यांकन करती है जो अभिव्यक्ति का मूल्यांकन करती है।


def __mod__(a, b)... क्यों a,और के बीच की जगह b?
श्री एक्सकोडर


@ Mr.Xcoder मुझे लगता है कि आप एक अनावश्यक स्थान को हटाकर एक बाइट बचा सकते हैं ; __sub__:। और संभवतः यहां भी lambda a,b: l(:।
जोनाथन फ्रीच

1
आप एक exec("""...""".replace("...","..."))स्टेटमेंट में अपने पूरे कोड को लपेटकर और अक्सर (जैसे return ) होने वाले स्ट्रिंग्स को बदलकर कुछ बाइट्स बचा सकते हैं । हालांकि, मुझे करने के लिए exec-stategy हमेशा थोड़ा असभ्य लगता है ...
जोनाथन फ्रीच

के शरीर __mod__और __add__जरूरत नहीं है कि ज्यादा इंडेंट
ngn

3

एपीएल (डायलॉग क्लासिक) , 367 बाइट्स

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

इसे ऑनलाइन आज़माएं!

evaluate_dice()क्रॉफ्ट और ऑब्जेक्ट-ओरिएंटेड बकवास के बिना विलय के संदर्भ कार्यान्वयन से यह शंटिंग यार्ड एल्गोरिदम है । केवल दो स्टैक का उपयोग किया जाता है: hऑपरेटरों के vलिए और मूल्यों के लिए। पार्सिंग और मूल्यांकन परस्पर जुड़े हुए हैं।

मध्यवर्ती परिणामों को 2 × N मेट्रिसेस के रूप में दर्शाया जाता है जहां पहली पंक्ति यादृच्छिक मान होती है और दूसरी पंक्ति उन पासा पर पक्षों की संख्या होती है जो उन्हें पैदा करते हैं। जब एक परिणाम पासा-फेंकने वाले "डी" ऑपरेटर द्वारा निर्मित नहीं होता है, तो दूसरी पंक्ति में मनमानी संख्याएं होती हैं। एकल यादृच्छिक मान 2 × 1 मैट्रिक्स है और इस प्रकार 1-तत्व सूची से अप्रभेद्य है।


3

पायथन 3: 723 722 714 711 707 675 653 665 बाइट्स

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)

प्रवेश बिंदु है E। यह नियमित रूप से भावों पर लागू होता है। पहले यह xएक पूर्णांक सूची सूची के साथ सभी पूर्णांकों को प्रतिस्थापित करता है [(x,0)]। फिर पहली नियमित अभिव्यक्ति dऑपरेशन का प्रदर्शन करती है , [(x,0)]d[(b,0)]जैसे कि टुपल्स की एक सरणी के स्ट्रिंग प्रतिनिधित्व के साथ सभी को प्रतिस्थापित करके [(1,b),(2,b),(3,b)]। प्रत्येक टपल का दूसरा तत्व दूसरा ऑपरेंड है d। फिर, बाद के नियमित भाव प्रत्येक अन्य संचालक का प्रदर्शन करते हैं। पूरी तरह से गणना की गई अभिव्यक्तियों से पार्न्स को हटाने के लिए एक विशेष रेगेक्स है।


3

क्लोजर, 731 720 बाइट्स

(जब newlines निकाल दिए जाते हैं)

अद्यतन: का एक छोटा कार्यान्वयन 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 "))))))

इसमें चार मुख्य भाग होते हैं:

  • N: एक सूची को एक संख्या में समेटता है
  • g: एक सार वाक्यविन्यास पेड़ का मूल्यांकन करता है (3 आइटम के साथ एस-भाव)
  • F: एक infix एएसटी को उपसर्ग संकेतन (एस-एक्सप्रेशन) में परिवर्तित करता है, साथ ही ऑपरेंड ऑर्डर पूर्ववर्तीता को भी लागू करता है
  • f: read-stringसंख्याओं और प्रतीकों के एक नेस्टेड अनुक्रम में एक स्ट्रिंग को बदलने के लिए उपयोग करता है (infix एएसटी), उन्हें एफ -> जी -> एन के माध्यम से पाइप करता है, परिणाम संख्या लौटाता है।

मुझे यकीन नहीं है कि एक संदर्भ कार्यान्वयन के खिलाफ सांख्यिकीय परीक्षणों के माध्यम से इसे पूरी तरह से कैसे परीक्षण किया जाए? कम से कम एएसटी और इसके मूल्यांकन का पालन करना अपेक्षाकृत आसान है।

उदाहरण एस से अभिव्यक्ति 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))))

प्रशिक्षुता परिणाम और परीक्षण के साथ कम गोल्फ:

(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

पायथन 3, 695 बाइट्स

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())

एक दुभाषिया tatsu, एक खूंटी पार्सर पुस्तकालय का उपयोग कर बनाया गया है । पहला तर्क tatsu.parser()खूंटी व्याकरण है।

class D(डाई के लिए) निर्मित intप्रकार में उप-वर्ग करता है । यह एक रोल का परिणाम है। विशेषता .sमरने पर पक्षों की संख्या है।

class S पार्सर के लिए शब्दार्थ क्रियाएँ हैं, और दुभाषिया को लागू करता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.