language-agnostic - 评估骰子滚动符号字符串

标签 language-agnostic dice expression-evaluation

规则

编写一个接受字符串作为参数的函数,返回
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​​ 解决方案,使用eval,共92 81个字符:
    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
    

    最佳答案

    C#类。它从左到右递归评估加法和乘法,适用于链式模具辊

    编辑:

  • 每次调用时删除.Replace(" ","")
  • .Trim()上添加了int.TryParse而不是
  • 现在所有工作都在单个方法
  • 中完成
  • 如果未指定模数,则假定为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));
        }
    

    关于language-agnostic - 评估骰子滚动符号字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1031466/

    相关文章:

    language-agnostic - 压缩二进制矩阵

    algorithm - 浮点除法与乘法的精度差异

    c++ - 定义 "library-safe"代码的概念

    python - 掷骰子程序的无限 while 循环问题

    java - 使 Math.Random 循环,直到达到特定数字

    Prolog:使用 is/2 为某些子表达式显示任意表达式的真值表

    c - C 中的表达式求值

    algorithm - 二叉树的排列

    r - 在数据框的上下文中评估操作