【问题标题】:Evaluate dice rolling notation strings评估骰子滚动符号字符串
【发布时间】:2010-11-05 02:41:24
【问题描述】:

规则

编写一个接受字符串作为参数的函数,返回 dice notation 中表达式的评估值, 包括加法和乘法。

为了清楚起见,这里是 EBNF 对法律表达式的定义:

roll ::= [positive integer], "d", positive integer
entity ::= roll | positive number
expression ::= entity { [, whitespace], "+"|"*"[, whitespace], entity }

示例输入:

  • “3d6 + 12”
  • “4*d12 + 3”
  • “d100”

不禁止使用 eval 函数或类似函数,但我鼓励 不使用这些来解决。欢迎再次入园。

我不能提供测试用例,因为输出应该是随机的;)。

格式化您的答案标题:语言、n 个字符(重要说明 — 无 eval 等)


我的ruby解决方案,92 81个字符,使用eval:

def f s
eval s.gsub(/(\d+)?d(\d+)/i){eval"a+=rand $2.to_i;"*a=($1||1).to_i}
end

另一个 ruby 解决方案,不是更短(92 个字符),但我觉得它很有趣——它仍然使用 eval,但这次以非常有创意的方式。

class Fixnum
def**b
eval"a+=rand b;"*a=self
end
end
def f s
eval s.gsub(/d/,'**')
end

【问题讨论】:

  • @Johannes,我想 4*d12 可能意味着滚动一个 d12 并将结果乘以 4(而不是将 d12 滚动 4 次并将结果相加)。无论如何,这听起来像是某人的作业,原始发布者应该发布一些他们自己的代码,以表明他们至少做出了努力。
  • 听起来更像是回避家庭作业而不是家庭作业 ;-)
  • 2d2d6 确实有一个有用的含义,即 (2-4)d6,而且我见过要求掷随机数骰子的游戏。 2d(2d6) 对我来说没有意义。并不是说它需要在问题中。
  • Onorio 是对的 - 标准 RPG 表示法是 4d12 表示 d12 + d12 + d12 + d12,但 4*d12 将是 4 * d12。
  • RPG?谁说的RPG?!我敢肯定这是针对完全不相关的事情。对 Wisdom 进行检查,看看你是否相信我。

标签: language-agnostic dice expression-evaluation


【解决方案1】:

C# 类。它递归地评估加法和乘法,从左到右链式掷骰子

编辑:

  • 在每次通话中删除 .Replace(" ","")
  • 改为在int.TryParse 上添加.Trim()
  • 现在所有工作都以单一方法完成
  • 如果未指定模具面数,则假定为 6(参见 Wiki 文章)
  • 重构冗余调用以解析“d”的左侧
  • 重构了不必要的if 语句

缩小:(411 字节)

class D{Random r=new Random();public int R(string s){int t=0;var a=s.Split('+');if(a.Count()>1)foreach(var b in a)t+=R(b);else{var m=a[0].Split('*');if(m.Count()>1){t=1;foreach(var n in m)t*=R(n);}else{var d=m[0].Split('d');if(!int.TryParse(d[0].Trim(),out t))t=0;int f;for(int i=1;i<d.Count();i++){if(!int.TryParse(d[i].Trim(),out f))f=6;int u=0;for(int j=0;j<(t== 0?1:t);j++)u+=r.Next(1,f);t+=u;}}}return t;}}

