Розкажіть кістки підземелля та драконів


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є кількість кісток, які потрібно скотити; він повинен бути принаймні 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для перевірки навичок без рангів / тренувань та модифікатора негативної здатності).
Брайан S

2
Ви збираєтесь грати в dnd без набору 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
@Vynce я припускаю, що ви цього не зробили. Я використовую |0для передачі до int, оскільки randповертає псевдовипадково вибраний поплавок .
Денніс

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

Явасципта, 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?) Знаків

Цей виклик, здається, трохи упереджений до регулярних виразів, особливо з необхідністю розмежувати недійсні дані. 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 і суму.


Це працює 01d01+01?
Cees Timmerman

@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 ().


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.


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

Пітон 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

На користь будь-кому іншому, хто замислюється про те, чому режекс закріплений в одному кінці, а не в іншому: 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')

Це так схоже на відповідь Snack
user12205

Ну є схожість, це та сама мова / алгоритм ... Але я подумав, що в моєму коді (і регулярному вираженні) достатньо відмінностей, щоб опублікувати іншу відповідь.
Майкл М.

Згідно з коментарями до питання, це неправильна відповідь, оскільки він відкидає вхід 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

Шахта перевершує існуючу відповідь 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+)?


Відповідно до уточненого питання, це неправильна відповідь, оскільки вона приймає вхід 3d20+.
Пітер Тейлор

Гарна думка! #filler
alexander-brett

І ні 01d01+01.
Cees Timmerman
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.