[Question]
  [
I want to play Dungeons and Dragons, but I don't have any dice! Your challenge is to roll some D&D dice.
The input format specification in [Backus-Naur form](http://en.wikipedia.org/wiki/Backus%E2%80%93Naur_Form) is:
```
<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>
```
The optional integer before the `d` is the number of dice to roll; it must be at least `1`, and defaults to `1` if not supplied.
The required integer immediately after the `d` is the number of sides each die has; it must be at least `1`. The sides of each die are distinct consecutive positive integers starting at `1`.
The optional modifier may be `+0`, and it defaults to `+0` if not specified.
For example, for the input `2d10+5`, you generate two random numbers from 1 to 10 inclusive, add them together, and add 5. Then you will output the result.
If you receive invalid input, such as `2d`, `d20+`, `0d4`, `2d5+1+2`, `2+2`, or anything else that doesn't fit this format, you must output "`Invalid input`". Otherwise, you must output only a single random integer, weighted according to the input. For example, [`3d6` should produce more `10`s than `4`s](http://anydice.com/program/1/).
### Test cases
```
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
```
This is [code-golf](/questions/tagged/code-golf "show questions tagged 'code-golf'"), so the shortest code in bytes will win!
  
[Answer]
# Perl, ~~109~~ ~~95~~ ~~93~~ ~~96~~ 89 bytes
```
s/^d/1d/;/^(\d+)d(\d+)(\+\d+)?$/;$d+=1+rand$2|0for
1..$1;$_=$1*$2?$d+$3:'Invalid input'
```
Requires the `-p` switch, which accounts for two of the bytes. Try it online on [Ideone](http://ideone.com/gLJfhO).
### How it works
* Because of the `-p` switch, a line is read from STDIN and stored in `$_`.
* The command `s/^d/1d/` prepends a *1* to `$_` if it begins with a *d*, i. e., if the number of dice has not been specified.
* The regular expression `/^(\d+)d(\d+)(\+\d+)?/` checks if the line consists of a number, a literal *d*, another number and, optionally, a third number preceded by a *+* sign.
If there is a match, the numbers will be saved in `$1`, `$2` and `$3`.
In this case, the input will be valid if and only if `$1` and `$2` are both positive.
* `$d += 1 + rand $2 | 0` adds a pseudo-randomly chosen integer from 1 to the specified number of sides to `$d` (initially treated as zero).
* `for 1 .. $1` does the above once for every integer between 1 and the number of dice.
* The command `$_ = $1 * $2 ? $d + $3 : 'Invalid input'` does the following:
	+ If `$1 * $2` is zero, it sets `$_` to *Invalid input*.
	+ Otherwise, the input is valid and it sets `$_` to the sum of the dice rolls and the modifier.
* Because of the `-p` switch, Perl prints the contents of `$_`.
* Since there a no further input lines, the script exits.
[Answer]
# 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;
```
Abuses implicit typing (`i-n` are all integers, everything else a real). Minor caveat: input must be space separated, so `2d10+5` must be entered as `2 d 10 + 5`, otherwise you'll get an `input conversion error`.
[Answer]
## Ruby, 116
Alternative Ruby version. I was trying to find a way to do it without the regular expressions, but the validation you have to do is a lot harder without them.
```
gets=~/^(\d+)?d(\d+)(\+\d+)?$/
a=$1||?1
puts$~&&a>?0?eval("r=#{$3||0};#{a}.times{r+=rand(#$2)+1};r"):'Invalid input'
```
This one is 112, using Dennis' clever Perl algorithm:
```
$p='(\d*[1-9]\d*)'
puts~/^#$p?d#$p(\+\d+)?$/?eval("r=#{$3||0};#{$1||1}.times{r+=rand(#$2)+1};r"):'Invalid input'
```
[Answer]
## GolfScript (120 106 bytes)
```
.100?!1`*\+.43?)!'+0'*+.10,'d+':^*-!*.10,''*-^=*^1/{/n*}/~].,3=*3,or:x~;*{x~\{rand)+}+@*}'Invalid input'if
```
This is not only shorter than the first version, but also more elegant. The part which actually does the die rolling is
```
\{rand)+}+@*
```
The rest is mainly input validation, and a few characters for parsing.
```
# 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
```
[Online demo with test framework](http://golfscript.apphb.com/?c=IyMKOydkMQpkNgpkMSszCmQyMCszCjJkMQoyZDYrMgpkMDEKZDAxKzAKMDFkMDErMDEKM2QyMCsxMApkCmQwCmQrMApkMCswCjBkMQowZDErMQpkMSsKMWQKMWQxKwoxZCsxCjJkKzJkCmQyK2QyCmQyKzIrMgpkMi0xCi1kMgotMmQyCjQqMwo0KmQyCiduL3sKLnAKIyMKCi4xMDA%2FITFgKlwrLjQzPykhJyswJyorLjEwLCdkKyc6XiotISouMTAsJycqLV49Kl4xL3svbip9L35dLiwzPSozLG9yOnh%2BOyp7eH5ce3JhbmQpK30rQCp9J0ludmFsaWQgaW5wdXQnaWYKCiMjCnByaW50IG4gcHJpbnR9LwojIwo%3D)
[Answer]
# Java, 378
Just wanted to try a solution with Java far from the best solution. But hey: Java isn't a golfing language in any case!
It gets the input from command line. First parameter `args[0]` is the input value.
```
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;}}
```
Did you know, that `decode` is shorter than `valueOf`?
[Answer]
# J - 130 (45?) char
This challenge seems to be a little biased towards regular expressions, especially with having to differentiate invalid input. J has a POSIX regex library, so it's not that bad, but it's not integrated as it is with Perl, so J fares no better than other languages.
```
+/@,`(1+?@#~)/`('Invalid input'"_)@.(0 e.$)0 1 1>.".>|.}.((,'?d','(\+[0-9]+)?$',~}.)'^([0-9]*[1-9][0-9]*)')(rxmatch rxfrom])1!:1]1
```
If you're just implementing the logic for valid expressions, like the Python/PHP solutions appear to, it's the more reasonable 45 chars:
```
+/,(1+[:?@#/1>.".;._2@,&'d')`".;._1'+',1!:1]1
```
Notable bits:
* `1!:1]1` is the input, and `(rxmatch rxfrom])` is the logic that returns the subexpression matches.
* Whether or not the input was legal is handled by the regex matching, so we can set the defaults for n and p with `0 1 1>.`. It looks backwards (n is 1 by default and p is 0) because we had to reverse (`|.`) the list earlier, so that the logic at the end executes in the right order.
* `@.` is the *Agenda* conjunction, essentially a J-ish switch statement. If the matches are empty (if 0 is an e.lement of the $hape: `0 e.$`), we emit the error message, else we go through with rolling the dice: `#~` to set out the dice, `1+?` to roll, and `+/@,` to add the modifier p and sum.
[Answer]
## [TinyMUSH](http://www.tinymush.net/index.php/Main_Page), 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)
```
The first four lines deal with the fact that "d" is an alias for the universal "down" exit with a built-in failure message when it doesn't exist; exits are scanned before user-defined commands. The remaining lines create an object with a user-defined command making use of the built-in die() function.
[Answer]
# PHP, 129
```
<?eval(preg_filter(~Ð¡×£›ÔÖÀ›×£›Ö×£Ô£›ÔÖÀÛÐ,~ÛžÂÝÛÎÝÀÅÎÄ™×ÄÛ–ÔÔÃÛžÄÛŒÔÂž‘›×ÎÓÛÍÖÖÄšœ—ÛŒÛÌÄ,$_GET[0])?:~šœ—Ý¶‘‰ž“–›ß–‘Š‹ÝÄ);
```
Uses a regex to create a expression which PHP then evaluates.
Input is fed in via url: ?0=*argument*. Make sure you urlencode the + to %2b.
Here's what it looks like in a more readable form:
```
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";');
```
Bitwise inverting the strings using `~` not only saves a character because you don't need quotes (PHP assumes they are strings) but also saves characters because you don't have to escape the backslashes in the regular expression.
The `?:` operator is a special form of the ternary operator. `$foo = $a ? $a : $b` is the same as `$foo = $a ?: $b`.
[Answer]
# Ruby, ~~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
```
Uses a regexp to do all the work. Since I'm using `\d+`, the only things I need to check for invalid input are that there was a match, that neither `n` nor `m` were `0`, 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.
The result-printing isn't that interesting, but...
```
([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)
```
I later changed `.inject(:+)` to `eval(...*?+)`, but the idea is the same.
[Answer]
# Python 3, 184 bytes
```
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)
```
Passes all tests. If zero dice were allowed, it would be 6 bytes shorter by leaving out `(or q)`.
[Answer]
# [Vyxal](https://github.com/Vyxal/Vyxal) `V`, 89 bytes
```
h\d=[1p|]⁽±Ḋ→a⟨←aL5=|←a⌊±T⟨0|2|4⟩=|←a1i\d=|←a3i\+=⟩A[←a0i⌊ʁ(←a2i⌊℅⅛)¾∑←a4i⌊+,|«¢q⁰∷Ṗ-←¥«,
```
[Try it Online!](https://vyxal.pythonanywhere.com/#WyJQViIsIiIsImhcXGQ9WzFwfF3igb3CseG4iuKGkmHin6jihpBhTDU9fOKGkGHijIrCsVTin6gwfDJ8NOKfqT184oaQYTFpXFxkPXzihpBhM2lcXCs94p+pQVvihpBhMGnijIrKgSjihpBhMmnijIrihIXihZspwr7iiJHihpBhNGnijIorLHzCq8KiceKBsOKIt+G5li3ihpDCpcKrLCIsIiIsIjJkNSsxMiJd)
Ties Perl
```
h\d=[1p|]         # Checks if the first character is a d, and prepends a 1 
        ⁽±Ḋ→a     # Splits the string on non-numeric values, so consecutive digits stay grouped, then casts the list to variable "a"
     ⟨←aL5=|           # is it Length 5 (3 numbers, the "+" and the "d")
       ←a⌊±T⟨0|2|4⟩=|  # convert the numbers-as-strings to numbers and check if the numbers are in positions 1 3 and 5 (0 indexed)
         ←a1i\d=|     # is the second item in the list  "d"
           ←a3i\+=⟩    # is the fourth item "+"
                A     # are all of these checks true?
  [←a0i⌊ʁ               # If all the checks are true, create a range from 0-a[0]
        (←a2i⌊℅⅛)       #  for i in said range, generate a random number 0-a[2] and push to global array
             ¾∑←a4i⌊+,  # push global array, sum the values, and add a[4] 
            |«¢q⁰∷Ṗ-←¥«, # If any of the checks are false, print "invalid input"
```
```
[Answer]
# Zsh, 205 ~~223~~ bytes
```
set -e;e=Invalid\ input;trap '<<<$e' ERR
echo "^0d\n+$\nd+\n+d\n+.+\n[-|*]">p;[[ `grep -cfp<<<$1`>0 ]]&&<<<$e&&exit
q=(${(s: :)${1//(#s)d/1d}//[^0-9]/ });for i ({1..$q[1]})((s+=RANDOM%q[2]+1))
<<<$[s+q[3]]
```
[Try it Online](https://tio.run/##TY9fa8IwFMXf8yku2tnGUJukQ5i1wmB72MM28DVGdCbVgvSP7caY87O7JplzCdzz495zbshXszs3ui2rFvRnqwul1XZfviGUBThATUpRX292JfQ81jNGCHWi06fiY73P1QLyonpvk/awrsCfTqee9uFxPkcusqRqURBvUSjSqeFRByL8HsrerEqEgNX2oCsIN1llwmw1oyDlYGA3DQb6M29RnQbeMWgmMMHekUVR0G@wipg6RZFY0vBORnDCSVYeIIfgyEYjrxZMnnAQNCSd3788vD7f1IJLwjBGZrFoSC1iKc8YZaCYKWNLJDbCqVU2tl1uDVyNCTdDylwltFPKLDHoODY5Ru3HjcXaTLFORV3ALusqYWCOe/WXmPqDf72rkyvClctwojhcsLsXDpmj0I4dcscd@rfD2L@y4v75Bw) (with all test cases)
Writing the validation code was a chore. Without this guff, the solution would be a [svelte 89 bytes](https://tio.run/##JYuxCsIwFEX3fEVoIyQEm7wUCpZ2EFxVcA1x0KRWEGtNB7H022Mbl3sO97379W3wbuheA3afwT2ts7dHd0GooYwiX0uUumvb4YRAEvqakpH6EpeMjCAETT2zAuwkhD7L9cYIPDHUdG98x3SELCO9BjMxSj2vT9vD7rhf9VoZDoyhqqqI9rzXuTFhXmELSxTReL5AyUgoYqvig7IFV8tRwj@5nCkhGuDZ82UHMvwA):
```
q=(${(s: :)${1//(#s)d/1d}//[^0-9]/ });for i ({1..$q[1]})((s+=RANDOM%q[2]+1))
<<<$[s+q[3]]
```
[Answer]
# 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+)?`
[Answer]
# [Go](https://go.dev), unseeded, 366 bytes
```
import(."regexp";."strconv";."math/rand")
func f(s string)int{k:=MustCompile(`^(\d*)d(\d+)(\+\d+)?$`).FindAllStringSubmatch(s,-1)
if len(k)<1||k[0][2]==""{return-1}
r:=k[0]
var n,l,f,m,t int
l=len(r)
n,_=Atoi(r[1])
if n<1&&r[1]==""{n=1}else if n<1{return-1}
if l>2{f,_=Atoi(r[2])}
if f<1{return-1}
if l>3{m,_=Atoi(r[3])}
for i:=0;i<n;i++{t+=Intn(f)+1}
t+=m
return t}
```
[Attempt This Online!](https://ato.pxeger.com/run?1=bVLdatswFGa3egohRidVdmbJo4wk3iiDwS42CmFXqdd6kZyK2HKQ5bTg5kl2Ewp7qO1ppp_-jK0339H50Xc-naMfd-vu8OvVtlptqrWEbaU0UO22M3aC6taiR8eqVqKfg63Tt79f6BjFE2TkWt5s0WyCemtWnd75Y1vZq9em0gIRUA96BWvcQ5dXek2UtuNmWnweevuha7eqkfjyGz4Xx0Q4pASfU2_ev7wkk49Ki9OmWYSbi-G7411d4T5JGQGqho3UeEPm7PZ2s8zKJS-LAqHRSDsYnbI9MNPCJ8CuMlAnTVInbWKhEwCawt81BOjkoji1ncJmycpAqufs6Mh7gUwXbC-bXsKY-Yvc93_Hx_qJgJckhOv_6_KxfarLfV3dGaimRTZTcz1TlI6WFp-01bgm1N1yXgsiCbT7h7G3YZh-R5jAESykFPhLd43J5KtWN5gQ4Ibcw2kBl2Uc94gEQwkSJx4Yzb3hWbA8ZLg4odxHMxaRZs5mLJx8KPf1LENR8kUS6N1u3WcJzUZw5hrZRru9-D07EfvHkJuo3lWNEv9oCq08hG4ii02DIIeURbUOmQhwf6ZRMeWBgFPBo-XxCTz1-TREUx7Mm-M8oHOeecCDuGffcD_1wyHaPw)
# [Go](https://go.dev), seeded, 393 bytes
```
import(."regexp";."strconv";."math/rand";."time")
func f(s string)int{k:=MustCompile(`^(\d*)d(\d+)(\+\d+)?$`).FindAllStringSubmatch(s,-1)
if len(k)<1||k[0][2]==""{return-1}
r:=k[0]
var n,l,f,m,t int
l=len(r)
n,_=Atoi(r[1])
if n<1&&r[1]==""{n=1}else if n<1{return-1}
if l>2{f,_=Atoi(r[2])}
if f<1{return-1}
if l>3{m,_=Atoi(r[3])}
Seed(Now().Unix())
for i:=0;i<n;i++{t+=Intn(f)+1}
t+=m
return t}
```
[Attempt This Online!](https://ato.pxeger.com/run?1=bVJbbtQwFBW_WYVlocqukxA7qEIzE1CFhMQHCGnED9PQhrEztSZxRo4zrZRmAayhP6NKLIKtsBr8aCmC_pzj-8i5r9zebbrDz1213lYbAdpKqki2u06bFNatgT8GUyevfj37HpwohVpsxPUOzlPYG73u1N4928pcvtCV4s4wshUQR_Wg1qBGPbB5Um2wVGbczooPQ2_edu1ONgJdfEVn_BhziwSjM-LozfMLnL6Tip82zdJ_uRy-Wf31JerjhOJI1qARCm3xgt7cbFdZuWJlUUA4amEGrRI6RXpWuEC0rzRQcRPXcRsbYBuImsJ9q3Gk4vPi1HQS6RUtvaha0KMjZ3kxVdBJNL0AIfKXuKv_mo31owArsXfX_-flY_uYl7u8pRAcfeyuEE4_K3mNsN1Up4GcFdlcLtRcEjIaUrxXRqEaEytkrTYKusBMDxf54vfrDoYwGCO75B7MCrAqw7pHyCmMIT9xQEnuiGWemY8wfkKY82Y0IMksZ9S_nCt3-TSDk-_vPPby9sb2N_HFxuiTLWQaZe_i7mwHmf647EbVvmok_6cnX8qBr8azUNQ3ZJHQ0K1Fyj3cv0nomDAvwAhngVkYgSUunnhvwjy9PM49WuOJAR6ae3KG-xUfDoF_Aw)
]