滚龙与地下城骰子


20

我想玩龙与地下城,但我没有任何骰子!您的挑战是掷出一些D&D骰子。

Backus-Naur格式的输入格式规范为:

<valid-input>  ::= <opt-integer> "d" <integer> <opt-modifier>
<opt-integer>  ::= | <integer>
<opt-modifier> ::= | "+" <integer>
<integer>      ::= "0" | "1" | "2" | "3" | "4" | "5" |
                   "6" | "7" | "8" | "9" | <integer> <integer>

之前的可选整数 d是掷骰子的数量;它必须至少为11如果未提供,则默认为。

紧随其后的必需整数 d是每个芯片的边数;至少应该是1。每个骰子的边都是从开始的不同的连续正整数1

可选修饰符可以是 +0+0如果未指定,则默认为。

例如,对于input 2d10+5,您生成两个从1到10(含1和10)之间的随机数,将它们加在一起,然后加5。然后将输出结果。

如果您收到无效的输入,如2dd20+0d42d5+1+22+2,或其他任何东西,不适合这种格式,你必须输出“ Invalid input”。否则,您必须仅输出根据输入加权的单个随机整数。例如,3d6应产生更多10s4

测试用例

Input      Minimum possible output    Maximum possible output
d1         1                          1
d6         1                          6
d1+3       4                          4
d20+3      4                          23
2d1        2                          2
2d6+2      4                          14
d01        1                          1
d01+0      1                          1
01d01+01   2                          2
3d20+10    13                         70

d          Invalid input
d0         Invalid input
d+0        Invalid input
d0+0       Invalid input
0d1        Invalid input
0d1+1      Invalid input
d1+        Invalid input
1d         Invalid input
1d1+       Invalid input
1d+1       Invalid input
2d+2d      Invalid input
d2+d2      Invalid input
d2+2+2     Invalid input
d2-1       Invalid input
-d2        Invalid input
-2d2       Invalid input
4*3        Invalid input
4*d2       Invalid input

这是,所以最短的代码(以字节为单位)将获胜!


1
02d05+073一个有效的输入?
MT0

2
关于这个问题的困难部分是验证输入,但是描述验证规则的段落是自相矛盾的。它描述np为可选内容,但选择不将其包括在内的输入(d20+)为无效。
彼得·泰勒

1
@PeterTaylor:我认为+只有在p提供修饰符的情况下,才应添加符号。
ProgramFOX 2014年

4
@Doorknob,好吧,因为d13和d17不是D&D中使用的骰子。D&D使用d4,d6,d8,d10,d12和d20。同样,当然,在某些情况下,掷骰子会包含不同类型的骰子(例如,1d4+1d6用匕首偷袭的潜行者)或否定的p(例如,1d20-1没有等级/训练的技能检查和否定的能力修正)。
布莱恩S

2
您将在没有用例的情况下玩dnd 2d8 + 1d6 + 4。您将会
度过

Answers:


12

Perl,109 95 93 96 89字节

s/^d/1d/;/^(\d+)d(\d+)(\+\d+)?$/;$d+=1+rand$2|0for
1..$1;$_=$1*$2?$d+$3:'Invalid input'

需要-p开关,该开关占两个字节。在线尝试 Ideone上

怎么运行的

  • 由于-p开关的原因,从STDIN读取一行并将其存储在$_

  • 命令s/^d/1d/预先考虑一个1$_,如果它开始于d,即,如果没有指定骰子的数量。

  • 正则表达式/^(\d+)d(\d+)(\+\d+)?/检查该行是否包含数字,文字d,另一个数字以及(可选)由第三个数字开头的数字 +

    如果有匹配项,数字将保存在中$1$2并且$3

    在这种情况下,仅当$1且仅当和$2均为正时。

  • $d += 1 + rand $2 | 0 将一个从1到指定边数的伪随机选择整数加到 $d(最初视为零)。

  • for 1 .. $1 对1和骰子数之间的每个整数执行一次以上操作。

  • 该命令$_ = $1 * $2 ? $d + $3 : 'Invalid input'执行以下操作:

    • 如果$1 * $2为零,则设置$_无效输入

    • 否则,输入有效,并将其设置$_为掷骰和修饰符的总和。

  • 由于-p切换,Perl会打印以下内容$_

  • 由于没有其他输入行,因此脚本退出。


