# comparing fomula

Anyone know of a foundry utility to compare two strings that might be dice formulae to tell which has the lesser deterministic value?
23 Replies
Calegoâ€¢2y ago
ðŸ§µ use case: I have two strings that - might just be numbers ('3' and '4') - might be simple formula ('3 + 3' and '4') - might be nonDeterministic formula ('3 + 1d4' and '4') I want to know: - if both are deterministic formula, what is the `Floor` of their values - if they aren't deterministic, I'll do nothing with either value oh i can use dnd5e's `simplifyRollFormula` for this if the output of `simplifyRollFormula` is parsable as a `Number`, I can compare them easily
Calegoâ€¢2y ago
ok wtf js
Calegoâ€¢2y ago
oh, i'm dumb. `.floor` is for rounding I'm looking for `.min` this is definitely excessive...
``    const { abilities, attributes, bonuses, details } = this.actor.system;    let spellAttackModFormula = [      new Intl.NumberFormat('en-US', {        signDisplay: 'exceptZero',      })        .format((abilities[attributes.spellcasting || 'int']?.mod ?? 0) + attributes.prof)        .toString(),    ];    // apply the bonuses if they are equivalent    if (bonuses.msak.attack === bonuses.rsak.attack) {      spellAttackModFormula.push(bonuses.msak.attack);      // apply the lesser deterministic bonus    } else if (!!bonuses.msak.attack && !!bonuses.rsak.attack) {      const lesserBonus = Math.min(        dnd5e.dice.simplifyRollFormula(bonuses.msak.attack),        dnd5e.dice.simplifyRollFormula(bonuses.rsak.attack)      );      // if lesserBonus is a number, push it to the spellAttackModFormula      if (!Number.isNaN(lesserBonus)) {        spellAttackModFormula.push(lesserBonus);      }    }    sheetData.spellAttackMod =      spellAttackModFormula.length === 1        ? spellAttackModFormula[0]        : dnd5e.dice.simplifyRollFormula(spellAttackModFormula.join(' + '));``
``    const { abilities, attributes, bonuses, details } = this.actor.system;    let spellAttackModFormula = [      new Intl.NumberFormat('en-US', {        signDisplay: 'exceptZero',      })        .format((abilities[attributes.spellcasting || 'int']?.mod ?? 0) + attributes.prof)        .toString(),    ];    // apply the bonuses if they are equivalent    if (bonuses.msak.attack === bonuses.rsak.attack) {      spellAttackModFormula.push(bonuses.msak.attack);      // apply the lesser deterministic bonus    } else if (!!bonuses.msak.attack && !!bonuses.rsak.attack) {      const lesserBonus = Math.min(        dnd5e.dice.simplifyRollFormula(bonuses.msak.attack),        dnd5e.dice.simplifyRollFormula(bonuses.rsak.attack)      );      // if lesserBonus is a number, push it to the spellAttackModFormula      if (!Number.isNaN(lesserBonus)) {        spellAttackModFormula.push(lesserBonus);      }    }    sheetData.spellAttackMod =      spellAttackModFormula.length === 1        ? spellAttackModFormula[0]        : dnd5e.dice.simplifyRollFormula(spellAttackModFormula.join(' + '));``
BUT it does do what I was looking for and covers all the edge cases I can think of Most of the time I know of, if there's a bonus, it'll be adding to both `msak` and `rsak` to represent a global increase but the data does support disparate mods, in which case, applying the lesser one is 'safe' to this display of 'spell attack modifier'
Manaâ€¢2y ago
`.evaluate({min:true, async:false})` doesn't work for you? Or did I misunderstand what you were after?
Calegoâ€¢2y ago
is that a method on `Roll`?
Manaâ€¢2y ago
Yes.
Calegoâ€¢2y ago
`min` would return the minimum possible based on the formula provided?
Manaâ€¢2y ago
Yes. It sets the dice to minimum value they'd give instead of randomizing them and returns the result.
Calegoâ€¢2y ago
gotcha, not quite what i'm looking for I'm really looking to compare two formulas, and use the 'min' one (but only if they're deterministic)
Manaâ€¢2y ago
Roll.isDeterministic is a thing It also exists for individual terms. That is available pre-eval
Calegoâ€¢2y ago
so the alternative to using the dnd5e `simplifyRollFormula` would look something like :
``const formulaA = new Roll(bonuses.msak.attack);const formulaB = new Roll(bonuses.rsak.attack);if (formulaA.isDeterministic() && formulaB.isDeterministic()) {  spellAttackModFormula.push(    Math.min(formulaA.evaluate(), formulaB.evaluate());  );}``
``const formulaA = new Roll(bonuses.msak.attack);const formulaB = new Roll(bonuses.rsak.attack);if (formulaA.isDeterministic() && formulaB.isDeterministic()) {  spellAttackModFormula.push(    Math.min(formulaA.evaluate(), formulaB.evaluate());  );}``
Manaâ€¢2y ago
Almost, .isDeterministic is a getter. And .evaluate() returns Roll instance, so you'd need to add .total there. Also eval is async unless you tell it to be non-async.
Calegoâ€¢2y ago
that `async:false` is being deprecated right? I could probably DIY that actually if `isDeterministic` is true jk not as easy i expected in js
Manaâ€¢2y ago
People keep saying it's not. The requirement for it is, because async is becoming the default. And there's no warning in it that sync option is going away, just that it won't be the default.
Calegoâ€¢2y ago
goootcha
Manaâ€¢2y ago
Anyway, you'd have this:
``if (formulaA.isDeterministic && formulaB.isDeterministic) {  spellAttackModFormula.push(    Math.min(formulaA.evaluate({async:false}).total, formulaB.evaluate({async:false}.total));  );}``
``if (formulaA.isDeterministic && formulaB.isDeterministic) {  spellAttackModFormula.push(    Math.min(formulaA.evaluate({async:false}).total, formulaB.evaluate({async:false}.total));  );}``
Calegoâ€¢2y ago
so then the question i have is 'is the overhead of creating two `Roll`s to compare these strings greater than or less than using `simplifyRollFormula`?' odds are, less than, simplifyRollFormula is a heavy function now that I look closer
Manaâ€¢2y ago
I'd favor whichever makes the intent of the code clearer.
Calegoâ€¢2y ago
``    // apply the bonuses if they are equivalent    if (bonuses.msak.attack === bonuses.rsak.attack) {      spellAttackModFormula.push(bonuses.msak.attack);    } else if (!!bonuses.msak.attack && !!bonuses.rsak.attack) {      const formulaA = new Roll(bonuses.msak.attack);      const formulaB = new Roll(bonuses.rsak.attack);      // apply the lesser deterministic bonus      if (formulaA.isDeterministic && formulaB.isDeterministic) {        spellAttackModFormula.push(          Math.min(formulaA.evaluate({ async: false }).total, formulaB.evaluate({ async: false }.total))        );      }    }``
``    // apply the bonuses if they are equivalent    if (bonuses.msak.attack === bonuses.rsak.attack) {      spellAttackModFormula.push(bonuses.msak.attack);    } else if (!!bonuses.msak.attack && !!bonuses.rsak.attack) {      const formulaA = new Roll(bonuses.msak.attack);      const formulaB = new Roll(bonuses.rsak.attack);      // apply the lesser deterministic bonus      if (formulaA.isDeterministic && formulaB.isDeterministic) {        spellAttackModFormula.push(          Math.min(formulaA.evaluate({ async: false }).total, formulaB.evaluate({ async: false }.total))        );      }    }``
suspect this will never be clear ðŸ˜› but this is a solidly simpler solution and doesn't rely on 5e code thanks @manaflower
Leo The League Lionâ€¢2y ago
@calego gave LeaguePointsâ„¢ to @manaflower (#15 â€¢ 203)
Calegoâ€¢2y ago
ðŸŽ‰
Unknown Userâ€¢2y ago
Message Not Public
Sign In & Join Server To View
Calegoâ€¢2y ago
External constraint, could be a simple formula like "+1 +1 +2"