naturalcrit / homebrewery

Create authentic looking D&D homebrews using only markdown
https://homebrewery.naturalcrit.com
MIT License
1.07k stars 327 forks source link

Enable `sign` and `abs` math functions #3537

Closed Gazook89 closed 1 month ago

Gazook89 commented 3 months ago

Your idea:

A discord user would like to have the sign and abs functions enabled in our Math parser. Because I'm not super familiar with that part of the repo, I'll keep it simple:

From user:

Is there a way to include a "sign" function? That is, something like $[sign(3)] that would return "+"

If they need a reason for both abs and sign, it comes from computing any modifier. The abs is needed to get the base number and the sign is needed to apply the sign.

$[StrSign]$[StrAbs]

If the modifier is negative and the abs function isn't available, this would return "--2".

Relevant code: https://github.com/naturalcrit/homebrewery/blob/master/shared/naturalcrit/markdown.js

Relevant Discord conversation: https://discord.com/channels/113801089362558983/950919905266507806/1252624469114097756

G-Ambatte commented 3 months ago

I had a (very) quick stab at this before I had to run out to work this morning, this is the modification to markdown.js that I came up with:

const mathParser = new MathParser({
    operators : {
        // These default to true, but are included to be explicit
        add      : true,
        subtract : true,
        multiply : true,
        divide   : true,
        power    : true,
        round    : true,
        floor    : true,
        ceil     : true,
        abs      : true,

        sin     : false, cos     : false, tan     : false, asin    : false, acos    : false,
        atan    : false, sinh    : false, cosh    : false, tanh    : false, asinh   : false,
        acosh   : false, atanh   : false, sqrt    : false, cbrt    : false, log     : false,
        log2    : false, ln      : false, lg      : false, log10   : false, expm1   : false,
        log1p   : false, trunc   : false, join    : false, sum     : false,
        '-'     : false, '+'     : false, exp     : false, not     : false, length  : false,
        '!'     : false, sign    : false, random  : false, fac     : false, min     : false,
        max     : false, hypot   : false, pyt     : false, pow     : false, atan2   : false,
        'if'    : false, gamma   : false, roundTo : false, map     : false, fold    : false,
        filter  : false, indexOf : false,

        remainder   : false, factorial   : false,
        comparison  : false, concatenate : false,
        logical     : false, assignment  : false,
        array       : false, fndef       : false
    }
});
mathParser.functions.sign = function (a) {
    if(a == 0) return null;
    if(a > 0) {
        return '+';
    } else {
        return '\\-';
    }
};

I was not having any luck getting abs() to actually function in a brew, even after enabling it. image

On further thought, I believe we could also (or instead) include a signed function that returns the input value as a string with a +/- prefix:

mathParser.functions.signed = function (a) {
    if(a >= 0) {
        return `+${a}`;
    } else {
        return `\\${a}`;
    }
};

(NB: the negative prefix needs to be \\- or else it will be treated as the start of a list when used at the beginning of a line; I have not yet determined any scenarios that require the positive prefix to be handled similarly)

G-Ambatte commented 3 months ago

Looks like the variable hasn't been resolved to the value at the time that the function runs:

image

G-Ambatte commented 3 months ago

signed works pretty well in it's current iteration: image