1
我相信,一般来说,额外的命令行参数被认为每个值值得一个字节,但是连字符是免费的。在这种情况下,-p只需花费您一个,就可以解决这个108字节的问题。
undergroundmonorail

2
可以做成96个字符,/^([1-9]\d*)?d([1-9]\d*)(\+\d+)?$/||die"Invalid input$/";$a+=1+int rand$2for(1..$1||1);$_=$a+$3
Hasturkun 2014年

1
@undergroundmonorail:我见过人们将单个命令行开关计数为一个,两个甚至三个(计算空格)字节。我宁愿将其视为一个,但是两个字节对我来说似乎很公平。
丹尼斯

1
@Vynce我以为你也没有。我使用|0强制转换为int,因为rand返回的是伪随机选择的float
丹尼斯

1
@Vynce我已在问题(ideone.com/gLJfhO)中添加了永久链接。-e除非您将单引号替换为双引号,否则在这里会出现问题。
丹尼斯

4

Fortran:145

character(1)a;read(*,*)s,a,j,a,k;n=0;if(k<0.or.a=="-")then;print*,"error k<0";stop;endif;do l=1,int(s);n=n+int(s*rand(0)+1);enddo;print*,n+k;end;

滥用隐式类型(i-n都是整数,其他都是实数)。次要注意事项:输入必须以空格分隔,因此2d10+5必须输入为2 d 10 + 5,否则您将获得input conversion error


4

红宝石,116

备用Ruby版本。我试图找到一种不用正则表达式的方法,但是如果没有正则表达式,您要做的验证会困难得多。

gets=~/^(\d+)?d(\d+)(\+\d+)?$/
a=$1||?1
puts$~&&a>?0?eval("r=#{$3||0};#{a}.times{r+=rand(#$2)+1};r"):'Invalid input'

这是112,使用Dennis的聪明的Perl算法:

$p='(\d*[1-9]\d*)'
puts~/^#$p?d#$p(\+\d+)?$/?eval("r=#{$3||0};#{$1||1}.times{r+=rand(#$2)+1};r"):'Invalid input'

@ m.buettner谢谢!我不知道为什么我认为必须> 0。
Paul Prestidge 2014年

3

Javascipt,158

m=prompt().match(/^([1-9]\d*)?d([1-9]\d*)(\+\d+)?$/);if(!m)alert("Invalid input");else{for(s=+m[3]|0,i=0;i<(+m[1]||1);i++)s+=Math.random()*+m[2]+1|0;alert(s)}

高尔夫比这更好。现在该恢复工作了。


1
s="Invalid input";if(m=prompt().match(/^([1-9]\d*)?d([1-9]\d*)(\+\d+)?$/))for(s=m[3]|0,i=0;i<(m[1]||1);i++)s+=Math.random()*m[2]+1|0;alert(s)只有137个字节。
丹尼斯

2
根据对该问题的评论,这是不正确的答案,因为它拒绝输入02d05+073
彼得·泰勒

3

GolfScript(120 106个字节)

.100?!1`*\+.43?)!'+0'*+.10,'d+':^*-!*.10,''*-^=*^1/{/n*}/~].,3=*3,or:x~;*{x~\{rand)+}+@*}'Invalid input'if

这不仅比第一个版本短,而且更优雅。实际进行压延的部分是

\{rand)+}+@*

其余的主要是输入验证,以及一些用于解析的字符。

# Start by converting valid inputs into valid inputs with all optional bits.
# Prepend a '1' if the string starts with 'd'.
.100?!1`*\+
# Append '+0' if there's no '+' in the string.
.43?)!'+0'*+
# Now we start knocking out the invalid inputs.
# If it contains a character other than [0-9d+], replace the string with ''.
.10,'d+':^*-!*
# If it doesn't contain exactly one 'd', exactly one '+', and the 'd' before the '+',
# replace the string with ''.
.10,''*-^=*
# Now we either have a valid string, an empty string, or a string which is almost valid
# but has some empty substrings which should be integers, or a forbidden 0 integer value.
# Replace the 'd' and '+' with newlines, eval the result, and gather into an array.
^1/{/n*}/~]
# If we had any empty parts, we'll have fewer than 3 items on the stack.
# In that case, replace with integer values which will fail the final validation step.
.,3=*3,or
# Final validation: number of dice * number of sides per die != 0.
:x~;*
# If we pass, do the actual die rolling. Otherwise give the error message.
{x~\{rand)+}+@*}'Invalid input'if

