D & D 5e HP Calculator

11

У меня проблемы с запоминанием всего, что я должен делать при прокачке персонажа D & D. По какой-то причине одна из вещей, которая доставляет мне неприятности, - это выяснить, каким должно быть их новое максимальное значение HP. Для этой задачи вы напишите программу или функцию для автоматического вычисления правильного значения.

терминология

Первое, что вам нужно знать о том, как рассчитать максимальное количество здоровья, - это «модификатор Конституции». Каждый персонаж DND имеет шесть целочисленных показателей способностей, в том числе один для Телосложения. Единственное релевантное знание, необходимое для этого задания, - это то, как показатель способности Телосложения влияет на другой показатель, который является модификатором Телосложения. Короче, модификатор равен floor( (ability_score - 10) / 2 ). Авантюристы могут иметь очки способностей от 1 до 20 включительно. Вашему коду никогда не придется обрабатывать оценки за пределами этого диапазона, что также означает, что ему никогда не придется обрабатывать модификатор ниже -5 или больше +5. Хотя модификатор Телосложения может меняться по мере повышения уровня персонажа, его эффекты на HP применяются задним числом, поэтому для вычисления текущего максимального HP необходимо только его текущее значение.

(Это не имеет никакого отношения к задаче, но если вам интересно, как она влияет на максимальный HP: вы можете предположить, что умение «Крепкий» добавляет 2 к модификатору Телосложения персонажа для целей расчета HP, поскольку это фактически то, что он делает. Это не текст подвига, но математика получается точно такой же. Вам не нужно обрабатывать этот подвиг в своем ответе.)

Затем каждому классу присваивается тип «Hit Die», который участвует в расчете HP. В следующей таблице перечислены хит-кости для каждого класса.

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

Наконец, уровень персонажа. Все, на что это влияет, - это сколько раз добавить значение к промежуточной сумме в следующем разделе. Уровень персонажа - это целое число от 1 до 20, включительно 1 . Ваш код никогда не будет обрабатывать уровень за пределами этого диапазона. Чтобы достичь уровня n, персонаж начинает с уровня 1 и поднимается до уровня n-1. Например, персонаж уровня 3 достиг того места, где он находится, будучи персонажем уровня 1 и повышая уровень в два раза.

Как рассчитать максимальный HP

Максимальная HP персонажа равна его HP на уровне 1 плюс сумма увеличения, которое они получают на каждом уровне.

На уровне 1

На уровне 1, HP персонажа равняется наибольшему возможному броску на его хит-кубе (число в названии кубика для тех из вас, кто не знаком с кубиками, у которых больше 6 сторон) плюс их модификатор Телосложения. Помните, что при расчете HP на более позднем уровне вы можете предположить, что конституция персонажа всегда была одинаковой, так как эта часть вычисления выполняется заново каждый раз, когда изменяется Конституция.

При повышении уровня

Каждый раз, когда персонаж повышается, у него есть два варианта. Они могут либо бросить один из своих кубиков, либо взять средний бросок этого кубика (округленный в большую сторону). Что бы они ни выбрали, их модификатор Конституции добавляется к результату. Это общее количество, которое увеличивает их HP. Для этой задачи всегда используется средний бросок, поэтому результат является детерминированным. (Опять же, если вы не знакомы с> шестигранными кубиками, вы можете рассчитать округленный до среднего бросок как (highest_possible_roll / 2) + 1.)

Есть одно заметное исключение. Максимальное здоровье персонажа всегда увеличивается как минимум на 1 при каждом повышении уровня до 2 . Если инструкции в вышеприведенном абзаце приведут к увеличению на 0 или меньше при повышении уровня, вместо этого оно увеличивается на 1.

Соревнование

Ваша программа или функция будет принимать три входа :

  • Класс персонажа в виде строки
  • Уровень персонажа
  • Оценка способностей персонажа ( не модификатор)

Это будет выход только одно: текущий максимум HP персонажа.

Примеры

Всю возможную комбинацию входов и связанных с ними выходов можно найти по этой ссылке. Ради того, чтобы что-то посмотреть на этой странице, мы выбрали случайные 30 тестов:

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. Строго говоря, я не думаю, что есть правило, согласно которому 20 - это максимальный уровень. Однако 21 - это точка, в которой перестают быть таблицы в книге, чтобы сказать вам, какими должны быть некоторые из чисел в правилах, включая количество опыта, которое вам нужно получить, чтобы достичь его. Это достаточно хороший уровень для меня.

2. Я на самом деле не думаю, что это правда с RAW. Я спросил на rpg.se, и такая вещь, кажется, нигде не записана. Однако Mike Mearls, ведущий дизайнер D & D, написал это в марте 2015 года . Это не является авторитетным способом, которым вы могли бы поспорить с твиттером от ведущего разработчика правил Джереми Кроуфорда, но это доказательство того, что они и хотели, поэтому я буду использовать его для этой задачи.

