Calculadora HP D&D 5e

11

Tenho dificuldade em lembrar de tudo o que tenho que fazer ao subir de nível um personagem de D&D. Por qualquer motivo, uma das coisas que me causa problemas é descobrir qual deve ser o novo valor máximo da HP. Para esse desafio, você escreverá um programa ou função para calcular o valor correto automaticamente.

Terminologia

A primeira coisa que você precisa saber para calcular o HP máximo é o "modificador de Constituição". Cada caractere DND possui seis pontuações de habilidades inteiras, incluindo uma para Constituição. O único conhecimento relevante necessário para esse desafio é como a pontuação da habilidade de Constituição afeta outra estatística, que é o modificador de Constituição. Em resumo, o modificador é igual a floor( (ability_score - 10) / 2 ). Os aventureiros só podem ter notas de habilidade de 1 a 20, inclusive. Seu código nunca precisará lidar com pontuações fora desse intervalo, o que também significa que nunca precisará lidar com um modificador menor que -5 ou maior que +5. Embora o modificador de Constituição possa mudar à medida que o caractere sobe de nível, seus efeitos sobre a HP são aplicados retroativamente, portanto, apenas seu valor atual é necessário para calcular o máximo de HP atual.

(Isso é totalmente irrelevante para o desafio, mas se você estiver curioso sobre como isso afeta o HP máximo: Você pode assumir que o talento "Difícil" adiciona 2 ao modificador de Constituição de um personagem para fins de cálculo da HP, pois é efetivamente o que ele faz Esse não é o texto da façanha, mas a matemática é exatamente a mesma. Você não precisa lidar com essa façanha na sua resposta.)

Em seguida, toda classe tem um tipo de "dado de batida" atribuído, envolvido no cálculo da HP. A tabela a seguir lista os dados de acerto para cada classe.

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, o nível do personagem. Tudo o que isso afeta é quantas vezes adicionar um valor ao total em execução na seção a seguir. O nível de um personagem é um número inteiro de 1 a 20, inclusive 1 . Seu código nunca precisará lidar com um nível fora desse intervalo. Para atingir o nível n, um personagem começa no nível 1 e sobe de nível n-1. Por exemplo, um personagem de nível 3 chegou onde está sendo um personagem de nível 1 e subiu de nível duas vezes.

Como calcular o HP máximo

O HP máximo de um personagem é igual ao HP no nível 1 mais a soma do aumento que eles receberam em cada nível.

No nível 1

No nível 1, o HP de um personagem é igual à maior jogada possível no seu dado de acerto (o número no nome do dado, para aqueles que não estão familiarizados com dados com mais de 6 lados) mais o modificador de Constituição. Lembre-se de que, ao calcular o HP em um nível posterior, você pode assumir que a Constituição de um personagem sempre foi a mesma, pois essa parte do cálculo é repetida toda vez que a Constituição for alterada.

Ao subir de nível

Toda vez que um personagem sobe de nível, ele tem duas opções. Eles podem rolar um de seus dados de vida ou fazer o lançamento médio desse dado (arredondado para cima). Qualquer que seja a sua escolha, seu modificador de Constituição é adicionado ao resultado. Esse total é a quantia que o HP deles aumenta. Para esse desafio, o rolo médio é sempre obtido, portanto a produção é determinística. (Novamente, se você não estiver familiarizado com> dados de 6 lados, poderá calcular a média da rolagem arredondada como (highest_possible_roll / 2) + 1.)

Há uma exceção notável. O HP máximo de um personagem sempre aumenta em pelo menos 1 cada vez que ele aumenta de nível 2 . Se as instruções no parágrafo acima resultarem em um aumento de 0 ou menos ao subir de nível, ele aumentará em 1.

O desafio

Seu programa ou função terá três entradas :

  • A classe do personagem, como uma string
  • O nível do personagem
  • A pontuação de habilidade de Constituição do personagem ( não modificador)

Ele produzirá apenas uma coisa: o HP máximo atual do personagem.

Exemplos

Todas as combinações possíveis de entradas e saídas associadas podem ser encontradas neste link. Para ter algo para ver nesta página, aqui estão 30 casos de teste escolhidos aleatoriamente:

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. A rigor, não acho que exista uma regra que diga que 20 é o nível máximo. No entanto, 21 é o ponto em que deixa de haver tabelas no livro para dizer quais devem ser alguns dos vários números das regras, incluindo a quantidade de experiência necessária para alcançá-lo. Esse é um limite de nível bom o suficiente para mim.

2. Na verdade, não acho que isso seja verdade com o RAW. Eu perguntei no rpg.se e tal coisa não parece estar escrita em lugar algum. No entanto, Mike Mearls, designer-chefe de D&D, twittou em março de 2015 . Isso não é autoritário da maneira que você poderia argumentar com um tweet do desenvolvedor de regras líder Jeremy Crawford, mas é uma evidência de que é o que eles pretendiam, então eu o usarei para esse desafio.