带有测试框架的在线演示


我想知道你为什么不使用n./?也许也10,n*少了一个字符。
霍华德

@Howard,首先,因为这是通过一些测试用例的最后一刻,我并没有考虑打高尔夫球。第二,这将使其接受一些无效的输入。
彼得·泰勒

2

J-130(45?)char

这项挑战似乎偏向于正则表达式,尤其是在必须区分无效输入的情况下。J有一个POSIX正则表达式库,因此它还不错,但是没有像Perl那样集成,因此J的性能并不比其他语言更好。

+/@,`(1+?@#~)/`('Invalid input'"_)@.(0 e.$)0 1 1>.".>|.}.((,'?d','(\+[0-9]+)?$',~}.)'^([0-9]*[1-9][0-9]*)')(rxmatch rxfrom])1!:1]1

如果您只是为有效的表达式实现逻辑(如Python / PHP解决方案看上去的那样),则是更合理的45个字符:

+/,(1+[:?@#/1>.".;._2@,&'d')`".;._1'+',1!:1]1

值得注意的位:

  • 1!:1]1是输入,(rxmatch rxfrom])是返回子表达式匹配项的逻辑。

  • 输入是否合法由正则表达式匹配处理,因此我们可以使用设置n和p的默认值0 1 1>.。它向后看(默认情况下n为1,p为0),因为我们不得不|.更早地反转()列表,以便最后的逻辑以正确的顺序执行。

  • @.议程连词,本质上是J ish switch语句。如果匹配为空(如果0是$ hape:的元素0 e.$),则发出错误消息,否则我们滚动骰子:#~设置骰子,1+?滚动并+/@,添加修饰符p和。


这样有用01d01+01吗?
Cees Timmerman 2014年

@CeesTimmerman我不好。现在可以了。
algorithmhark

2

TinyMUSH,239

@dig/t +
@op d=+
@lo d=d
@fail d=Invalid input
@cr .
@set .=com
&d .=$*:\ifelse(regmatch(%0,^(\\\\d+)?d(\\\\d+)(\\\\+\\\\d+)?$,0 1 2 3),ifzero(and(or(not(strlen(%q1)),%q1),%q2),Invalid input,add(die(usetrue(%q1,1),%q2),%q3)),Invalid input)

前四行处理的事实是,“ d”是通用“ down”出口的别名,当出口不存在时,它会带有内置的故障消息。在用户定义的命令之前先扫描出口。其余各行使用内置的die()函数,通过用户定义的命令创建对象。


2

PHP 129

<?eval(preg_filter(~Сף›ÔÖÀ›×£›Ö×£Ô£›ÔÖÀÛÐ,~ÛžÂÝÛÎÝÀÅÎÄ™×ÄÛ–ÔÔÃÛžÄیԞ‘›×ÎÓÛÍÖÖÄšœ—ÛŒÛÌÄ,$_GET[0])?:~šœ—ݶ‘‰ž“–›ß–‘Š‹ÝÄ);

使用正则表达式创建一个表达式,然后PHP对其求值。输入通过url输入:?0 = 参数。请确保将+编码为%2b。这是更具可读性的形式:

eval(preg_filter('/^(\\d)?d(\\d)(\\+\\d)?$/','$a="$1"?:1;for(;$i++<$a;$s+=rand(1,$2));echo$s$3;',$_GET[0])?:'echo"Invalid input";');

使用逐位反转字符串~不仅可以节省字符,因为您不需要引号(PHP假定它们是字符串),而且可以节省字符,因为您不必在正则表达式中转义反斜杠。

