Rzuć kostką Lochów i Smoków

20

Chcę grać w Dungeons and Dragons, ale nie mam żadnych kości! Twoim zadaniem jest rzucić kostką D&D.

Specyfikacja formatu wejściowego w postaci Backus-Naur to:

<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>

Opcjonalna liczba całkowita przed djest liczbą kości do rzucenia; musi być co najmniej 1i domyślnie ustawiony, 1jeśli nie jest dostarczony.

Wymagana liczba całkowita bezpośrednio po djest liczbą stron każdej kości; to musi być przynajmniej 1. Boki każdej kości są odrębnymi kolejnymi dodatnimi liczbami całkowitymi, zaczynając od 1.

Opcjonalnym modyfikatorem może być +0i domyślnie jest ustawiony, +0jeśli nie jest określony.

Na przykład dla danych wejściowych 2d10+5generujesz dwie liczby losowe od 1 do 10 włącznie, dodajesz je razem i dodajesz 5. Następnie otrzymasz wynik.

Jeśli otrzymasz nieprawidłowe dane, takie jak 2d, d20+, 0d4, 2d5+1+2, 2+2, lub cokolwiek innego, co nie pasuje do tego formatu, trzeba wyjście „ Invalid input”. W przeciwnym razie musisz wyprowadzić tylko jedną losową liczbę całkowitą, ważoną zgodnie z danymi wejściowymi. Na przykład 3d6powinien produkować więcej 10s niż 4s .

Przypadki testowe

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

To jest , więc wygra najkrótszy kod w bajtach!

Klamka
źródło
1
Czy 02d05+073jest poprawny wpis?
MT0,
2
Trudną częścią tego pytania jest sprawdzenie poprawności danych wejściowych, ale akapit opisujący reguły sprawdzania poprawności jest wewnętrznie sprzeczny. Opisuje ni pjako opcjonalne, ale dane wejściowe, które decydują się nie uwzględniać ich ( d20+) jako niepoprawnych.
Peter Taylor,
1
@PeterTaylor: Myślę, że +znak należy dodać tylko wtedy, gdy ppodany jest modyfikator .
ProgramFOX
4
@Doorknob, cóż, ponieważ d13 i d17 nie są kostkami używanymi w D&D. D&D używa d4, d6, d8, d10, d12 i d20. Ponadto z pewnością istnieją przypadki, w których rzut zawierałby różne rodzaje kości (np. 1d4+1d6Za Rogue'a skradającego się za pomocą sztyletu) lub mający negatywne p(np. 1d20-1Za sprawdzenie umiejętności bez rang / treningu i modyfikatora negatywnej zdolności).
Brian S,
2
Będziesz grać w dnd bez użycia 2d8 + 1d6 + 4? Będziesz miał zły czas
corsiKa

Odpowiedzi:

12

Perl, 109 95 93 96 89 bajtów

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

Wymaga -pprzełącznika, który odpowiada za dwa bajty. Wypróbuj online na Ideone .

Jak to działa

  • Z powodu -pprzełącznika wiersz jest odczytywany ze STDIN i zapisywany w $_.

  • Komenda s/^d/1d/poprzedza się 1 do $_jeżeli zaczyna się od d , to znaczy, jeżeli liczba kości nie został określony.

  • Wyrażenie regularne /^(\d+)d(\d+)(\+\d+)?/sprawdza, czy wiersz składa się z liczby, literału d , innej liczby i, opcjonalnie, trzeciej liczby poprzedzonej znakiem + .

    W przypadku dopasowania liczby zostaną zapisane w $1, $2i $3.

    W tym przypadku, wejście będzie ważna tylko wtedy, gdy $1i $2to zarówno pozytywne.

  • $d += 1 + rand $2 | 0dodaje pseudolosowo wybraną liczbę całkowitą od 1 do określonej liczby stron do $d(początkowo traktowanych jako zero).

  • for 1 .. $1 robi powyższe raz dla każdej liczby całkowitej od 1 do liczby kości.

  • Polecenie $_ = $1 * $2 ? $d + $3 : 'Invalid input'wykonuje następujące czynności:

    • Jeśli $1 * $2wynosi zero, ustawia się $_na Niepoprawne dane wejściowe .

    • W przeciwnym razie dane wejściowe są prawidłowe i ustawiają $_sumę rzutów kostką oraz modyfikator.

  • Z powodu -pprzełącznika Perl drukuje zawartość $_.

  • Ponieważ nie ma już żadnych wierszy wprowadzania, skrypt kończy działanie.

Dennis
źródło
1
Uważam, że generalnie dodatkowe parametry wiersza poleceń są uważane za warte bajtu, ale myślnik jest wolny. W takim przypadku -pkosztowałby Cię tylko jeden, dzięki czemu jest to rozwiązanie 108-bajtowe.
undergroundmonorail
2
Można zrobić 96 znaków,/^([1-9]\d*)?d([1-9]\d*)(\+\d+)?$/||die"Invalid input$/";$a+=1+int rand$2for(1..$1||1);$_=$a+$3
Hasturkun,
1
@undergroundmonorail: Widziałem ludzi liczących pojedynczy przełącznik wiersza poleceń jako jeden, dwa, a nawet trzy (licząc białe znaki) bajty. Wolę liczyć to jako jeden, ale dwa bajty wydają mi się sprawiedliwe.
Dennis,
1
@ Vynce Zakładam, że ty też nie. Używam |0do rzutowania na int, ponieważ randzwraca pseudolosowo wybraną liczbę zmiennoprzecinkową .
Dennis,
1
@ Vynce Dodałem bezpośredni link do pytania ( ideone.com/gLJfhO ). -ebyłoby tutaj problematyczne, chyba że zastąpisz pojedyncze cudzysłowy podwójnymi cudzysłowami.
Dennis,
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;

Nadużywa niejawnego pisania ( i-nwszystkie są liczbami całkowitymi, wszystko inne jest prawdziwe). Drobne zastrzeżenie: dane wejściowe muszą być oddzielone spacją, więc 2d10+5należy wprowadzić jako 2 d 10 + 5, w przeciwnym razie otrzymasz input conversion error.

Kyle Kanos
źródło
4

Ruby, 116

Alternatywna wersja Ruby. Próbowałem znaleźć sposób, aby to zrobić bez wyrażeń regularnych, ale walidacja, którą musisz zrobić, jest o wiele trudniejsza bez nich.

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

Ten ma numer 112, wykorzystujący sprytny algorytm Perla Dennisa:

$p='(\d*[1-9]\d*)'
puts~/^#$p?d#$p(\+\d+)?$/?eval("r=#{$3||0};#{$1||1}.times{r+=rand(#$2)+1};r"):'Invalid input'
Paul Prestidge
źródło
@ m.buettner Thanks! Nie wiem, dlaczego myślałem, że to musi być> 0.
Paul Prestidge
3

JavaScript, 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)}

