Lancez les dés de Donjons et Dragons


20

Je veux jouer à Dungeons and Dragons, mais je n'ai pas de dés! Votre défi est de lancer des dés D&D.

La spécification du format d'entrée sous forme Backus-Naur est:

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

L'entier facultatif avant le dest le nombre de dés à lancer; il doit être au moins 1, et par défaut 1s'il n'est pas fourni.

L'entier requis immédiatement après le dest le nombre de côtés de chaque dé; ça doit être au moins 1. Les côtés de chaque dé sont des entiers positifs consécutifs distincts commençant à 1.

Le modificateur facultatif peut être +0, et il est par défaut +0s'il n'est pas spécifié.

Par exemple, pour l'entrée 2d10+5, vous générez deux nombres aléatoires de 1 à 10 inclus, les ajoutez ensemble et en ajoutez 5. Ensuite, vous produirez le résultat.

Si vous recevez une entrée invalide, comme 2d, d20+, 0d4, 2d5+1+2, 2+2, ou toute autre chose qui ne correspond pas à ce format, vous devez sortie « Invalid input». Sinon, vous ne devez générer qu'un seul entier aléatoire, pondéré en fonction de l'entrée. Par exemple, 3d6devrait produire plus de 10s que 4s .

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

Il s'agit de , donc le code le plus court en octets gagnera!


1
Est-ce 02d05+073une entrée valide?
MT0

2
La partie difficile de cette question est la validation de l'entrée, mais le paragraphe qui décrit les règles de validation est contradictoire. Il décrit net pcomme facultatif, mais les entrées qui choisissent de ne pas les inclure ( d20+) comme invalides.
Peter Taylor

1
@PeterTaylor: Je pense que le +signe ne devrait être ajouté que si le modificateur pest fourni.
ProgramFOX

4
@ Doorknob, Eh bien, parce que d13 et d17 ne sont pas des dés utilisés dans D&D. D&D utilise d4, d6, d8, d10, d12 et d20. De plus, il y a certainement des cas où un jet comprendrait différents types de dés (par exemple, 1d4+1d6pour un voleur sournois attaquant avec un poignard) ou ayant un négatif p(par exemple, 1d20-1pour un test de compétence sans rang / formation et un modificateur de capacité négatif).
Brian S

2
Vous allez jouer à dnd sans utiliser le cas 2d8 + 1d6 + 4? Tu vas passer un mauvais moment
corsiKa

Réponses:


12

Perl, 109 95 93 96 89 octets

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

Nécessite le -pcommutateur, qui représente deux des octets. Essayez-le en ligne sur Ideone .

Comment ça fonctionne

  • En raison du -pcommutateur, une ligne est lue à partir de STDIN et stockée dans $_.

  • La commande s/^d/1d/ajoute un 1 à $_si elle commence par un d , c'est-à-dire si le nombre de dés n'a pas été spécifié.

  • L'expression régulière /^(\d+)d(\d+)(\+\d+)?/vérifie si la ligne se compose d'un nombre, d'un d littéral , d'un autre nombre et, éventuellement, d'un troisième nombre précédé d'un signe + .

    S'il y a un match, les numéros seront enregistrés dans $1, $2et $3.

    Dans ce cas, l'entrée sera valide si et seulement si $1et $2sont tous deux positifs.

  • $d += 1 + rand $2 | 0ajoute un entier choisi de manière pseudo-aléatoire de 1 au nombre spécifié de côtés $d(initialement traité comme zéro).

  • for 1 .. $1 fait ce qui précède une fois pour chaque entier compris entre 1 et le nombre de dés.

  • La commande $_ = $1 * $2 ? $d + $3 : 'Invalid input'effectue les opérations suivantes:

    • Si $1 * $2est égal à zéro, il définit $_une entrée non valide .

    • Sinon, l'entrée est valide et correspond $_à la somme des jets de dés et du modificateur.

  • En raison du -pcommutateur, Perl imprime le contenu de $_.

  • Puisqu'il n'y a plus de lignes d'entrée, le script se ferme.