undergroundmonorail
fonte
A classe precisa ser dada como uma string ou o número do dado de acerto, uma vez que essa é a única informação relevante para uma classe. Caso contrário, as pessoas só vai precisar de uma mesa genérico de "Se essas classes, então este morrer, se essas classes então este die" etc.
Skidsdev
Também o nível e a constituição são passados ​​como números inteiros ou como strings dizendo "xthth level" e "y CON"?
Skidsdev
1
Puxa, eu estou velho, eu ainda me lembro desta tabela: ancientscrossroads.com/adnd_tools/con_table.htm
Neil
@ Mayube Provavelmente não deveria ter feito uma pergunta e imediatamente saiu para comer pizza, hein? : P A classe deve ser uma string, porque acho que há dados suficientes nessas strings para encontrar padrões para encurtar a tabela (que parece ser o caso, com base nas respostas que chegaram até agora). Nível e constituição são ints.
Undergroundmonorail
3
Achei muito difícil analisar as informações relevantes de todas as informações sendo lançadas para mim.
Jonathan Allan

Respostas:

2

Geléia , 34 bytes

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

Programa completo com três argumentos de linha de comando: classe, pontuação, nível.

Experimente online!

Quão?

O meio do código, separado por ðs, é um link diádico que calcula o resultado de alguns valores calculados anteriormente:

+‘»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

O modificador é calculado no lado direito:

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

Metade do valor do dado é calculado no lado esquerdo:

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)

Considerando as somas ordinais do módulo de nomes de classe m, isso mé mínimo e, ao mesmo tempo, impede que as classificações (por matriz) colidam os rendimentos m=15. Colocar os valores necessários (rolo de meia matriz) nesses índices em uma lista de comprimento 15 permite a pesquisa usando a indexação modular da Jelly com . A compactação da lista como um número 6 base com o único 6substituído por a 0é um byte mais curto que as alternativas de compactação na base 7 ou na compactação na base 4 e aumentando os valores (com a sobrecarga de bytes associada ao uso de um nilad extra na cadeia) . A descompressão base 6, em vez de 7, é obtida usando o fato de que a descompressão base (em vez da conversão base b) tem construção implícita de intervalo quando é o argumento correto,r, é um número inteiro, o que significa que é como converter para base re depois alterar qualquer 0um para um de uma rsó vez.

Isso é:

         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 lista, convertendo o 6 no índice 13 para zero e tornando-o mínimo na 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

Fazendo o 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
fonte
8

JavaScript (ES6), 81 78 76 74 bytes

Recebe entrada como (classe, nível, constitution_ability_score) . A classe não diferencia maiúsculas de 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

Isso é essencialmente usando a mesma matemática da minha versão inicial, mas d agora é calculado sem nenhuma tabela de pesquisa.

Casos de teste


Versão 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

Como funciona

A parte complicada é converter a string de classe c nos dados de acerto correspondentes. Mais precisamente, o valor que vamos armazenar é d = dice / 2 + 1 .

Usamos a fórmula parseInt(c, 35) % 24 % 15que fornece:

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

Inserindo os valores de d nas posições correspondentes em uma string e preenchendo slots não utilizados com zeros, obtemos:

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

Daí a fórmula final:

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

Depois de termos d , calculamos:

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

que é o número teórico de pontos ganhos em cada nível.

Se h for positivo, simplesmente calculamos:

h * l

Caso contrário, precisamos levar em consideração o fato de que pelo menos 1 ponto é ganho em cada nível. Então calculamos:

h + l - 1

Nos dois casos, ajustamos o resultado adicionando d - 2 , para que o número inicial de pontos seja corretamente integrado.

Casos de teste

Arnauld
fonte
Algo parece estar errado com seu código; Bardos com um CON de 1 ou Wizards com um CON de 2 ou 3 obtêm o mesmo número de pontos de vida, independentemente do seu nível.
Neil
1
@ Neil Obrigado por perceber. Eu acho que isso está resolvido.
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

Recebe classe, nível e constituição como argumentos da linha de comando. Explicação: O HP pode ser calculado como (HP no nível 1) + (nível - 1) + min (HP adicional por nível, 0) * (nível - 1). O HP adicional por nível é metade da matriz de acerto mais o modificador de constituição. A maioria das classes usa d8, então isso se torna um a menos da metade da constituição ( %3/2-1), enquanto o HP no nível 1 é 3 a mais que isso. O HP adicional por nível e o HP no nível 1 são então ajustados para as seis classes que não usam o d8. O HP adicional por nível é então limitado a 0 (na verdade, ele usa o valor negativo, pois é um pouco mais golfista dessa maneira).

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

Função anônima. Executa como f(class, level, CON).

Explicação: Cria vetores para a classe sdividir no máximo d, usando a 3ª e a 4ª letras no nome da classe (menor mapeamento exclusivo que encontrei).

O mod CON mé direto da especificação e HP = primeiro nível ( d + m) + o restante dos níveis ( (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
fonte