Nie można lepiej grać w golfa. Czas wrócić do pracy.

Przekąska
źródło
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)ma tylko 137 bajtów.
Dennis,
2
Zgodnie z komentarzami do pytania jest to nieprawidłowa odpowiedź, ponieważ odrzuca dane wejściowe 02d05+073.
Peter Taylor,
3

GolfScript ( 120 106 bajtów)

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

Jest to nie tylko krótsze niż pierwsza wersja, ale także bardziej eleganckie. Część, która faktycznie wykonuje rzut kostką, jest

\{rand)+}+@*

Reszta to głównie sprawdzanie poprawności danych wejściowych i kilka znaków do analizy.

# 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

Demo online ze środowiskiem testowym

Peter Taylor
źródło
Zastanawiam się, dlaczego nie używasz n./? Może także 10,n*o jedną postać mniej.
Howard,
@Howard, do pierwszego, ponieważ to był hack w ostatniej chwili, aby zdać kilka testów, a ja nie myślałem o grze w golfa. Po drugie, spowodowałoby to akceptację nieprawidłowych danych wejściowych.
Peter Taylor,
2

J - 130 (45?) Char

To wyzwanie wydaje się być trochę tendencyjne w stosunku do wyrażeń regularnych, szczególnie z koniecznością różnicowania nieprawidłowych danych wejściowych. J ma bibliotekę wyrażeń regularnych POSIX, więc nie jest tak źle, ale nie jest zintegrowana z Perlem, więc J nie radzi sobie lepiej niż inne języki.

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

Jeśli tylko implementujesz logikę prawidłowych wyrażeń, takich jak wydaje się, że rozwiązania Python / PHP, to bardziej rozsądne 45 znaków:

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

Znaczące bity:

  • 1!:1]1jest wejściem i (rxmatch rxfrom])logiką, która zwraca dopasowania podwyrażenia.

  • To, czy dane wejściowe były zgodne z prawem, jest obsługiwane przez dopasowanie wyrażenia regularnego, więc możemy ustawić wartości domyślne dla n i p za pomocą 0 1 1>.. Spogląda wstecz (domyślnie n wynosi 1, a p wynosi 0), ponieważ musieliśmy wcześniej odwrócić ( |.) listę, aby logika na końcu była wykonywana we właściwej kolejności.

  • @.to koniunkcja Agenda , zasadniczo instrukcja J-ish switch. Jeśli dopasowania są puste (jeśli 0 jest e.lementem $ hape:) 0 e.$, wysyłamy komunikat o błędzie, w przeciwnym razie przechodzimy przez rzucanie kostkami: #~aby ustalić kości, 1+?rzucić i +/@,dodać modyfikator p i suma.