1
Je crois que, en général, les paramètres de ligne de commande supplémentaires sont considérés comme valant un octet chacun, mais le trait d'union est libre. Dans ce cas, -pne vous en coûterait qu'un, ce qui en fait une solution de 108 octets.
undergroundmonorail

2
Peut être fait 96 caractères,/^([1-9]\d*)?d([1-9]\d*)(\+\d+)?$/||die"Invalid input$/";$a+=1+int rand$2for(1..$1||1);$_=$a+$3
Hasturkun

1
@undergroundmonorail: J'ai vu des gens compter un seul commutateur de ligne de commande comme un, deux et même trois (en comptant les espaces) octets. Je préfère le compter comme un, mais deux octets me semblent justes.
Dennis

1
@Vynce Je suppose que vous non plus. J'utilise |0pour convertir en int, car randretourne un flotteur choisi de manière pseudo-aléatoire .
Dennis

1
@Vynce J'ai ajouté un permalien à la question ( ideone.com/gLJfhO ). -eserait problématique ici, à moins que vous ne remplaciez les guillemets simples par des guillemets doubles.
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;

Abuse le typage implicite ( i-nsont tous des entiers, tout le reste un réel). Mise en garde mineure: l'entrée doit être séparée par des espaces, donc 2d10+5doit être entrée comme 2 d 10 + 5, sinon vous obtiendrez un input conversion error.


4

Rubis, 116

Version alternative Ruby. J'essayais de trouver un moyen de le faire sans les expressions régulières, mais la validation que vous avez à faire est beaucoup plus difficile sans elles.

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

Celui-ci est 112, en utilisant l'algorithme Perl intelligent de 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 Merci! Je ne sais pas pourquoi je pensais que ça devait être> 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)}

Je ne peux pas mieux jouer au golf que ça. Il est temps de retourner au travail.


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)n'a que 137 octets.
Dennis

2
Selon les commentaires sur la question, il s'agit d'une réponse incorrecte car elle rejette l'entrée 02d05+073.
Peter Taylor

3

GolfScript ( 120 106 octets)

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

Ce n'est pas seulement plus court que la première version, mais aussi plus élégant. La partie qui fait le roulement est

\{rand)+}+@*

Le reste est principalement la validation des entrées et quelques caractères pour l'analyse.

# 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

Démo en ligne avec framework de test


Je me demande pourquoi tu n'utilises pas n./? Peut-être aussi 10,n*pour un personnage de moins.
Howard

@Howard, au premier, parce que c'était un hack de dernière minute pour passer quelques cas de test et je n'ai pas pensé à jouer au golf. Pour le second, cela lui ferait accepter des entrées invalides.
Peter Taylor

2

J - 130 (45?) Char

Ce défi semble être un peu biaisé vers les expressions régulières, en particulier avec la nécessité de différencier les entrées invalides. J a une bibliothèque d'expression régulière POSIX, donc ce n'est pas si mal, mais elle n'est pas intégrée comme elle l'est avec Perl, donc J ne fait pas mieux que les autres langages.

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

Si vous implémentez simplement la logique des expressions valides, comme les solutions Python / PHP semblent le faire, ce sont les 45 caractères les plus raisonnables:

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

Bits notables:

  • 1!:1]1est l'entrée et (rxmatch rxfrom])est la logique qui renvoie les correspondances de sous-expression.

  • Que l'entrée soit légale ou non est gérée par la correspondance d'expression régulière, nous pouvons donc définir les valeurs par défaut pour n et p avec 0 1 1>.. Il regarde en arrière (n est 1 par défaut et p est 0) car nous avons dû inverser ( |.) la liste plus tôt, afin que la logique à la fin s'exécute dans le bon ordre.

  • @.est la conjonction Agenda , essentiellement une instruction J-ish switch. Si les correspondances sont vides (si 0 est un e.lement de $ hape:) 0 e.$, nous émettons le message d'erreur, sinon nous passons par lancer les dés: #~pour définir les dés, 1+?lancer et +/@,ajouter le modificateur p et somme.


