评估骰子滚动符号字符串
规则
编写一个接受字符串作为参数的函数,返回 骰子符号中表达式的计算值, 包括加法和乘法。
为了澄清问题,这里是合法表达式的 EBNF 定义:
roll ::= [positive integer], "d", positive integer
entity ::= roll | positive number
expression ::= entity { [, whitespace], "+"|"*"[, whitespace], entity }
示例输入:
- "3d6 + 12"
- "4*d12 + 3"
- "d100"
不禁止使用 eval 函数或类似函数,但我鼓励 不使用这些来解决。 欢迎重新进入。
我无法提供测试用例,因为输出应该是随机的;)。
设置答案标题的格式:语言、n 个字符(重要说明 - 无需评估等)
我的 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
Rules
Write a function that accepts string as a parameter, returning
evaluated value of expression in dice notation,
including addition and multiplication.
To clear the things up, here comes EBNF definition of legal expressions:
roll ::= [positive integer], "d", positive integer
entity ::= roll | positive number
expression ::= entity { [, whitespace], "+"|"*"[, whitespace], entity }
Example inputs:
- "3d6 + 12"
- "4*d12 + 3"
- "d100"
Using eval functions, or similar, is not forbidden, but I encourage
to solving without using these. Re-entrancy is welcome.
I cannot provide test-cases, as output should be random ;).
Format your answers' titles: language, n characters (important notes — no eval, etc.)
My ruby solution, 92 81 characters, using eval:
def f s
eval s.gsub(/(\d+)?d(\d+)/i){eval"a+=rand $2.to_i;"*a=($1||1).to_i}
end
Another ruby solution, not shorter (92 characters), but I find it interesting — it still uses eval but this time in quite creative way.
class Fixnum
def**b
eval"a+=rand b;"*a=self
end
end
def f s
eval s.gsub(/d/,'**')
end
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(14)
Python 带 eval 时为 124 个字符,不带 eval 时为 154 个字符。
只是为了表明 python 不具备可读性,这里有一个 124 个字符的解决方案,与原始方案具有类似的基于 eval 的方法:
[编辑] 这是一个没有 eval 的 154 个字符的解决方案:
注意:两者都适用于“2d6 + 1d3 + 5”等输入,但不支持更高级的变体,如“2d3d6”或负骰子(“1d6-4”可以,但“1d6-2d4”不行)(您可以删除 2 个字符,以便在第二个字符中根本不支持负数)
Python 124 chars with eval, 154 without.
Just to show python doesn't have to be readable, here's a 124 character solution, with a similar eval-based approach to the original:
[Edit] And here's a 154 character one without eval:
Note: both will work for inputs like "2d6 + 1d3 + 5" but don't support more advanced variants like "2d3d6" or negative dice ("1d6-4" is OK, but "1d6-2d4" isn't) (You can shave off 2 characters to not support negative numbers at all in the second one instead)
python,模糊版本有 197 个字符。
可读版本:369 个字符。 没有评估,直接解析。
压缩版本:258个字符,单字符名称,滥用条件表达式,逻辑表达式中的快捷方式:
模糊版本:216个字符,使用reduce,大量映射以避免“def”,“return”。
最新版本:197 个字符,折叠在 @Brain 的评论中,添加了测试运行。
测试:
该解决方案无法处理没有相邻数字的空格。 所以“43d29d16d21 * 9 + d7d9 * 91 + 2 * d24 * 7”可以工作,但“43d29d16d21 * 9 + d7d9 * 91 + 2 * d24 * 7”不会,因为第二个空格(在“ +”和“之间d”)。 可以通过首先从 s 中删除空格来纠正它,但这将使代码长度超过 200 个字符,所以我将保留该错误。
python, 197 chars in obscured version.
Readable version: 369 chars. No eval, straight forward parsing.
compressed version: 258 chars, single character names, abused conditional expressions, shortcut in logical expression:
obscured version: 216 chars, using reduce, map heavily to avoid "def", "return".
Last version: 197 chars, folded in @Brain's comments, added testing runs.
Tests:
This solution can't handle whitespaces without adjacent digits. so "43d29d16d21*9+d7d9*91+2*d24*7" will work, but "43d29d16d21*9 + d7d9*91 + 2*d24*7" will not, due to the second space (between "+" and "d"). It can be corrected by first removing whitespaces from s, but this will make the code longer than 200 chars, so I'll keep the bug.
perl,无评估,144个字符,多次工作,支持多次掷骰子
扩展版本,注释
编辑清理,更新解释到最新版本
perl, no evals, 144 chars, works multiple times, supports multiple dice rolls
Expanded version, with comments
EDIT cleaned up, updated explanation to latest version
Ruby,166 个字符,无
eval
在我看来相当优雅;)。
去混淆版本+评论:
Ruby, 166 characters, no
eval
In my opinion quite elegant ;).
Deobfuscated version + comments:
Python,压缩版本 452 字节
我不确定这是否很酷、丑陋或愚蠢,但编写它很有趣。
我们所做的如下:我们使用正则表达式(这通常不是处理此类事情的正确工具)将骰子符号字符串转换为小型基于堆栈的语言的命令列表。 该语言有四个命令:
mul
将堆栈顶部的两个数字相乘,并将结果压入add
将堆栈顶部的两个数字相加,并将结果压入roll
从堆栈中弹出骰子大小,然后进行计数,将大小面的骰子滚动计数次,并将结果压入然后计算此命令列表。
顺便说一句(这已在问题评论中讨论过),此实现将允许像
"2d3d6"
这样的字符串,将其理解为“滚动 d3 两次,然后滚动 d6 的次数与两个卷。”此外,尽管有一些错误检查,但它仍然需要有效的输入。 例如,传递“*4”将导致无限循环。
这是压缩版本(不太漂亮):
Python, 452 bytes in the compressed version
I'm not sure if this is cool, ugly, or plain stupid, but it was fun writing it.
What we do is as follows: We use regexes (which is usually not the right tool for this kind of thing) to convert the dice notation string into a list of commands in a small, stack-based language. This language has four commands:
mul
multiplies the top two numbers on the stack and pushes the resultadd
adds the top two numbers on the stack and pushes the resultroll
pops the dice size from the stack, then the count, rolls a size-sided dice count times and pushes the resultThis command list is then evaluated.
By the way (this was discussed in the question comments), this implementation will allow strings like
"2d3d6"
, understanding this as "roll a d3 twice, then roll a d6 as many times as the result of the two rolls."Also, although there is some error checking, it still expects a valid input. Passing "*4" for example will result in an infinite loop.
Here is the compressed version (not pretty):
Ruby,87 个字符,使用
eval
这是我的 Ruby 解决方案,部分基于 OP。 它短了五个字符,并且仅使用
eval
一次。代码的可读版本:
Ruby, 87 characters, uses
eval
Here's my Ruby solution, partially based on the OP's. It's five characters shorter and only uses
eval
once.A readable version of the code:
JAVASCRIPT,1399 个字符,没有评估
旧帖子,我知道。 但我尝试贡献
它是单个骰子掷骰,例如“2d8+2”或“4-18”“3/4d6”(4 d6 中的最佳 3 个)
来检查累积掷骰子,更好地循环输入字符串上的匹配结果,例如
JAVASCRIPT, 1399 chars, no eval
old post, i know. but i try to contribute
it's a single dice roll, like "2d8+2" or "4-18" "3/4d6" (best 3 of 4 d6)
to check cumulative rolls, better loop on matched result ove rthe input string like
PHP,147 个符号,无评估:
$i
包含输入字符串。编辑:哎呀,忘记了前缀操作。 brb。
PHP, 147 symbols, no eval:
$i
contains input string.Edit: oops, forgot about prefixed operation. brb.
C# 类。 它以递归方式计算加法和乘法,从左到右计算链式骰子
编辑:
.Replace(" ","")
.Trim()
onint.TryParse
if
语句缩小:(411 字节)
扩展形式:
测试用例:
C# class. It evaluates recursively for addition and multiplication, left-to-right for chained die rolls
Edits:
.Replace(" ","")
on each call.Trim()
onint.TryParse
insteadif
statementMinified: (411 bytes)
Expanded form:
Test cases:
J
在 cobbal 的帮助下,将所有内容压缩为 93 个字符。
J
With cobbal's help, squeeze everything into 93 characters.
JavaScript 解决方案,压缩后 340 个字符(无 eval,支持前缀乘法器和后缀加法):
测试代码:
压缩版本(很确定你可以做得更短):
JavaScript solution, 340 chars when compressed (no eval, supports prefixed multiplicator and suffixed addition):
Test code:
Compressed version (pretty sure you can do shorter):
Clojure,原样 854 个字符,缩小了 412 个
只需运行“(roll-dice "input-string")”即可。
为了缩小,我将变量设为 1 个字母,将(第一位)/(第二位)移至变量中,将 dice-func 设为匿名函数,为 Integer.parseInt 制作一个名为“i”的包装器,并删除注释和额外的空格。
这应该适用于任何有效的内容,无论有没有空格。 只是不要去询问它“15dROBERT”,它会抛出异常。
他们的工作方式是将字符串分成骰子(即第三行,let)。 所以“5d6+2*d4-17”变成“5d6”,“2*d4”,“-17”。
然后,每个都由函数 dice-func 处理,并将结果相加(这是最后一行的映射/归约)
Dice-func 接受一个小骰子字符串(例如“5d6”)并将其拆分为“d”。 如果只剩下一部分,则它是一个简单的数字(6、-17 等)。
如果第一部分包含 *,我们将该数字乘以一个随机整数,1 到(d 后的数字)(含)。
如果第一部分不包含*,我们将随机滚动第一个数字(就像前一行一样)并将它们相加(这是中间的映射/归约)。
这是一个有趣的小挑战。
Clojure, 854 characters as is, 412 shrunk
Just run "(roll-dice "input-string")".
To shrink, I made variables 1 letter, moved the (first bits)/(second bits) into variables, made dice-func an anonymous function, made a wrapper for Integer.parseInt called 'i', and stripped out comments and extra whitespace.
This should work on anything valid, with or without whitespace. Just don't go asking it for "15dROBERT", it will throw an exception.
They way it works is by splitting up the string into dice (that's the 3rd line, the let). So "5d6+2*d4-17" becomes "5d6","2*d4","-17".
Each of those is then processed by the function dice-func, and the results are added up (this is the map/reduce on the last line)
Dice-func takes a little dice string (such a "5d6") and splits it on the "d". If there is only one part left, it was a simple number (6, -17, etc).
If the first part contains a *, we multiply that number by a random interger, 1 to (number after d), inclusive.
If the first part doesn't contain a *, we take first number random rolls (just like previous line) and add them up (this is the map/reduce in the middle).
This was fun little challenge.
perl eval 版本,72 个字符
运行,类似于
基于 ruby 解决方案,只能运行一次(您应该在运行之间
undef $a
)。较短的版本,68 个字符,时髦(基于 0)骰子
编辑
perl 5.8.8 不喜欢以前的版本,这里有一个 73 个字符的版本,可以工作
70 个字符的版本支持多个卷
perl eval version, 72 chars
runs like
Based on the ruby solution, can only run once(you should
undef $a
between runs).shorter version, 68 chars, funky (0 based) dice
EDIT
perl 5.8.8 didn't like the previous version, here's a 73 char version that works
70 char version supporting multiple rolls
F#(无 eval 和无 正则表达式)
233 个字符
此解决方案应该是完全通用的,因为它可以处理您抛出的几乎任何字符串它,甚至是一些疯狂的事情,例如:
需要全局定义:
完全模糊版本:
可读版本:
我正在挑战某人击败这个解决方案(以任何语言)不使用< code>eval 或正则表达式。 我认为这可能是可能的,但我仍然有兴趣看到这种方法。
F# (no eval and no regex)
233 characters
This solution should be fully generic, in that it can handle just about any string you throw at it, even something crazy such as:
Need to define this globally:
Fully obfuscated version:
Readable version:
I'm challenging someone to beat this solution (in any language) without using
eval
or regular expressions. I think it's likely to be possible, but I am interested in seeing the approach still.