Lancia i dadi di Dungeons and Dragons


20

Voglio giocare a Dungeons and Dragons, ma non ho dadi! La tua sfida è lanciare alcuni dadi D&D.

La specifica del formato di input in formato 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>

Il numero intero opzionale prima del dè il numero di dadi da lanciare; deve essere almeno 1e il valore predefinito è 1se non fornito.

Il numero intero richiesto immediatamente dopo il dè il numero di lati di ciascun dado; deve essere almeno 1. I lati di ciascun dado sono numeri interi positivi consecutivi distinti a partire da 1.

Il modificatore opzionale può essere +0, e per impostazione predefinita è +0se non specificato.

Ad esempio, per l'input 2d10+5, si generano due numeri casuali da 1 a 10 inclusi, sommarli e aggiungere 5. Quindi si otterrà il risultato.

Se si riceve input non valido, come ad esempio 2d, d20+, 0d4, 2d5+1+2, 2+2, o qualsiasi altra cosa che non va bene questo formato, è necessario l'uscita " Invalid input". In caso contrario, è necessario produrre solo un intero intero casuale, ponderato in base all'input. Ad esempio, 3d6dovrebbe produrre più 10s che 4s .

Casi test

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

Questo è , quindi vincerà il codice più breve in byte!


1
È 02d05+073un input valido?
MT0

2
La parte difficile di questa domanda è convalidare l'input, ma il paragrafo che descrive le regole di validazione è contraddittorio. Descrive ne pcome facoltativo, ma input che scelgono di non includerli ( d20+) come non validi.
Peter Taylor,

1
@PeterTaylor: Penso che il +segno dovrebbe essere aggiunto solo se pviene fornito il modificatore .
Programma FOX

4
@Doorknob, Beh, perché d13 e d17 non sono dadi usati in D&D. D&D utilizza d4, d6, d8, d10, d12 e d20. Inoltre, ci sono certamente casi in cui un tiro includerebbe diversi tipi di dadi (ad esempio, 1d4+1d6per un ladro che attacca furtivamente con un pugnale) o con un negativo p(ad esempio, 1d20-1per un controllo delle abilità senza gradi / addestramento e un modificatore di abilità negativo).
Brian S

2
Giocherai a dnd senza il caso d'uso di 2d8 + 1d6 + 4? Ti
divertirai

Risposte:


12

Perl, 109 95 93 96 89 byte

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

Richiede l' -popzione, che rappresenta due byte. Provalo online su Ideone .

Come funziona

  • A causa dello -pswitch, una riga viene letta da STDIN e memorizzata in $_.

  • Il comando s/^d/1d/antepone un 1 a $_se inizia con una d , ovvero se il numero di dadi non è stato specificato.

  • L'espressione regolare /^(\d+)d(\d+)(\+\d+)?/controlla se la linea è composta da un numero, una letterale d , un altro numero e, facoltativamente, un terzo numero preceduto da un segno + .

    Se c'è una corrispondenza, i numeri verranno salvati in $1, $2e $3.

    In questo caso, l'ingresso sarà valido se e solo se $1e $2sono entrambi positivi.

  • $d += 1 + rand $2 | 0aggiunge un numero intero scelto pseudo-casualmente da 1 al numero specificato di lati a $d(inizialmente trattato come zero).

  • for 1 .. $1 fa quanto sopra una volta per ogni numero intero compreso tra 1 e il numero di dadi.

  • Il comando $_ = $1 * $2 ? $d + $3 : 'Invalid input'procede come segue:

    • Se $1 * $2è zero, imposta $_su Input non valido .

    • Altrimenti, l'input è valido e si imposta $_sulla somma dei tiri di dado e del modificatore.

  • A causa -pdell'opzione, Perl stampa il contenuto di $_.

  • Poiché non vi sono ulteriori righe di input, lo script viene chiuso.


1
Credo che, in generale, si considerino che valgano un byte parametri di riga di comando aggiuntivi ciascuno ma il trattino è libero. In questo caso, -pti costerebbe solo uno, rendendola una soluzione da 108 byte.
undergroundmonorail,

2
Può essere effettuato 96 caratteri,/^([1-9]\d*)?d([1-9]\d*)(\+\d+)?$/||die"Invalid input$/";$a+=1+int rand$2for(1..$1||1);$_=$a+$3
Hasturkun

1
@undergroundmonorail: ho visto persone contare un singolo switch della riga di comando come uno, due e persino tre (contando lo spazio bianco) byte. Preferirei considerarlo come uno, ma due byte mi sembrano giusti.
Dennis,

1
@Vynce Suppongo che neanche tu. Uso il |0cast per int, poiché randrestituisce un float scelto pseudo-casualmente .
Dennis,

1
@Vynce Ho aggiunto un permalink alla domanda ( ideone.com/gLJfhO ). -esarebbe problematico qui, a meno che non si sostituiscano le virgolette singole con virgolette doppie.
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;

Abuso della digitazione implicita ( i-nsono tutti numeri interi, tutto il resto un reale). Avvertenza minore: l'input deve essere separato da spazio, quindi 2d10+5deve essere inserito come 2 d 10 + 5, altrimenti otterrai un input conversion error.


4

Ruby, 116

Versione Ruby alternativa. Stavo cercando di trovare un modo per farlo senza le espressioni regolari, ma la convalida che devi fare è molto più difficile senza di loro.

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

Questo è il 112, usando l'algoritmo Perl intelligente di Dennis:

$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 Grazie! Non so perché ho pensato che dovesse essere> 0.
Paul Prestidge,

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

Non posso giocare a golf meglio di così. È ora di tornare al lavoro.


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)ha solo 137 byte.
Dennis,