Est-ce que ça marche 01d01+01?
Cees Timmerman le

@CeesTimmerman My bad. C'est le cas maintenant.
algorithmshark

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)

Les quatre premières lignes traitent du fait que "d" est un alias pour la sortie universelle "down" avec un message d'échec intégré lorsqu'il n'existe pas; les sorties sont analysées avant les commandes définies par l'utilisateur. Les lignes restantes créent un objet avec une commande définie par l'utilisateur utilisant la fonction die () intégrée.


2

PHP, 129

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

Utilise une expression régulière pour créer une expression que PHP évalue ensuite. L'entrée est introduite via url:? 0 = argument . Assurez-vous d'avoir encodé le + en% 2b. Voici à quoi cela ressemble sous une forme plus lisible:

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

L'inversion au niveau du bit des chaînes en utilisant ~non seulement enregistre un caractère car vous n'avez pas besoin de guillemets (PHP suppose que ce sont des chaînes) mais enregistre également des caractères car vous n'avez pas à échapper les barres obliques inverses dans l'expression régulière.

L' ?:opérateur est une forme spéciale de l'opérateur ternaire. $foo = $a ? $a : $best le même que $foo = $a ?: $b.


1

Java, 378

Je voulais juste essayer une solution avec Java loin de la meilleure solution. Mais bon: Java n'est en aucun cas un langage de golf!

Il obtient l'entrée de la ligne de commande. Le premier paramètre args[0]est la valeur d'entrée.

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

Saviez-vous que decodec'est plus court que valueOf?


1

Python 3, 184 octets

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)

Réussit tous les tests. Si zéro dé était autorisé, il serait 6 octets plus court en omettant (or q).


J'ai mal compris la BNF. Cette page aide.
Cees Timmerman du

Pour le bénéfice de toute autre personne qui se demande pourquoi l'expression régulière est ancrée à une extrémité mais pas à l'autre: Python re.matchs'ancre implicitement au début mais pas à la fin. Je ne connais aucune autre bibliothèque regex qui fait cela.
Peter Taylor

1
Il y a une petite économie en initialisant t=int(c or 0); et il pourrait être possible de combiner votre réponse avec celle existante en Python (qui utilise moins d'espaces blancs) pour en économiser quelques autres.
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')

Ceci est tellement similaire à la réponse de Snack
user12205

Eh bien il y a des similitudes, c'est le même langage / algorithme ... Mais je pensais qu'il y avait suffisamment de différences dans mon code (et l'expression régulière) pour poster une réponse différente.
Michael M.

Selon les commentaires sur la question, il s'agit d'une réponse incorrecte car elle rejette l'entrée 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

Utilise une expression rationnelle pour effectuer tout le travail. Depuis que je suis à l' aide \d+, les seules choses que je dois vérifier les entrées invalides sont qu'il y avait un match, que ni nni métait 0, et qu'il y avait un m. Si l'un d'eux est trouvé, il s'interrompt avec un message ( 'Invalid input'). Ensuite, il imprime simplement le résultat, car il aurait été abandonné maintenant si l'entrée n'était pas valide.

L'impression des résultats n'est pas si intéressante, mais ...

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

Plus tard, j'ai changé .inject(:+)pour eval(...*?+), mais l'idée est la même.


0

Python3, 204B

Le mien bat la réponse Python existant en ajoutant dans la gestion des erreurs requise et la lecture d20comme 1d20plutôt que 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)

sous la direction de fixer 2 fautes de frappe: I(x) => I(c),Invalid Input => Invalid input

modifié pour corriger l'expression régulière: \+?(\d*) => (\+\d+)?


Selon la question clarifiée, il s'agit d'une réponse incorrecte car elle accepte l'entrée 3d20+.
Peter Taylor

Bon point! #filler
alexander-brett

Et non 01d01+01.
Cees Timmerman le
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.