评估骰子滚动符号字符串

sam*_*uil 21 language-agnostic expression-evaluation dice

规则

编写一个接受字符串作为参数的函数,以骰子表示法返回表达式的计算值,包括加法和乘法.

为了清楚起来,EBNF对法律表达的定义如下:

roll ::= [positive integer], "d", positive integer
entity ::= roll | positive number
expression ::= entity { [, whitespace], "+"|"*"[, whitespace], entity }
Run Code Online (Sandbox Code Playgroud)

示例输入:

  • "3d6 + 12"
  • "4*d12 + 3"
  • "D100"

不禁止使用eval函数或类似函数,但我鼓励在不使用这些函数的情况下求解.欢迎重新入门.

我无法提供测试用例,因为输出应该是随机的;).

格式化答案的标题:语言,n个字符(重要说明 - 没有评估等)


我的红宝石溶液,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
Run Code Online (Sandbox Code Playgroud)

另一种红宝石的解决方案,而不是更短(92个字符),但我觉得很有意思-它仍然使用eval但这次颇有创意的方式.

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

Gal*_*boy 13

C#类.它递归地评估链式模具辊的从左到右的加法和乘法

编辑:

  • .Replace(" ","")每次通话都删除了
  • 增加了.Trim()int.TryParse替代
  • 所有工作现在都以单一方法完成
  • 如果没有指定模具面数,则假设为6(参见维基文章)
  • 重构冗余调用以解析"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;}}
Run Code Online (Sandbox Code Playgroud)

扩展形式:

    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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

测试用例:

    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));
    }
Run Code Online (Sandbox Code Playgroud)

  • +1它的可读性(与顶部的红宝石解决方案不同) (3认同)
  • @Hardwareguy,代码高尔夫的目的根本不是可读性. (3认同)

eph*_*ent 5

Ĵ

在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


ins*_* me 4

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) );
}
Run Code Online (Sandbox Code Playgroud)

测试代码:

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

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

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));}
Run Code Online (Sandbox Code Playgroud)