algorytmshark
źródło
Czy to działa 01d01+01?
Cees Timmerman
@CeesTimmerman My bad. To robi teraz.
algorytmshark
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)

Pierwsze cztery wiersze dotyczą faktu, że „d” jest aliasem uniwersalnego wyjścia „w dół” z wbudowanym komunikatem o awarii, gdy nie istnieje; wyjścia są skanowane przed poleceniami zdefiniowanymi przez użytkownika. Pozostałe linie tworzą obiekt za pomocą polecenia zdefiniowanego przez użytkownika, korzystając z wbudowanej funkcji die ().

Muqo
źródło
2

PHP, 129

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

Używa wyrażenia regularnego, aby utworzyć wyrażenie, które następnie PHP ocenia. Dane wejściowe są podawane przez adres url:? 0 = argument . Upewnij się, że urlencode + na% 2b. Oto jak wygląda w bardziej czytelnej formie:

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";');

Bitowe odwracanie ciągów za pomocą ~nie tylko zapisuje znak, ponieważ nie potrzebujesz cudzysłowów (PHP zakłada, że ​​są to ciągi), ale także zapisuje znaki, ponieważ nie musisz uciekać przed odwrotnymi ukośnikami w wyrażeniu regularnym.

?:Operator jest specjalną formą operatora trójskładnikowego. $foo = $a ? $a : $bjest taki sam jak $foo = $a ?: $b.

Tryth
źródło
1

Java, 378

Chciałem tylko wypróbować rozwiązanie z Javą dalekie od najlepszego rozwiązania. Ale hej: Java w żadnym wypadku nie jest językiem golfowym!

Pobiera dane wejściowe z wiersza poleceń. Pierwszy parametr args[0]to wartość wejściowa.

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;}}

Czy wiesz, że decodejest krótszy niż valueOf?

Bobbel
źródło
1

Python 3, 184 bajty

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)

Przechodzi wszystkie testy. Gdyby dozwolone były kości zero, pomijanie byłoby o 6 bajtów krótsze (or q).

Cees Timmerman
źródło
Jednak źle zrozumiałem BNF. Ta strona pomaga.
Cees Timmerman
Z korzyścią dla każdego, kto zastanawia się, dlaczego wyrażenie regularne jest zakotwiczone na jednym końcu, ale nie na drugim: Python re.matchdomyślnie zakotwicza na początku, ale nie na końcu. Nie znam żadnej innej biblioteki wyrażeń regularnych, która to robi.
Peter Taylor,
1
Inicjalizacja jest niewielka oszczędność t=int(c or 0); i może być możliwe połączenie twojej odpowiedzi z istniejącą w Pythonie (która wykorzystuje mniej białych znaków), aby zaoszczędzić jeszcze kilka.
Peter Taylor
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.
źródło
Jest to tak podobne do odpowiedzi
Snacka
Cóż, istnieją podobieństwa, to ten sam język / algorytm ... Ale myślałem, że jest wystarczająco dużo różnic w moim kodzie (i wyrażeniu regularnym), aby opublikować inną odpowiedź.
Michael M.
Zgodnie z komentarzami do pytania jest to nieprawidłowa odpowiedź, ponieważ odrzuca dane wejściowe 02d05+073.
Peter Taylor,
0

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

Używa wyrażenia regularnego do wykonania całej pracy. Ponieważ używam \d+, jedyne rzeczy, które muszę sprawdzić pod kątem nieprawidłowych danych wejściowych, to to, że było dopasowanie, które nie było ani nnie mbyło 0, i że było m. Jeśli którykolwiek zostanie znaleziony, przerywa się komunikatem ( 'Invalid input'). Następnie drukuje wynik, ponieważ zostałby przerwany, gdyby dane wejściowe były nieprawidłowe.

Drukowanie wyników nie jest tak interesujące, ale ...

([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)

Później zmieniłem .inject(:+)na eval(...*?+), ale pomysł jest taki sam.

Klamka
źródło
0

Python3, 204B

Kopalnia bije istniejącego Pythona odpowiedź dodając w wymaganej obsługi błędów i czytania d20jak 1d20zamiast 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)

edytowany naprawić 2 literówki: I(x) => I(c),Invalid Input => Invalid input

edytowane, aby naprawić regex: \+?(\d*) => (\+\d+)?

Alexander-Brett
źródło
Według wyjaśnionego pytania jest to niepoprawna odpowiedź, ponieważ akceptuje ona dane wejściowe 3d20+.
Peter Taylor,
Słuszna uwaga! #filler
Alexander-brett
I nie 01d01+01.
Cees Timmerman