Бросать кости подземелий и драконов

20

Я хочу играть в Dungeons and Dragons, но у меня нет игральных костей! Ваша задача - бросить кубики D & D.

Спецификация формата ввода в форме Бэкуса-Наура :

<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: число костей для броска; это должно быть по крайней мере 1, и по умолчанию, 1если не предоставлено.

Требуемое целое число сразу же после числа d- число сторон, которое имеет каждый кубик; это должно быть по крайней мере 1. Стороны каждого кубика являются различными последовательными положительными целыми числами, начиная с 1.

Необязательный модификатор может быть +0, и он по умолчанию, +0если не указан.

Например, для ввода 2d10+5вы генерируете два случайных числа от 1 до 10 включительно, складываете их вместе и добавляете 5. Затем вы получите результат.

Если вы получаете неверный ввод, такие как 2d, d20+, 0d4, 2d5+1+2, 2+2, или что - нибудь еще , что не соответствует этому формату, вы должны вывести « Invalid input». В противном случае вы должны вывести только одно случайное целое число, взвешенное в соответствии с входными данными. Например, 3d6должно выдавать больше 10s, чем 4s .

Контрольные примеры

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
Сложной частью этого вопроса является проверка входных данных, но параграф, который описывает правила проверки, является противоречивым. Он описывает nи pкак необязательный, но ввод, который выбирает не включать их ( d20+) как недействительный.
Питер Тейлор
1
@PeterTaylor: Я думаю, что +знак должен быть добавлен, только если указан модификатор p.
ProgramFOX
4
@ Doorknob, ну, потому что d13 и d17 - это не кости, используемые в D & D. D & D использует d4, d6, d8, d10, d12 и d20. Кроме того, безусловно, есть случаи, когда бросок будет включать в себя различные типы костей (например, 1d4+1d6для подлого разбойника, атакующего кинжалом) или отрицательный результат p(например, 1d20-1для проверки навыка без рангов / тренировок и модификатора отрицательной способности).
Брайан С.
2
Вы собираетесь играть в DDD без использования 2d8 + 1d6 + 4? У тебя будет плохое время
corsiKa

Ответы:

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 , другого числа и, необязательно, третьего числа, которому предшествует знак + .

    Если есть совпадение, цифры будут сохранены в $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 байтов.
подземный
2
Может быть сделано 96 символов,/^([1-9]\d*)?d([1-9]\d*)(\+\d+)?$/||die"Invalid input$/";$a+=1+int rand$2for(1..$1||1);$_=$a+$3
Hasturkun
1
@undergroundmonorail: я видел людей, считающих один параметр командной строки как один, два и даже три (считая пробел) байты. Я предпочел бы считать это как один, но два байта кажутся мне справедливыми.
Деннис
1
@ Винс, я полагаю, у тебя тоже нет. Я использую |0для приведения к int, так как randвозвращает псевдослучайно выбранный float .
Деннис
1
@ Vynce Я добавил постоянную ссылку на вопрос ( ideone.com/gLJfhO ). -eбыло бы здесь проблематично, если только вы не замените одинарные кавычки на двойные.
Деннис
4

Фортран: 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, используя умный алгоритм 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.
Пол Престиж
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*на один символ меньше.
Говард
@ Ховард, во-первых, потому что это был последний взлом, чтобы пройти несколько тестов, и я не думал о том, чтобы сыграть в гольф. Во-вторых, это заставило бы его принять некоторый неверный ввод.
Питер Тейлор
2

J - 130 (45?) Символ

Эта проблема, кажется, немного смещена в сторону регулярных выражений, особенно из-за необходимости различать неверный ввод. У 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. Если совпадения пустые (если 0 является элементом $ hape:) 0 e.$, мы выдаем сообщение об ошибке, иначе мы переходим к бросанию игральных костей: #~чтобы выставить кости, 1+?бросить и +/@,добавить модификатор p и сумма.

algorithmshark
источник
Это работает для 01d01+01?
Сис Тиммерман,
@CeesTimmerman Мой плохой. Это сейчас.
алгоритмистика
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» является псевдонимом универсального выхода «вниз» со встроенным сообщением об ошибке, когда его не существует; выходы сканируются перед пользовательскими командами. Оставшиеся строки создают объект с помощью пользовательской команды, использующей встроенную функцию die ().

Muqo
источник
2

PHP, 129

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

Использует регулярное выражение для создания выражения, которое затем оценивает PHP. Ввод осуществляется через URL:? 0 = аргумент . Убедитесь, что вы urlencode + до% 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.

Tryth
источник
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?

bobbel
источник
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).

Сис Тиммерман
источник
Хотя я неправильно понял БНФ. Эта страница помогает.
Сис Тиммерман,
В интересах всех, кто интересуется, почему регулярное выражение закреплено на одном конце, а не на другом: 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')
Майкл М.
источник
Это так похоже на ответ
Снэка
Ну, есть сходства, это один и тот же язык / алгоритм ... Но я подумал, что в моем коде (и в регулярном выражении) достаточно различий, чтобы опубликовать другой ответ.
Майкл М.
Согласно комментариям на вопрос, это неправильный ответ, потому что он отклоняет ввод 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ни mбыло 0, и было ли это m. Если какой-либо из них найден, он завершается с сообщением ( 'Invalid input'). Затем он просто печатает результат, так как он бы сейчас прервался, если ввод был неверным.

Печать результатов не так интересна, но ...

([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 бьет существующий ответ на Python, добавив в требуемой обработки ошибок и чтения , d20как 1d20вместо 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)

отредактировано, чтобы исправить 2 опечатки: I(x) => I(c) ,Invalid Input => Invalid input

отредактировано, чтобы исправить регулярные выражения: \+?(\d*) => (\+\d+)?

александр-Brett
источник
Согласно уточненному вопросу, это неправильный ответ, потому что он принимает входные данные 3d20+.
Питер Тейлор
Хорошая точка зрения! #filler
alexander-brett
И нет 01d01+01.
Сис Тиммерман,