undergroundmonorail
источник
Должен ли класс быть задан в виде строки, или же он может быть задан как номер метки, если это единственная релевантная информация для класса. В противном случае людям просто понадобится общая таблица «Если эти классы умрут, если эти классы умрут» и т. Д.
Skidsdev
Кроме того, уровень и конституция передаются как целые числа или как строки, говорящие "xth level" и "y CON"?
Скидсдев
1
Черт возьми, я старый, я до сих пор помню эту таблицу: ancientscrossroads.com/adnd_tools/con_table.htm
Нил
@ Mayub Наверное, не следовало задавать вопрос и сразу же пойти на пиццу, а? : P Класс должен быть строкой, потому что я думаю, что в этих строках достаточно данных, чтобы найти шаблоны для укорачивания таблицы (что, похоже, так и есть, основываясь на ответах, которые были до сих пор). Уровень и конституция являются целыми.
подземный
3
Мне было довольно сложно разобрать соответствующую информацию из всей информации, которую мне бросают.
Джонатан Аллан

Ответы:

2

Желе , 34 байта

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

Полная программа, принимающая три аргумента командной строки: класс, оценка, уровень.

Попробуйте онлайн!

Как?

Середина кода, разделенная символом ðs, представляет собой двоичную ссылку, которая вычисляет результат по некоторым ранее вычисленным значениям:

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

Модификатор рассчитывается с правой стороны:

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

Половина значения матрицы рассчитывается с левой стороны:

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)

Рассматривая порядковые суммы имен классов по модулю так m, чтобы они были mминимальными при сохранении классификаций (по кубикам) от встречных выходов m=15. Помещение требуемых значений (бросок на половину матрицы) в эти индексы в списке длиной 15 позволяет осуществлять поиск с использованием модульной индексации Jelly с . Сжатие списка в виде числа базы 6 с 6заменой единственного числа на a 0на байт короче, чем альтернативы сжатия base-7 или base-4 и увеличения значений (с использованием байтовых издержек, связанных с использованием дополнительной nilad в цепочке) , Декомпрессия base 6, а не 7, достигается тем, что декомпрессия base (вместо базового преобразования b) имеет неявную конструкцию диапазона, когда это правильный аргумент,r, является целым числом, что означает, что это все равно, что преобразовать в базу, rа затем заменить любой 0на rвсе сразу.

Это:

         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

Переставляем список, конвертируем 6 в индексе 13 в ноль и делаем его минимальным в базе 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

Создание кода

                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
Джонатан Аллан
источник
8

JavaScript (ES6), 81 78 76 74 байта

Принимает ввод как (класс, уровень, constitution_ability_score) . Класс нечувствителен к регистру.

(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

По сути, это та же математика, что и в моей первоначальной версии, но теперь d вычисляется без таблицы поиска.

Контрольные примеры


Начальная версия, 87 84 байта

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

Как это работает

Сложная задача - преобразовать строку класса c в соответствующий кубик попадания. Точнее, значение, которое мы собираемся сохранить, равно d = dice / 2 + 1 .

Мы используем формулу, parseInt(c, 35) % 24 % 15которая дает:

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

Вставляя значения d в соответствующих позициях в строку и дополняя неиспользуемые слоты нулями, мы получаем:

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

Отсюда и окончательная формула:

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

Как только у нас есть d , мы вычисляем:

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

это теоретическое количество очков, которые набираются на каждом уровне.

Если h положительно, мы просто вычисляем:

h * l

Если нет, мы должны принять во внимание тот факт, что по крайней мере 1 очко набирается на каждом уровне. Поэтому вместо этого мы вычисляем:

h + l - 1

В обоих случаях мы корректируем результат, добавляя d - 2 , чтобы начальное количество точек было правильно интегрировано.

Контрольные примеры

Arnauld
источник
Кажется, что-то не так с вашим кодом; Барды с CON 1 или Wizards с CON 2 или 3 получают одинаковое количество очков жизни независимо от их уровня.
Нейл
1
@Neil Спасибо, что заметили. Я думаю, что это исправлено.
Арно
3

Пакет, 172 байта

@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

Принимает класс, уровень и состав в качестве аргументов командной строки. Объяснение: HP можно рассчитать как (HP на уровне 1) + (уровень - 1) + min (далее HP за уровень, 0) * (уровень - 1). Дальнейшее здоровье за ​​уровень составляет половину хитового кубика плюс модификатор конституции. Большинство классов используют d8, так что это становится на половину меньше конституции ( %3/2-1), в то время как HP на уровне 1 на 3 больше, чем это. Далее HP за уровень и HP на уровне 1 затем корректируются для шести классов, которые не используют d8. Дальнейшее количество HP за уровень ограничивается 0 (на самом деле используется отрицательное значение, так как в этом случае он немного сложнее).

Нил
источник
2

R 181 163 байта

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

Анонимная функция. Работает как f(class, level, CON).

Объяснение: Создает векторы для класса sот максимума до кости d, используя 3-ю и 4-ю буквы в имени класса (наименьшее уникальное сопоставление, которое я нашел).

CON мод mпрямо из спецификации, а HP = первый уровень ( d + m) + остальные уровни ( (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
источник