Calculadora HP D&D 5e

11

Tengo problemas para recordar todo lo que tengo que hacer al subir de nivel a un personaje de D&D. Por alguna razón, una de las cosas que me da problemas es descubrir cuál debería ser su nuevo valor máximo de HP. Para este desafío, escribirá un programa o función para calcular el valor correcto automáticamente.

Terminología

Lo primero que debe saber para calcular el HP máximo es el "modificador de Constitución". Cada personaje DND tiene seis puntajes de habilidad entera, incluido uno para Constitución. El único conocimiento relevante requerido para este desafío es cómo el puntaje de habilidad de la Constitución afecta a otra estadística, que es el modificador de la Constitución. En resumen, el modificador es igual a floor( (ability_score - 10) / 2 ). Los aventureros solo pueden tener puntajes de habilidad de 1 a 20, inclusive. Su código nunca tendrá que manejar puntajes fuera de ese rango, lo que también significa que nunca tendrá que manejar un modificador menor que -5 o mayor que +5. Aunque el modificador de Constitución puede cambiar a medida que un personaje sube de nivel, sus efectos en HP se aplican de forma retroactiva, por lo que solo se necesita su valor actual para calcular el HP máximo actual.

(Esto es completamente irrelevante para el desafío, pero si tiene curiosidad acerca de cómo afecta al HP máximo: puede suponer que la hazaña "Tough" agrega 2 al modificador de Constitución de un personaje para el cálculo de HP, ya que eso es efectivamente lo que hace Ese no es el texto de la hazaña, pero las matemáticas son exactamente iguales. No tiene que manejar esta hazaña en su respuesta).

Luego, cada clase tiene asignado un tipo de "dado de golpe", que está involucrado en el cálculo de HP. La siguiente tabla enumera los dados de golpe para cada clase.

Sorcerer:  d6
Wizard:    d6
Bard:      d8
Cleric:    d8
Druid:     d8
Monk:      d8
Rogue:     d8
Warlock:   d8
Fighter:   d10
Paladin:   d10
Ranger:    d10
Barbarian: d12

Finalmente, el nivel del personaje. Todo lo que esto afecta es cuántas veces agregar un valor al total acumulado en la siguiente sección. El nivel de un personaje es un número entero de 1 a 20, incluido 1 . Su código nunca tendrá que manejar un nivel fuera de ese rango. Para alcanzar el nivel n, un personaje comienza en el nivel 1 y sube de nivel n-1veces. Por ejemplo, un personaje de nivel 3 llegó a donde está al ser un personaje de nivel 1 y subir de nivel dos veces.

Cómo calcular el HP máximo

El HP máximo de un personaje es igual a su HP en el nivel 1 más la suma del aumento que recibió en cada nivel.

En el nivel 1

En el nivel 1, el HP de un personaje es igual a la tirada más alta posible en su dado de golpe (el número en el nombre del dado, para aquellos de ustedes que no están familiarizados con los dados que tienen más de 6 lados) más su modificador de Constitución. Recuerde que al calcular HP en un nivel posterior, puede suponer que la Constitución de un personaje siempre ha sido la misma, ya que esta parte del cálculo se vuelve a hacer cada vez que la Constitución cambia.

Al subir de nivel

Cada vez que un personaje sube de nivel, tiene dos opciones. Pueden tirar uno de sus dados de golpe o tomar la tirada promedio de ese dado (redondeado). Cualquiera que elijan, su modificador de Constitución se agrega al resultado. Este total es la cantidad que aumenta su HP. Para este desafío, siempre se toma la tirada promedio, por lo que la salida es determinista. (Nuevamente, si no está familiarizado con> dados de 6 caras, puede calcular la tirada promedio redondeada como (highest_possible_roll / 2) + 1).

Hay una notable excepción. El HP máximo de un personaje siempre aumenta en al menos 1 cada vez que sube de nivel 2 . Si las instrucciones en el párrafo anterior resultarían en un aumento de 0 o menos al subir de nivel, en su lugar, aumentará en 1.

El reto

Su programa o función tomará tres entradas :

  • La clase del personaje, como una cadena.
  • El nivel del personaje
  • El puntaje de habilidad de Constitución del personaje ( no modificador)

