Roll Dungeons and Dragons dice

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.

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.


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'

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.