2
Secondo i commenti sulla domanda, questa è una risposta errata perché rifiuta l'input 02d05+073.
Peter Taylor,

3

GolfScript ( 120 106 byte)

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

Questo non è solo più corto della prima versione, ma anche più elegante. La parte che effettivamente esegue il lancio del dado è

\{rand)+}+@*

Il resto è principalmente la convalida dell'input e alcuni caratteri per l'analisi.

# 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 con framework di test


Mi chiedo perché non usi n./? Forse anche 10,n*per un personaggio in meno.
Howard,

@Howard, al primo, perché è stato un hack dell'ultimo minuto per passare alcuni casi di test e non ho pensato di giocare a golf. Al secondo, ciò consentirebbe di accettare alcuni input non validi.
Peter Taylor,

2

J - 130 (45?) Char

Questa sfida sembra essere un po 'distorta verso le espressioni regolari, in particolare con la necessità di differenziare input non validi. J ha una libreria di regex POSIX, quindi non è poi così male, ma non è integrato come lo è con Perl, quindi J non è migliore delle altre lingue.

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

Se stai solo implementando la logica per espressioni valide, come sembrano le soluzioni Python / PHP, sono i 45 caratteri più ragionevoli:

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

Bit notevoli:

  • 1!:1]1è l'input ed (rxmatch rxfrom])è la logica che restituisce le corrispondenze della sottoespressione.

  • Se l'input era legale è gestito dalla corrispondenza regex, quindi possiamo impostare i valori predefiniti per n e p con 0 1 1>.. Guarda indietro (n è 1 per impostazione predefinita e p è 0) perché abbiamo dovuto invertire ( |.) l'elenco prima, in modo che la logica alla fine venga eseguita nel giusto ordine.

  • @.è la congiunzione Agenda , essenzialmente una dichiarazione switch J-ish. Se le partite sono vuote (se 0 è un e.lement di $ hape:) 0 e.$, emettiamo il messaggio di errore, altrimenti procediamo con il lancio dei dadi: #~per impostare i dadi, 1+?tirare e +/@,aggiungere il modificatore p e somma.


Funziona per 01d01+01?
Cees Timmerman,

@CeesTimmerman Mio male. Lo fa adesso.
algoritmo

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)

Le prime quattro righe trattano il fatto che "d" è un alias per l'uscita "down" universale con un messaggio di errore incorporato quando non esiste; le uscite vengono scansionate prima dei comandi definiti dall'utente. Le righe rimanenti creano un oggetto con un comando definito dall'utente facendo uso della funzione die () integrata.


2

PHP, 129

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

Usa una regex per creare un'espressione che PHP quindi valuta. L'input viene immesso tramite url:? 0 = argomento . Assicurati di codificare da + a% 2b. Ecco come appare in una forma più leggibile:

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

Inversione bit per bit delle stringhe utilizzando ~ non solo salva un carattere perché non hai bisogno di virgolette (PHP presume che siano stringhe) ma salva anche i caratteri perché non devi sfuggire alle barre rovesciate nell'espressione regolare.

L' ?:operatore è una forma speciale dell'operatore ternario. $foo = $a ? $a : $bè lo stesso di $foo = $a ?: $b.


1

Java, 378

Volevo solo provare una soluzione con Java tutt'altro che la migliore soluzione. Ma hey: Java non è un linguaggio da golf in ogni caso!

Ottiene l'input dalla riga di comando. Il primo parametro args[0]è il valore di input.

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

Lo sapevi che decodeè più breve di valueOf?


1

Python 3, 184 byte

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)

Supera tutti i test. Se fossero ammessi zero dadi, sarebbe più corto di 6 byte lasciandolo fuori (or q).


Ho frainteso il BNF, però. Questa pagina aiuta.
Cees Timmerman,

A beneficio di chiunque si chieda perché il regex sia ancorato da un lato ma non dall'altro: Python è re.matchimplicitamente ancorato all'inizio ma non alla fine. Non sono a conoscenza di altre librerie regex che lo fanno.
Peter Taylor,

1
C'è un piccolo risparmio inizializzando t=int(c or 0); e potrebbe essere possibile combinare la tua risposta con quella esistente di Python (che utilizza meno spazi bianchi) per risparmiare un paio di più.
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')

Questo è molto simile alla risposta di Snack
user12205

Bene, ci sono somiglianze, questo è lo stesso linguaggio / algoritmo ... Ma ho pensato che ci fossero abbastanza differenze nel mio codice (e nella regex) per pubblicare una risposta diversa.
Michael M.,

Secondo i commenti sulla domanda, questa è una risposta errata perché rifiuta l'input 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

Usa una regexp per fare tutto il lavoro. Dal momento che sto usando \d+, le uniche cose che devo controllare per l'input non valido sono che c'è stata una corrispondenza, che né nné lo msono stati 0, e che c'è stato un m. Se ne viene trovato uno, si interrompe con un messaggio ( 'Invalid input'). Quindi stampa solo il risultato, poiché ormai si sarebbe interrotto se l'input non fosse valido.

La stampa dei risultati non è così interessante, ma ...

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

In seguito sono passato .inject(:+)a eval(...*?+), ma l'idea è la stessa.


0

Python3, 204B

Il mio batte la risposta Python esistente aggiungendo la gestione e la lettura dell'errore richieste d20come 1d20anziché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)

modificato per correggere 2 errori di battitura: I(x) => I(c) ,Invalid Input => Invalid input

modificato per correggere regex: \+?(\d*) => (\+\d+)?


Secondo la domanda chiarita, questa è una risposta errata perché accetta l'input 3d20+.
Peter Taylor,

Buon punto! #filler
alexander-brett

E no 01d01+01.
Cees Timmerman,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.