展开形式:

    class D
    {
        /// <summary>Our Random object.  Make it a first-class citizen so that it produces truly *random* results</summary>
        Random r = new Random();

        /// <summary>Roll</summary>
        /// <param name="s">string to be evaluated</param>
        /// <returns>result of evaluated string</returns>
        public int R(string s)
        {
            int t = 0;

            // Addition is lowest order of precedence
            var a = s.Split('+');

            // Add results of each group
            if (a.Count() > 1)
                foreach (var b in a)
                    t += R(b);
            else
            {
                // Multiplication is next order of precedence
                var m = a[0].Split('*');

                // Multiply results of each group
                if (m.Count() > 1)
                {
                    t = 1; // So that we don't zero-out our results...

                    foreach (var n in m)
                        t *= R(n);
                }
                else
                {
                    // Die definition is our highest order of precedence
                    var d = m[0].Split('d');

                    // This operand will be our die count, static digits, or else something we don't understand
                    if (!int.TryParse(d[0].Trim(), out t))
                        t = 0;

                    int f;

                    // Multiple definitions ("2d6d8") iterate through left-to-right: (2d6)d8
                    for (int i = 1; i < d.Count(); i++)
                    {
                        // If we don't have a right side (face count), assume 6
                        if (!int.TryParse(d[i].Trim(), out f))
                            f = 6;

                        int u = 0;

                        // If we don't have a die count, use 1
                        for (int j = 0; j < (t == 0 ? 1 : t); j++)
                            u += r.Next(1, f);

                        t += u;
                    }
                }
            }

            return t;
        }
    }

测试用例:

    static void Main(string[] args)
    {
        var t = new List<string>();
        t.Add("2d6");
        t.Add("2d6d6");
        t.Add("2d8d6 + 4d12*3d20");
        t.Add("4d12");
        t.Add("4*d12");
        t.Add("4d"); // Rolls 4 d6

        D d = new D();
        foreach (var s in t)
            Console.WriteLine(string.Format("{0}\t{1}", d.R(s), s));
    }

【讨论】:

  • 真正的问题空间包括负面和正面。
  • @Hardwareguy,代码打高尔夫球的目的根本不是可读性。
  • @Loren:是的,但在这种情况下,“问题陈述”被列为仅加法和乘法。
【解决方案2】:

J

在 cobbal 的帮助下,将所有内容压缩成 93 个字符。

