D&D 5e HP计算器


11

我很难记住升级D&D角色时要做的一切。无论出于什么原因,给我带来麻烦的事情之一就是弄清楚它们的新最大HP值应该是多少。为应对这一挑战,您将编写一个程序或函数来自动计算正确的值。

术语

要计算最大HP,您需要了解的第一件事是“宪法修改器”。每个DND角色都有六个整数能力得分,其中一个是体质得分。这项挑战所需的唯一相关知识是宪法能力得分如何影响另一个属性,即宪法修正。简而言之,修饰符等于floor( (ability_score - 10) / 2 )。冒险者只能获得1到20(含)之间的能力得分。您的代码将永远不必处理超出该范围的分数,这也意味着它将永远不必处理小于-5或大于+5的修饰符。尽管“体质”修改器可以随着角色升级而改变,但它对HP的影响会追溯应用,因此仅需要其当前值即可计算当前的最大HP。

(这与挑战完全无关,但是如果您对它如何影响最大HP感到好奇:您可以假设“强壮”专长在角色的体质修改器中增加2,以进行HP计算,因为这实际上是它的作用这不是专长的文字,但数学公式完全相同。您不必在回答中处理此专长。)

接下来,每个类别都有一个分配的“命中失败”类型,该类型涉及计算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级角色并升级两次而达到了他们所在的位置。

如何计算最大生命值

角色的最大生命值等于其在等级1处的生命值加上在每个等级中获得的增加值之和。

1级

在等级1上,角色的HP等于其命中骰子上的最高掷骰数(骰子名称中的数字,对于不熟悉骰子且面数多于6的那些人)加上其体质修改器。请记住,在以后计算HP时,您可能会假定角色的体质始终是相同的,因为每次更改体质时都会重新计算此部分。

升级时

每次角色升级时,都有两个选择。他们可以掷一个命中骰子,也可以掷该骰子的平均骰子(四舍五入)。无论选择哪种方法,都会将其“宪法”修改器添加到结果中。这个总数就是他们的HP增加的数量。对于此挑战,始终采用平均滚动,因此输出是确定性的。(同样,如果您不熟悉> 6面骰子,则可以将向上舍入的平均掷骰计算为(highest_possible_roll / 2) + 1。)

有一个值得注意的例外。角色每次升级2时,其最大HP总是至少增加1 。如果上段中的说明在升级时导致增加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上问,这样的事情似乎在任何地方都没有写下来。但是,D&D的首席设计师Mike Mearls 在2015年3月发布了推文。您不能以这种方式来争辩主要规则开发人员Jeremy Crawford的推文,但有证据表明这正是他们的意图,因此我将其用于挑战。


鉴于类是唯一相关的信息,所以必须将类指定为字符串,还是可以将其指定为命中模具的编号。否则,人们将只需要一个通用表“如果这些类会死,如果这些类便死”等
。– Skidsdev,2017年

还可以将级别和构造作为整数或表示“ xth level”和“ y CON”的字符串传递吗?
Skidsdev

1
天哪,我老了,我还记得这张桌子:Ancientscrossroads.com/adnd_tools/con_table.htm
Neil

@Mayube大概不应该问一个问题,马上出去吃披萨吧?:P该类必须是一个字符串,因为我认为这些字符串中有足够的数据来查找缩短表的模式(根据迄今为止的答案,情况似乎如此)。等级和体质是整数。
地下

3
我发现很难从扔给我的所有信息中解析出相关信息。
乔纳森·艾伦

Answers:


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为基数的数字,用lone 6代替a 0的字节比基7压缩或基4压缩的替代方案短并增加值(字节开销与在链中使用额外的nilad相关) 。底数为6而不是7的解压缩是通过使用以下事实来实现的:当它是正确的参数时,底子解压缩(而不是基数转换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

重新排列列表,将索引13处的6转换为零,并使其以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字节

将输入作为(class,level,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来调整结果,以便正确积分初始点数。

测试用例


您的代码似乎有问题;CON值为1的吟游诗人或CON值为2或3的巫师无论其等级如何都获得相同数量的生命值。
尼尔

1
@Neil感谢您的关注。我认为这是固定的。
Arnauld

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可以计算为(等级1的HP)+(等级-1)+分钟(每个等级的进一步HP,0)*(等级-1)。每个等级的生命值加成是命中值加上构造修正值的一半。大多数班级都使用d8,因此这成为构成(%3/2-1)的一半以下,而等级1的HP则比其高3。然后针对不使用d8的六个类别调整每个级别的其他HP和级​​别1的HP。然后将每个级别的更多HP限制为0(这实际上使用负值,因为这样会稍微偏高)。


2

R,181163字节

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)

说明:使用类名中的第3和第4个字母(我找到的最小的唯一映射),为类创建矢量以s将max切成小方块d

CON mod 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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.