?:运算符是三元运算符的一种特殊形式。$foo = $a ? $a : $b与相同$foo = $a ?: $b


1

爪哇,378

只是想尝试使用Java解决方案而不是最佳解决方案。但是,嘿:无论如何,Java都不是一种高尔夫语言!

它从命令行获取输入。第一个参数args[0]是输入值。

class A{public static void main(String[]s){System.out.print(s[0].matches(
"(0+\\d+|[1-9]\\d*|)d(0+\\d+|[1-9]\\d*)(\\+\\d+)?")?z(s[0]):"Invalid input");}static int
z(String s){String[]a=s.split("d");String[]b=a[1].split("\\+");int c=a[0].isEmpty()?1:Byte.
decode(a[0]);int d=b.length<2?0:Byte.decode(b[1]);while(c-->0)d+=new java.util.Random().
nextInt(Byte.decode(b[0]))+1;return d;}}

你知道吗,decode比那还短valueOf


1

Python 3,184个字节

import random,re
try:a,b,c=re.findall("^(\d*)d(\d+)(\+\d+)?$",input())[0];t=int(c or 0)+(sum(random.randint(1,int(b))for i in range(int(a or 1)))or q)
except:t="Invalid input"
print(t)

通过所有测试。如果允许使用零个骰子,则通过省略将减少6个字节(or q)


我误解了BNF。此页面有帮助。
Cees Timmerman 2014年

为了其他人的利益,他们想知道为什么将正则表达式锚定在一端而不是另一端:Python re.match隐式地锚定在开始而不是末尾。我不知道这样做的任何其他正则表达式库。
彼得·泰勒

1
通过初始化可以节省一点钱t=int(c or 0);并且可以将您的答案与现有的Python答案(使用较少的空白)结合起来以节省更多。
彼得·泰勒

0

的JavaScript 134

m=prompt().match(/^((?!0)\d*)d((?!0)\d+)(\+\d+)?$/);alert(m?eval('for(o=m[3]|0,i=m[1]||1;i--;)o+=m[2]*Math.random()+1|0'):'Invalid input')


嗯,有很多相似之处,这是相同的语言/算法...但是我认为我的代码(和正则表达式)有足够的差异,可以发布不同的答案。
Michael M.

根据对该问题的评论,这是不正确的答案,因为它拒绝输入02d05+073
彼得·泰勒

0

红宝石, 167 147

/^(\d+)?d(\d+)(\+\d+)?$/.match gets
abort'Invalid input'if !$~||$1==?0||!$2||$2==?0
p eval(([0]*($1||1).to_i).map{rand($2.to_i)+1}*?+)+($3||0).to_i

使用正则表达式完成所有工作。由于我使用的\d+,我只需要检查输入无效的事情,有一个比赛,既不n也不m0, and that there was an m. If any of those are found, it aborts with a message ('Invalid input'). Then it just prints the result, since it would have aborted by now if the input was invalid.

结果打印并不有趣,但是...

([0]*($1||1).to_i)    # create an array of n elements (1 if there is no n)
.map{rand($2.to_i)+1} # fill it up with random numbers, where the number x is 1 < x < m+1
.inject(:+)           # add them all up
+($3||0).to_i         # and finally add the modifier (0 if there is none)

后来我更改.inject(:+)eval(...*?+),但想法是相同的。


0

Python3, 204B

Mine beats the existing Python answer by adding in the required error handling and reading d20 as 1d20 rather than 0d20 :)

import random,re
try:a,b,c=re.findall('^([1-9]\d*)?d(\d+)(\+\d+)?$',input())[0];I=int;R=sum(random.randrange(I(b))+1for x in[0]*(1if a==''else I(a)))+(0if c==''else I(c))
except:R='Invalid input'
print(R)

edited to fix 2 typos: I(x) => I(c), Invalid Input => Invalid input

edited to fix regex: \+?(\d*) => (\+\d+)?


According to the clarified question, this is an incorrect answer because it accepts the input 3d20+.
Peter Taylor

Good point! #filler
alexander-brett

And not 01d01+01.
Cees Timmerman
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.