Será salida de una sola cosa: la corriente máxima de HP del personaje.

Ejemplos

Todas las combinaciones posibles de entradas y sus salidas asociadas se pueden encontrar en este enlace. En aras de tener algo que ver en esta página, aquí hay 30 casos de prueba elegidos al azar:

Barbarian, 15th level, 13 CON: 125
    Rogue, 10th level, 18 CON: 93
   Wizard, 15th level, 18 CON: 122
   Wizard, 16th level,  1 CON: 16
Barbarian, 15th level,  7 CON: 80
  Warlock, 15th level,  3 CON: 18
   Ranger, 14th level,  1 CON: 18
  Warlock,  3rd level, 14 CON: 24
    Druid,  3rd level,  4 CON: 9
   Cleric, 11th level,  5 CON: 25
     Bard, 20th level, 11 CON: 103
Barbarian, 11th level, 13 CON: 93
     Bard,  8th level, 19 CON: 75
     Bard, 16th level, 17 CON: 131
  Fighter, 10th level,  6 CON: 44
     Monk, 10th level,  2 CON: 13
   Cleric, 14th level, 17 CON: 115
   Cleric,  6th level,  5 CON: 15
    Rogue,  7th level, 13 CON: 45
   Cleric,  4th level, 14 CON: 31
    Rogue, 19th level, 15 CON: 136
  Paladin, 13th level, 13 CON: 95
   Cleric, 13th level, 15 CON: 94
     Bard,  8th level,  5 CON: 19
     Monk, 20th level, 11 CON: 103
Barbarian,  8th level, 20 CON: 101
     Monk,  1st level,  4 CON: 5
     Bard,  5th level, 17 CON: 43
     Monk, 18th level,  7 CON: 57
   Wizard, 17th level,  5 CON: 19

1. Hablando estrictamente, no creo que haya una regla que diga que 20 es el nivel máximo. Sin embargo, 21 es el punto donde dejará de haber tablas en el libro para decirle cuáles deberían ser algunos de los diversos números en las reglas, incluida la cantidad de experiencia que necesita obtener para alcanzarla. Ese es un límite de nivel lo suficientemente bueno para mí.

2. En realidad no creo que esto sea cierto con RAW. Pregunté en rpg.se y tal cosa no parece estar escrita en ningún lado. Sin embargo, Mike Mearls, diseñador principal de D&D, lo tuiteó en marzo de 2015 . Esta no es la forma autorizada en la que podría argumentar que sería un tweet del desarrollador principal de reglas Jeremy Crawford, pero es evidencia de que es lo que pretendían, así que lo usaré para este desafío.

metro subterráneo
fuente
¿La clase tiene que ser dada como una cadena, o puede ser dada como el número del dado, dado que esa es la única información relevante para una clase? De lo contrario, las personas solo necesitarán una tabla genérica de "Si estas clases, entonces mueren, si estas clases, entonces mueren", etc.
Skidsdev
¿También se pasan el nivel y la constitución como enteros, o como cadenas que dicen "xth level" y "y CON"?
Skidsdev
1
Gosh, soy viejo, todavía recuerdo esta tabla: ancientscrossroads.com/adnd_tools/con_table.htm
Neil
@Mayube Probablemente no debería haber hecho una pregunta e inmediatamente salí a comer pizza, ¿eh? : P La clase tiene que ser una cadena, porque creo que hay suficientes datos en esas cadenas para encontrar patrones para acortar la tabla (que parece ser el caso, en función de las respuestas que han llegado hasta ahora). El nivel y la constitución son ints.
undergroundmonorail
3
Me resultó bastante difícil analizar la información relevante de toda la información que se me arroja.
Jonathan Allan

Respuestas:

2

Jalea , 34 bytes

OSị“#®Ʋ?[’ṃ6¤ð+‘»1×⁵’¤+⁸Ḥ¤+ð⁹_10:2

Programa completo que toma tres argumentos de línea de comando: clase, puntaje, nivel.

Pruébalo en línea!

¿Cómo?

El centro del código, separado por ðs es un enlace diádico que calcula el resultado de algunos valores calculados previamente:

+‘»1×⁵’¤+⁸Ḥ¤+ - maxHitPoints(halfDieValue, modifier)
+             - add: halfDieValue + modifier
 ‘            - increment
  »1          - maximum of that and 1: this is the level-up delta
       ¤      - nilad followed by links as a nilad:
     ⁵        -   program's 3rd argument, level (5th command line argument)
      ’       -   decrement: this is the number of level-ups
    ×         - multiply: level-ups * level-up delta
           ¤  - nilad followed by links as a nilad:
         ⁸    -   link's left argument: halfDieValue
          Ḥ   -   double: dieValue
        +     - add: level-ups * level-up delta + dieValue
            + - add: level-ups * level-up delta + dieValue + modifier

El modificador se calcula en el lado derecho:

⁹_10:2 - getModifier(class, score)
⁹      - link's right argument, the 2nd argument, the score
 _10   - minus 10
    :2 - integer divide by 2

La mitad del valor del dado se calcula en el lado izquierdo:

OSị“#®Ʋ?[’ṃ6¤ - getHalfDieValue(class)
O             - cast to ordinals
 S            - sum
            ¤ - nilad followed by link(s) as a nilad:
   “#®Ʋ?[’    -   base 250 literal 140775266092
          ṃ6  -   convert to base 6 but with 6s in place of 0s
  ị           - index into (1-indexed and modular)

Teniendo en cuenta las sumas ordinales del módulo de nombres de clase de mmodo que msea ​​mínimo mientras se mantiene las clasificaciones (por troquel) de rendimientos colisionantes m=15. Colocar los valores requeridos (medio rollo de dado) en esos índices en una lista de longitud 15 permite la búsqueda usando la indexación modular de Jelly con . La compresión de la lista como un número de base 6 con el único 6reemplazado por a 0es un byte más corto que las alternativas de compresión de base 7 o compresión de base 4 y el aumento de los valores (con la sobrecarga de bytes asociada con el uso de una nilad adicional en la cadena) . La descompresión de base 6, en lugar de 7, se logra utilizando el hecho de que la descompresión de base (en lugar de la conversión de base b) tiene una construcción de rango implícita cuando es un argumento correcto,r, es un número entero, lo que significa que es como convertir a base ry luego cambiar cualquiera 0a un rtodo de una vez.

Es decir:

         class: Sorcerer,Wizard,Bard,Cleric,Druid,Monk,Rogue,Warlock,Fighter,Paladin,Ranger,Barbarian
   Ordinal sum: 837,     625,   377, 594,   504,  405, 514,  723,    713,    697,    607,   898
        mod 15:  12,      10,     2,   9,     9,    0,   4,    3,      8,      7,      7,    13
required value:   3,       3,     4,   4,     4,    4,   4,    4,      5,      5,      5,     6

Reorganizando a la lista, convirtiendo el 6 en el índice 13 a cero y haciéndolo mínimo en la base 6:

mod 15:    2   3   4           7   8   9  10      12  13      0  
 value: 1, 4,  4,  4,  0,  0,  5,  5,  4,  3,  0,  3,  0,  0,  4

Haciendo el código

                list: [1,4,4,4,0,0,5,5,4,3,0,3,0,0,4]
         from base 6: 140775266092
         to base 250: [36,9,154,64,92]
code page characters:   # ®   Ʋ  ?  [
          final code: “#®Ʋ?[’ṃ6
Jonathan Allan
fuente
8

JavaScript (ES6), 81 78 76 74 bytes

Toma datos como (clase, nivel, constitution_ability_score) . La clase no distingue entre mayúsculas y minúsculas.

(c,l,s,h=(d=parseInt(c,34)*59.9%97%77%6|4)+(s-10>>1))=>(h>0?h*l:h+l-1)+d-2

Básicamente, esto usa las mismas matemáticas que mi versión inicial, pero d ahora se calcula sin ninguna tabla de búsqueda.

Casos de prueba


Versión inicial, 87 84 bytes

(c,l,s,h=(d=+'55654607554506'[parseInt(c,35)%24%15])+(s-10>>1))=>(h>0?h*l:h+l-1)+d-2

Cómo funciona

La parte difícil es convertir la cadena de clase c en los dados de golpe correspondientes. Más precisamente, el valor que vamos a almacenar es d = dados / 2 + 1 .

Usamos la fórmula parseInt(c, 35) % 24 % 15que da:

Class       | Base 35 -> decimal | MOD 24 | MOD 15 | d
------------+--------------------+--------+--------+---
"Sorcerer"  |      1847055419467 |     19 |      4 | 4
"Wizard"    |               1138 |     10 |     10 | 4
"Bard"      |             484833 |      9 |      9 | 5
"Cleric"    |          662409592 |     16 |      1 | 5
"Druid"     |           20703143 |     23 |      8 | 5
"Monk"      |             973475 |     11 |     11 | 5
"Rogue"     |           41566539 |      3 |      3 | 5
"Warlock"   |        59391165840 |      0 |      0 | 5
"Fighter"   |        28544153042 |      2 |      2 | 6
"Paladin"   |        46513817828 |     20 |      5 | 6
"Ranger"    |         1434103117 |     13 |     13 | 6
"Barbarian" |     25464249364423 |      7 |      7 | 7

Al insertar los valores de d en las posiciones correspondientes en una cadena y rellenar las ranuras no utilizadas con ceros, obtenemos:

00000000001111
01234567890123
--------------
55654607554506

De ahí la fórmula final:

d = +'55654607554506'[parseInt(c, 35) % 24 % 15]

Una vez que tenemos d , calculamos:

h = d + ((s - 10) >> 1))

cuál es el número teórico de puntos que se ganan en cada nivel.

Si h es positivo, simplemente calculamos:

h * l

Si no, debemos tener en cuenta el hecho de que se gana al menos 1 punto en cada nivel. Entonces calculamos en su lugar:

h + l - 1

En ambos casos, ajustamos el resultado agregando d - 2 , para que el número inicial de puntos se integre correctamente.

Casos de prueba

Arnauld
fuente
Algo parece estar mal con su código; Los bardos con un CON de 1 o los magos con un CON de 2 o 3 obtienen el mismo número de puntos de golpe, sea cual sea su nivel.
Neil
1
@Neil Gracias por notarlo. Creo que esto está arreglado.
Arnauld
3

Lote, 172 bytes

@set/aa=1-%3/2,h=4-a
@for %%c in (-1.Sorcerer -1.Wizard 1.Fighter 1.Paladin 1.Ranger 2.Barbarian)do @if %%~xc==.%1 set/aa-=c=%%~nc,h+=c*2
@cmd/cset/a"a*=(a>>9),-~a*~-%2+h

Toma clase, nivel y constitución como argumentos de línea de comandos. Explicación: El HP se puede calcular como (HP en el nivel 1) + (nivel - 1) + min (más HP por nivel, 0) * (nivel - 1). El HP adicional por nivel es la mitad del dado de golpe más el modificador de constitución. La mayoría de las clases usan d8, por lo que esto se convierte en uno menos de la mitad de la constitución ( %3/2-1), mientras que el HP en el nivel 1 es 3 más que eso. Los HP adicionales por nivel y HP en el nivel 1 se ajustan para las seis clases que no usan d8. El HP adicional por nivel se limita a 0 (esto en realidad usa el valor negativo ya que es un poco más golfista de esta manera).

Neil
fuente
2

R, 181 163 bytes

function(s,n,t){a=Hmisc::Cs(rc,za,rd,er,ui,mk,gu,rl,gh,la,ng,rb)
b=c(6,6,rep(8,6),rep(10,3),12)
d=b[a == substr(s,3,4)]
m=floor((t-10)/2)
d+m+(n-1)*max(d/2+1+m,1)}

Función anónima. Corre como f(class, level, CON).

Explicación: Crea vectores para que la clase sapunte al máximo d, usando las letras tercera y cuarta en el nombre de la clase (el mapeo único más pequeño que encontré).

CON mod mes directo de la especificación, y HP = primer nivel ( d + m) + el resto de los niveles ( (n-1) * max(average_die + m, 1).

> f("Barbarian", 15, 13)
[1] 125
> f("Rogue", 10, 18)
[1] 93
> f("Wizard", 15, 18)
[1] 122
> f("Wizard", 16, 1)
[1] 16
> f("Barbarian", 15, 7)
[1] 80
> f("Warlock", 15, 3)
[1] 18
> f("Ranger", 14, 1)
[1] 18
BLT
fuente