$ jconsole e=:".@([`('%'"_)@.(=&'/')"0@,)@:(3 :'":(1".r{.y)([: +/>:@?@$) ::(y&[)0".}.y}.~r=.y i.''d'''@>)@;: e'3d6 + 12' 20 e 10$,:'3d6 + 12' 19 23 20 26 24 20 20 20 24 27 e 10$,:'4*d12 + 3' 28 52 56 16 52 52 52 36 44 56 e 10$,:'d100' 51 51 79 58 22 47 95 6 5 64

【讨论】:

  • 尝试用 ": (1 ". r {. y) d :: (y&[) 0 ". }. y }.~ r =. y i. 'd 替换 f 的内部'
  • 谢谢!在这个部分我们需要更多的 J 用户。当有 50,000 种方法可以解决问题时,让其他人寻找替代方法真的很有帮助:)
  • 这是一种有点令人生畏的语言,但你可以用它做些什么真是太棒了。当然会改变你对许多问题的看法
【解决方案3】:

JavaScript 解决方案,压缩时 340 个字符(无 eval,支持前缀乘法和后缀加法):

function comp (s, m, n, f, a) {
    m = parseInt( m );
    if( isNaN( m ) ) m = 1;
    n = parseInt( n );
    if( isNaN( n ) ) n = 1;
    f = parseInt( f );
    a = typeof(a) == 'string' ? parseInt( a.replace(/\s/g, '') ) : 0;
    if( isNaN( a ) ) a = 0;
    var r = 0;
    for( var i=0; i<n; i++ )
        r += Math.floor( Math.random() * f );
    return r * m + a;
};
function parse( de ) {
    return comp.apply( this, de.match(/(?:(\d+)\s*\*\s*)?(\d*)d(\d+)(?:\s*([\+\-]\s*\d+))?/i) );
}

测试代码:

var test = ["3d6 + 12", "4*d12 + 3", "d100"];
for(var i in test)
    alert( test[i] + ": " + parse(test[i]) );

压缩版(很确定你可以做得更短):

function c(s,m,n,f,a){m=parseInt(m);if(isNaN(m))m=1;n=parseInt(n);if(isNaN(n))n=1;f=parseInt(f);a=typeof(a)=='string'?parseInt(a.replace(/\s/g,'')):0;if(isNaN(a))a=0;var r=0;for(var i=0;i<n;i++)r+=Math.floor(Math.random()*f);return r*m+a;};function p(d){return c.apply(this,d.match(/(?:(\d+)\s*\*\s*)?(\d*)d(\d+)(?:\s*([\+\-]\s*\d+))?/i));}

【讨论】:

    【解决方案4】:

    Clojure,854 个字符,412 个缩小

    只需运行“(roll-dice "input-string")”。

    (defn roll-dice
      [string]
      (let [parts (. (. (. string replace "-" "+-") replaceAll "\\s" "") split "\\+")
            dice-func (fn [d-notation]
                        (let [bits (. d-notation split "d")]
                          (if (= 1 (count bits))
                            (Integer/parseInt (first bits))  ; Just a number, like 12
                            (if (zero? (count (first bits)))
                              (inc (rand-int (Integer/parseInt (second bits))))  ; Just d100 or some such
                              (if (. (first bits) contains "*")
                                (* (Integer/parseInt (. (first bits) replace "*" ""))
                                    (inc (rand-int (Integer/parseInt (second bits)))))
                                (reduce +
                                  (map #(+ 1 %)
                                        (map rand-int
                                            (repeat
                                              (Integer/parseInt (first bits))
                                              (Integer/parseInt (second bits)))))))))))]      
        (reduce + (map dice-func parts))))
    

    为了缩小,我将变量设为 1 个字母,将(第一位)/(第二位)移动到变量中,将 dice-func 设为匿名函数,为 Integer.parseInt 制作一个名为“i”的包装器,并去掉 cmets和额外的空格。

    这应该适用于任何有效的东西,不管有没有空格。只是不要向它询问“15dROBERT”,它会抛出异常。

    他们的工作方式是将字符串分成骰子(这是第三行,let)。所以“5d6+2*d4-17”变成了“5d6”、“2*d4”、“-17”。

    然后每一个都由函数 dice-func 处理,并将结果相加(这是最后一行的 map/reduce)

    Dice-func 需要一个小骰子字符串(例如“5d6”)并将其拆分到“d”上。如果只剩下一个部分,那就是一个简单的数字(6、-17 等)。

    如果第一部分包含 *,我们将该数字乘以一个随机整数,从 1 到(d 之后的数字),包括 1。

    如果第一部分不包含 *,我们取第一个随机数(就像上一行一样)并将它们相加(这是中间的 map/reduce)。

    这是一个有趣的小挑战。

    【讨论】:

      【解决方案5】:

      perl 评估版本,72 个字符

      sub e{$_=pop;s/(\d+)?d(\d+)/\$a/i;$a+=1+int rand$2-1for 0...$1-1;eval$_}
      

      运行方式

      print e("4*d12+3"),"\n";
      

      基于 ruby​​ 解决方案,只能运行一次(你应该在运行之间undef $a)。

      较短的版本,68 个字符,时髦(基于 0)骰子

      sub e{$_=pop;s/(\d+)?d(\d+)/\$a/i;$a+=int rand$2for 0...$1-1;eval$_}
      

      编辑

      perl 5.8.8 不喜欢以前的版本,这里有一个 73 字符的版本可以工作

      sub e{$_=pop;s/(\d+)?d(\d+)/\$a/i;$a+=1+int rand$2-1for 1...$1||1;eval$_}
      

      70 字符版本支持多卷

      sub e{$_=pop;s/(\d*)d(\d+)/$a=$1||1;$a+=int rand$a*$2-($a-1)/ieg;eval}
      

      【讨论】:

      • 规则没有提到重入,所以你的解决方案是正确的:)
      • 一些缩短提示 - 使用 '..' 代替 '...',使用 '(\d*)' 而不是 '(\d+)?',如果给出 eval()没有参数它默认为 $_
      【解决方案6】:

      F#(no eval 和 no 正则表达式)

      233 个字符

      这个解决方案应该是完全通用的,因为它可以处理你扔给它的任何字符串,甚至是一些疯狂的东西,例如:

      43d29d16d21*9 + d7d9*91 + 2*d24*7

      需要全局定义:

      let r = new System.Random()
      

      完全混淆的版本:

      let f(s:string)=let g d o i p (t:string)=t.Split([|d|])|>Array.fold(fun s x->o s (p x))i in g '+'(+)0(g '*' (*) 1 (fun s->let b=ref true in g 'd'(+)1(fun t->if !b then b:=false;(if t.Trim()=""then 1 else int t)else r.Next(int t))s))s
      

      可读版本:

      let f (s:string) =
          let g d o i p (t:string) =
              t.Split([|d|]) |> Array.fold (fun s x -> o s (p x)) i
          g '+' (+) 0 (g '*' (*) 1 (fun s ->
                                              let b = ref true
                                              g 'd' (+) 1 (fun t ->
                                              if !b then b := false; (if t.Trim() = "" then 1 else int t)
                                              else r.Next(int t)) s)) s
      

      我正在挑战某人以击败此解决方案(以任何语言)不使用使用eval 或正则表达式。我认为这可能是可能的,但我仍然有兴趣看到这种方法。

      【讨论】:

        【解决方案7】:

        Python 124 个字符带 eval,154 个不带。

        只是为了说明 python 没有 可读性,这里有一个 124 个字符的解决方案,与原始的基于 eval 的方法类似:

        import random,re
        f=lambda s:eval(re.sub(r'(\d*)d(\d+)',lambda m:int(m.group(1)or 1)*('+random.randint(1,%s)'%m.group(2)),s))
        

        [编辑] 这是一个没有 eval 的 154 个字符:

        import random,re
        f=lambda s:sum(int(c or 0)+sum(random.randint(1,int(b))for i in[0]*int(a or 1))for a,b,c in re.findall(r'(\d*)d(\d+)(\s*[+-]\s*\d+)?',s))
        

        注意:两者都适用于“2d6 + 1d3 + 5”等输入,但不支持“2d3d6”或负骰子等更高级的变体(“1d6-4”可以,但“1d6-2d4”不行t) (您可以在第二个字符中去掉 2 个字符以完全不支持负数)

        【讨论】:

          【解决方案8】:

          python,隐藏版本中的 197 个字符。

          可读版本:369 个字符。没有 eval,直接解析。

          import random
          def dice(s):
              return sum(term(x) for x in s.split('+'))
          def term(t):
              p = t.split('*')
              return factor(p[0]) if len(p)==1 else factor(p[0])*factor(p[1])
          def factor(f):
              p = f.split('d')
              if len(p)==1:
                  return int(f)
              return sum(random.randint(1, int(g[1]) if g[1] else 6) for \
                         i in range(int(g[0]) if g[0] else 1))
          

          压缩版:258 个字符,单字符名称,滥用条件表达式,逻辑表达式中的快捷方式:

          import random
          def d(s):
           return sum(t(x.split('*')) for x in s.split('+'))
          def t(p):
           return f(p[0])*f(p[1]) if p[1:] else f(p[0])
          def f(s):
           g = s.split('d')
           return sum(random.randint(1, int(g[1] or 6)) for i in range(int(g[0] or 1))) if g[1:] else int(s)
          

          模糊版本:216 个字符,使用reduce,大量映射以避免“def”、“return”。

          import random
          def d(s):
           return sum(map(lambda t:reduce(lambda x,y:x*y,map(lambda f:reduce(lambda x,y:sum(random.randint(1,int(y or 6)) for i in range(int(x or 1))), f.split('d')+[1]),t.split('*')),1),s.split('+')))
          

          最新版本:197 个字符,折叠在 @Brain 的 cmets 中,添加了测试运行。

          import random
          R=reduce;D=lambda s:sum(map(lambda t:R(int.__mul__,map(lambda f:R(lambda x,y:sum(random.randint(1,int(y or 6))for i in[0]*int(x or 1)),f.split('d')+[1]),t.split('*'))),s.split('+')))
          

          测试:

          >>> for dice_expr in ["3d6 + 12", "4*d12 + 3","3d+12", "43d29d16d21*9+d7d9*91+2*d24*7"]: print dice_expr, ": ", list(D(dice_expr) for i in range(10))
          ... 
          3d6 + 12 :  [22, 21, 22, 27, 21, 22, 25, 19, 22, 25]
          4*d12 + 3 :  [7, 39, 23, 35, 23, 23, 35, 27, 23, 7]
          3d+12 :  [16, 25, 21, 25, 20, 18, 27, 18, 27, 25]
          43d29d16d21*9+d7d9*91+2*d24*7 :  [571338, 550124, 539370, 578099, 496948, 525259, 527563, 546459, 615556, 588495]
          

          此解决方案无法处理没有相邻数字的空格。所以 "43d29d16d21*9+d7d9*91+2*d24*7" 可以工作,但 "43d29d16d21*9 + d7d9*91 + 2*d24*7" 由于第二个空格(在 "+" 和 " d")。它可以通过首先从 s 中删除空格来纠正,但这会使代码长度超过 200 个字符,所以我会保留这个错误。

          【讨论】:

          • 我不认为这可以处理'd'之前的前缀。但是,如果我错了,请纠正我。
          • 您可以通过一些微优化将其降至 202:使用 d=lambda s:避免需要“返回”,节省 5 个字符。将 reduce 绑定到单个字符可以再节省 1,您可以将 range(int(x or 1)) 更改为 [0]*int(x or 1) 再多 4。第 2 行变为:“R=reduce;d=lambda s:sum(map(lambda t:R(lambda x,y:xy,map(lambda f:R(lambda x,y:sum(random.randint(1,int(y or 6))) i in[0]*int(x or 1)),f.split('d')+[1]),t.split('')),1),s.split('+ ')))"
          • 一项改进:“lambda x,y:x*y”可以更改为“int.__mul__”,使您低于200标记。
          • @Brain:谢谢。我喜欢在您的解决方案中使用 re,希望我已经有了这个想法。 @Noldorin:你的意思是像“3d6”这样的情况吗?如果有,处理了,如果没有,可以举个例子吗?
          【解决方案9】:

          perl,无 eval,144 个字符,多次工作,支持多次掷骰子

          sub e{($c=pop)=~y/+* /PT/d;$b='(\d+)';map{$a=0while$c=~s!$b?$_$b!$d=$1||1;$a+=1+int rand$2for 1..$d;$e=$2;/d/?$a:/P/?$d+$e:$d*$e!e}qw(d T P);$c}
          

          扩展版,带 cmets

          sub f {
              ($c = pop); #assign first function argument to $c
              $c =~ tr/+* /PT/d;  #replace + and * so we won't have to escape them later.
                                  #also remove spaces
              #for each of 'd','T' and 'P', assign to $_ and run the following
              map {
                  #repeatedly replace in $c the first instance of <number> <operator> <number> with
                  #the result of the code in second part of regex, capturing both numbers and
                  #setting $a to zero after every iteration
                  $a=0 while $c =~ s[(\d+)?$_(\d+)][
                      $d = $1 || 1;   #save first parameter (or 1 if not defined) as later regex 
                                      #will overwrite it
                      #roll $d dice, sum in $a
                      for (1..$d)
                      {
                          $a += 1 + int rand $2;
                      }
                      $e = $2;        #save second parameter, following regexes will overwrite
                      #Code blocks return the value of their last statement
                      if (/d/)
                      {
                          $a; #calculated dice throw
                      }
                      elsif (/P/)
                      {
                          $d + $e;
                      }
                      else
                      {
                          $d * $e;
                      }
                  ]e;
              } qw(d T P);
              return $c;
          }
          

          EDIT清理,更新到最新版本的解释

          【讨论】:

          • 你能提供去混淆的版本吗?
          • 添加了一些解释尝试。希望有一些意义
          • 谢谢。当我理解你的算法时,我有一个说法——你不能用单次调用来计算多个骰子掷骰的结果,因为它将具有均匀分布而不是接近高斯分布。
          • 添加了一个不统一骰子的版本,现在是 146 个字符而不是 145 个
          【解决方案10】:

          Ruby,166 个字符,无 eval

          在我看来相当优雅;)。

          def g s,o=%w{\+ \* d}
          o[a=0]?s[/#{p=o.pop}/]?g(s.sub(/(\d+)?\s*(#{p})\s*(\d+)/i){c=$3.to_i
          o[1]?($1||1).to_i.times{a+=rand c}+a:$1.to_i.send($2,c)},o<<p):g(s,o):s
          end
          

          反混淆版本+cmets:

          def evaluate(string, opers = ["\\+","\\*","d"])
            if opers.empty?
              string
            else
              if string.scan(opers.last[/.$/]).empty? # check if string contains last element of opers array
          
                # Proceed to next operator from opers array.
          
                opers.pop
                evaluate(string, opers)
          
              else # string contains that character...
          
                # This is hard to deobfuscate. It substitutes subexpression with highest priority with
                # its value (e.g. chooses random value for XdY, or counts value of N+M or N*M), and
                # calls recursively evaluate with substituted string.
          
                evaluate(string.sub(/(\d+)?\s*(#{opers.last})\s*(\d+)/i) { a,c=0,$3.to_i; ($2 == 'd') ? ($1||1).to_i.times{a+=rand c}+a : $1.to_i.send($2,c) }, opers)
          
              end
            end
          end
          

          【讨论】:

            【解决方案11】:

            Python,压缩版452字节

            我不确定这是酷、丑还是愚蠢,但写它很有趣。

            我们所做的如下:我们使用正则表达式(这通常不是处理这类事情的正确工具)将骰子符号字符串转换为基于堆栈的小型语言的命令列表。这种语言有四个命令:

            • mul 将栈顶的两个数字相乘并压入结果
            • add 将栈顶的两个数字相加并压入结果
            • roll 从堆栈中弹出骰子大小,然后计数,掷骰子大小的次数并推送结果
            • 一个数字只是将自己压入堆栈

            然后评估此命令列表。

            import re, random
            
            def dice_eval(s):
                s = s.replace(" ","")
                s = re.sub(r"(\d+|[d+*])",r"\1 ",s) #seperate tokens by spaces
                s = re.sub(r"(^|[+*] )d",r"\g<1>1 d",s) #e.g. change d 6 to 1 d 6
                while "*" in s:
                    s = re.sub(r"([^+]+) \* ([^+]+)",r"\1 \2mul ",s,1)
                while "+" in s:
                    s = re.sub(r"(.+) \+ (.+)",r"\1 \2add ",s,1)
                s = re.sub(r"d (\d+) ",r"\1 roll ",s)
            
                stack = []
            
                for token in s.split():
                    if token == "mul":
                        stack.append(stack.pop() * stack.pop())
                    elif token == "add":
                        stack.append(stack.pop() + stack.pop())
                    elif token == "roll":
                        v = 0
                        dice = stack.pop()
                        for i in xrange(stack.pop()):
                            v += random.randint(1,dice)
                        stack.append(v)
                    elif token.isdigit():
                        stack.append(int(token))
                    else:
                        raise ValueError
            
                assert len(stack) == 1
            
                return stack.pop() 
            
            print dice_eval("2*d12+3d20*3+d6")
            

            顺便说一下(这在问题 cmets 中讨论过),此实现将允许像 "2d3d6" 这样的字符串,将其理解为“将 d3 滚动两次,然后将 d6 滚动两次作为两次滚动的结果。 "

            此外,虽然有一些错误检查,但它仍然需要有效的输入。例如传递“*4”将导致无限循环。

            这是压缩版(不漂亮):

            import re, random
            r=re.sub
            def e(s):
             s=r(" ","",s)
             s=r(r"(\d+|[d+*])",r"\1 ",s)
             s=r(r"(^|[+*] )d",r"\g<1>1 d",s)
             while"*"in s:s=r(r"([^+]+) \* ([^+]+)",r"\1 \2M ",s)
             while"+"in s:s=r(r"(.+) \+ (.+)",r"\1 \2A ",s)
             s=r(r"d (\d+)",r"\1 R",s)
             t=[]
             a=t.append
             p=t.pop
             for k in s.split():
              if k=="M":a(p()*p())
              elif k=="A":a(p()+p())
              elif k=="R":
               v=0
               d=p()
               for i in [[]]*p():v+=random.randint(1,d)
               a(v)
              else:a(int(k))
             return p()
            

            【讨论】:

              【解决方案12】:

              Ruby,87 个字符,使用 eval

              这是我的 Ruby 解决方案,部分基于 OP。它缩短了五个字符,并且只使用了一次eval

              def f s
              eval s.gsub(/(\d+)?[dD](\d+)/){n=$1?$1.to_i: 1;n.times{n+=rand $2.to_i};n}
              end
              

              代码的可读版本:

              def f s
                  eval (s.gsub /(\d+)?[dD](\d+)/ do
                      n = $1 ? $1.to_i : 1
                      n.times { n += rand $2.to_i }
                      n
                  end)
              end
              

              【讨论】:

              • 关于不使用 .nil 的好处是什么?但是双 eval 版本更短;)
              • 可以通过将正则表达式更改为 /(\d+)?d(\d+)/i 来缩短另外 2 个字符
              【解决方案13】:

              JAVASCRIPT,1399 个字符,无评估

              旧帖子,我知道。但我会努力做出贡献

              Roll = window.Roll || {};
              
              Roll.range = function (str) {
                  var rng_min, rng_max, str_split,
                      delta, value;
              
                  str = str.replace(/\s+/g, "");
                  str_split = str.split("-");
                  rng_min = str_split[0];
                  rng_max = str_split[1];
              
                  rng_min = parseInt(rng_min) || 0;
                  rng_max = Math.max(parseInt(rng_max), rng_min) || rng_min;
              
                  delta = (rng_max - rng_min + 1);
              
                  value = Math.random() * delta;
                  value = parseInt(value);
              
                  return value + rng_min;
              };
              
              Roll.rollStr = function (str) {
                  var check,
                      qta, max, dice, mod_opts, mod,
                      rng_min, rng_max,
                      rolls = [], value = 0;
              
                  str = str.replace(/\s+/g, "");
                  check = str.match(/(?:^[-+]?(\d+)?(?:\/(\d+))?[dD](\d+)(?:([-+])(\d+)\b)?$|^(\d+)\-(\d+)$)/);
              
                  if (check == null) {return "ERROR"}
                  qta = check[1];
                  max = check[2];
                  dice = check[3];
                  mod_opts = check[4];
                  mod = check[5];
                  rng_min = check[6];
                  rng_max = check[7];
                  check = check[0];
              
                  if (rng_min && rng_max) {return Roll.range(str)}
              
                  dice = parseInt(dice);
                  mod_opts = mod_opts || "";
                  mod = parseInt(mod) || 0;
                  qta = parseInt(qta) || 1;
                  max = Math.max(parseInt(max), qta) || qta;
              
                  for (var val; max--;) {
                      val = Math.random() * dice;
                      val = Math.floor(val) + 1;
                      rolls.push(val);
                  }
              
                  if (max != qta) {
                      rolls.sort(function (a, b) {return a < b});
                      rolls.unshift(rolls.splice(0, qta));
                  }
              
                  while (rolls[0][0]) {value += rolls[0].shift();}
              
                  if (mod_opts == "-") {value -= mod;}
                  else {value += mod;}
              
                  return value
              };
              
              if (!window.diceRoll) {window.diceRoll= Roll.rollStr;}
              

              这是一个单掷骰子,例如“2d8+2”或“4-18”“3/4d6”(最好 3 of 4 d6)

              diceRoll("2d8+2"); 
              diceRoll("4-18");
              diceRoll("3/4d6");
              

              为了检查累积滚动,更好地循环输入字符串上的匹配结果,例如

              r = "2d8+2+3/4d6"
              r.match(/([-+])?(\d+)?(?:\/(\d+))?[dD](\d+)(?:([-+])(\d+)\b)?/g);
              // => ["2d8+2", "+3/4d6"]
              // a program can manage the "+" or "-" on the second one (usually is always an addiction)
              

              【讨论】:

                【解决方案14】:

                PHP,147 个符号,无 eval:

                preg_match('/(\d+)?d(\d+)[\s+]?([\+\*])?[\s+]?(\d+)?/',$i,$a);$d=rand(1,$a[2])*((!$a[1])?1:$a[1]);$e['+']=$d+$a[4];$e['*']=$d*$a[4];print$e[$a[3]];
                

                $i 包含输入字符串。

                编辑:哎呀,忘记了前缀操作。 brb。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2020-04-20
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2014-01-28
                  相关资源
                  最近更新 更多