Add support for floor/abs/other math operators
This commit is contained in:
		
							parent
							
								
									fd7bc5f152
								
							
						
					
					
						commit
						ac8602f598
					
				| 
						 | 
				
			
			@ -8,14 +8,14 @@ import config from '../../config.ts';
 | 
			
		|||
 | 
			
		||||
import { RollModifiers } from '../mod.d.ts';
 | 
			
		||||
import { CountDetails, ReturnData, SolvedRoll, SolvedStep } from './solver.d.ts';
 | 
			
		||||
import { compareTotalRolls, compareTotalRollsReverse, escapeCharacters, loggingEnabled } from './rollUtils.ts';
 | 
			
		||||
import { compareTotalRolls, compareTotalRollsReverse, escapeCharacters, legalMathOperators, loggingEnabled } from './rollUtils.ts';
 | 
			
		||||
import { formatRoll } from './rollFormatter.ts';
 | 
			
		||||
import { fullSolver } from './solver.ts';
 | 
			
		||||
 | 
			
		||||
// parseRoll(fullCmd, modifiers)
 | 
			
		||||
// parseRoll handles converting fullCmd into a computer readable format for processing, and finally executes the solving
 | 
			
		||||
export const parseRoll = (fullCmd: string, modifiers: RollModifiers): SolvedRoll => {
 | 
			
		||||
  const operators = ['^', '*', '/', '%', '+', '-', '(', ')'];
 | 
			
		||||
  const operators = ['(', ')', '^', '*', '/', '%', '+', '-'];
 | 
			
		||||
  const returnMsg = <SolvedRoll> {
 | 
			
		||||
    error: false,
 | 
			
		||||
    errorCode: '',
 | 
			
		||||
| 
						 | 
				
			
			@ -78,14 +78,17 @@ export const parseRoll = (fullCmd: string, modifiers: RollModifiers): SolvedRoll
 | 
			
		|||
      // Evaluate all rolls into stepSolve format and all numbers into floats
 | 
			
		||||
      for (let i = 0; i < mathConf.length; i++) {
 | 
			
		||||
        loggingEnabled && log(LT.LOG, `Parsing roll ${fullCmd} | Evaluating rolls into math-able items ${JSON.stringify(mathConf[i])}`);
 | 
			
		||||
        if (mathConf[i].toString().length === 0) {
 | 
			
		||||
 | 
			
		||||
        const strMathConfI = mathConf[i].toString();
 | 
			
		||||
 | 
			
		||||
        if (strMathConfI.length === 0) {
 | 
			
		||||
          // If its an empty string, get it out of here
 | 
			
		||||
          mathConf.splice(i, 1);
 | 
			
		||||
          i--;
 | 
			
		||||
        } else if (mathConf[i] == parseFloat(mathConf[i].toString())) {
 | 
			
		||||
        } else if (mathConf[i] == parseFloat(strMathConfI)) {
 | 
			
		||||
          // If its a number, parse the number out
 | 
			
		||||
          mathConf[i] = parseFloat(mathConf[i].toString());
 | 
			
		||||
        } else if (mathConf[i].toString().toLowerCase() === 'e') {
 | 
			
		||||
          mathConf[i] = parseFloat(strMathConfI);
 | 
			
		||||
        } else if (strMathConfI.toLowerCase() === 'e') {
 | 
			
		||||
          // If the operand is the constant e, create a SolvedStep for it
 | 
			
		||||
          mathConf[i] = {
 | 
			
		||||
            total: Math.E,
 | 
			
		||||
| 
						 | 
				
			
			@ -93,25 +96,21 @@ export const parseRoll = (fullCmd: string, modifiers: RollModifiers): SolvedRoll
 | 
			
		|||
            containsCrit: false,
 | 
			
		||||
            containsFail: false,
 | 
			
		||||
          };
 | 
			
		||||
        } else if (mathConf[i].toString().toLowerCase() === 'fart' || mathConf[i].toString().toLowerCase() === '💩') {
 | 
			
		||||
        } else if (strMathConfI.toLowerCase() === 'fart' || strMathConfI.toLowerCase() === '💩') {
 | 
			
		||||
          mathConf[i] = {
 | 
			
		||||
            total: 7,
 | 
			
		||||
            details: '💩',
 | 
			
		||||
            containsCrit: false,
 | 
			
		||||
            containsFail: false,
 | 
			
		||||
          };
 | 
			
		||||
        } else if (mathConf[i].toString().toLowerCase() === 'sex') {
 | 
			
		||||
        } else if (strMathConfI.toLowerCase() === 'sex') {
 | 
			
		||||
          mathConf[i] = {
 | 
			
		||||
            total: 69,
 | 
			
		||||
            details: '( ͡° ͜ʖ ͡°)',
 | 
			
		||||
            containsCrit: false,
 | 
			
		||||
            containsFail: false,
 | 
			
		||||
          };
 | 
			
		||||
        } else if (
 | 
			
		||||
          mathConf[i].toString().toLowerCase() === 'inf' ||
 | 
			
		||||
          mathConf[i].toString().toLowerCase() === 'infinity' ||
 | 
			
		||||
          mathConf[i].toString().toLowerCase() === '∞'
 | 
			
		||||
        ) {
 | 
			
		||||
        } else if (strMathConfI.toLowerCase() === 'inf' || strMathConfI.toLowerCase() === 'infinity' || strMathConfI.toLowerCase() === '∞') {
 | 
			
		||||
          // If the operand is the constant Infinity, create a SolvedStep for it
 | 
			
		||||
          mathConf[i] = {
 | 
			
		||||
            total: Infinity,
 | 
			
		||||
| 
						 | 
				
			
			@ -119,7 +118,7 @@ export const parseRoll = (fullCmd: string, modifiers: RollModifiers): SolvedRoll
 | 
			
		|||
            containsCrit: false,
 | 
			
		||||
            containsFail: false,
 | 
			
		||||
          };
 | 
			
		||||
        } else if (mathConf[i].toString().toLowerCase() === 'pi' || mathConf[i].toString().toLowerCase() === '𝜋') {
 | 
			
		||||
        } else if (strMathConfI.toLowerCase() === 'pi' || strMathConfI.toLowerCase() === '𝜋') {
 | 
			
		||||
          // If the operand is the constant pi, create a SolvedStep for it
 | 
			
		||||
          mathConf[i] = {
 | 
			
		||||
            total: Math.PI,
 | 
			
		||||
| 
						 | 
				
			
			@ -127,7 +126,7 @@ export const parseRoll = (fullCmd: string, modifiers: RollModifiers): SolvedRoll
 | 
			
		|||
            containsCrit: false,
 | 
			
		||||
            containsFail: false,
 | 
			
		||||
          };
 | 
			
		||||
        } else if (mathConf[i].toString().toLowerCase() === 'pie') {
 | 
			
		||||
        } else if (strMathConfI.toLowerCase() === 'pie') {
 | 
			
		||||
          // If the operand is pie, pi*e, create a SolvedStep for e and pi (and the multiplication symbol between them)
 | 
			
		||||
          mathConf[i] = {
 | 
			
		||||
            total: Math.PI,
 | 
			
		||||
| 
						 | 
				
			
			@ -149,23 +148,37 @@ export const parseRoll = (fullCmd: string, modifiers: RollModifiers): SolvedRoll
 | 
			
		|||
            ],
 | 
			
		||||
          );
 | 
			
		||||
          i += 2;
 | 
			
		||||
        } else if (!operators.includes(mathConf[i].toString())) {
 | 
			
		||||
        } else if (!legalMathOperators.includes(strMathConfI) && legalMathOperators.some((mathOp) => strMathConfI.endsWith(mathOp))) {
 | 
			
		||||
          // Identify when someone does something weird like 4floor(2.5) and split 4 and floor
 | 
			
		||||
          const matchedMathOp = legalMathOperators.filter((mathOp) => strMathConfI.endsWith(mathOp))[0];
 | 
			
		||||
          mathConf[i] = parseFloat(strMathConfI.replace(matchedMathOp, ''));
 | 
			
		||||
 | 
			
		||||
          mathConf.splice(i + 1, 0, ...['*', matchedMathOp]);
 | 
			
		||||
          i += 2;
 | 
			
		||||
        } else if (![...operators, ...legalMathOperators].includes(strMathConfI)) {
 | 
			
		||||
          // If nothing else has handled it by now, try it as a roll
 | 
			
		||||
          const formattedRoll = formatRoll(mathConf[i].toString(), modifiers);
 | 
			
		||||
          const formattedRoll = formatRoll(strMathConfI, modifiers);
 | 
			
		||||
          mathConf[i] = formattedRoll.solvedStep;
 | 
			
		||||
          tempCountDetails.push(formattedRoll.countDetails);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Identify if we are in a state where the current number is a negative number
 | 
			
		||||
        if (mathConf[i - 1] === '-' && ((!mathConf[i - 2] && mathConf[i - 2] !== 0) || mathConf[i - 2] === '(')) {
 | 
			
		||||
          if (typeof mathConf[i] === 'number') {
 | 
			
		||||
            mathConf[i] = <number> mathConf[i] * -1;
 | 
			
		||||
          if (typeof mathConf[i] === 'string') {
 | 
			
		||||
            // Current item is a mathOp, need to insert a "-1 *" before it
 | 
			
		||||
            mathConf.splice(i - 1, 1, ...[parseFloat('-1'), '*']);
 | 
			
		||||
            i += 2;
 | 
			
		||||
          } else {
 | 
			
		||||
            (<SolvedStep> mathConf[i]).total = (<SolvedStep> mathConf[i]).total * -1;
 | 
			
		||||
            (<SolvedStep> mathConf[i]).details = `-${(<SolvedStep> mathConf[i]).details}`;
 | 
			
		||||
            // Handle normally, just set current item to negative
 | 
			
		||||
            if (typeof mathConf[i] === 'number') {
 | 
			
		||||
              mathConf[i] = <number> mathConf[i] * -1;
 | 
			
		||||
            } else {
 | 
			
		||||
              (<SolvedStep> mathConf[i]).total = (<SolvedStep> mathConf[i]).total * -1;
 | 
			
		||||
              (<SolvedStep> mathConf[i]).details = `-${(<SolvedStep> mathConf[i]).details}`;
 | 
			
		||||
            }
 | 
			
		||||
            mathConf.splice(i - 1, 1);
 | 
			
		||||
            i--;
 | 
			
		||||
          }
 | 
			
		||||
          mathConf.splice(i - 1, 1);
 | 
			
		||||
          i--;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,8 @@ import { RollModifiers } from '../mod.d.ts';
 | 
			
		|||
import { ReturnData, RollSet } from './solver.d.ts';
 | 
			
		||||
 | 
			
		||||
export const loggingEnabled = false;
 | 
			
		||||
export const legalMath = [Math.abs, Math.ceil, Math.floor, Math.round, Math.sqrt, Math.cbrt];
 | 
			
		||||
export const legalMathOperators = legalMath.map((oper) => oper.name);
 | 
			
		||||
 | 
			
		||||
// genRoll(size) returns number
 | 
			
		||||
// genRoll rolls a die of size size and returns the result
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@ import {
 | 
			
		|||
} from '../../deps.ts';
 | 
			
		||||
 | 
			
		||||
import { SolvedStep } from './solver.d.ts';
 | 
			
		||||
import { loggingEnabled } from './rollUtils.ts';
 | 
			
		||||
import { legalMath, legalMathOperators, loggingEnabled } from './rollUtils.ts';
 | 
			
		||||
 | 
			
		||||
// fullSolver(conf, wrapDetails) returns one condensed SolvedStep
 | 
			
		||||
// fullSolver is a function that recursively solves the full roll and math
 | 
			
		||||
| 
						 | 
				
			
			@ -35,7 +35,7 @@ export const fullSolver = (conf: (string | number | SolvedStep)[], wrapDetails:
 | 
			
		|||
  while (conf.includes('(')) {
 | 
			
		||||
    loggingEnabled && log(LT.LOG, `Evaluating roll ${JSON.stringify(conf)} | Looking for (`);
 | 
			
		||||
    // Get first open parenthesis
 | 
			
		||||
    const openParenIdx = conf.indexOf('(');
 | 
			
		||||
    let openParenIdx = conf.indexOf('(');
 | 
			
		||||
    let closeParenIdx = -1;
 | 
			
		||||
    let nextParenIdx = 0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -66,18 +66,28 @@ export const fullSolver = (conf: (string | number | SolvedStep)[], wrapDetails:
 | 
			
		|||
    // Replace the items between openParenIdx and closeParenIdx (including the parens) with its solved equivalent
 | 
			
		||||
    conf.splice(openParenIdx, closeParenIdx - openParenIdx + 1, parenSolve);
 | 
			
		||||
 | 
			
		||||
    // Determine if previous idx is a Math operator and execute it
 | 
			
		||||
    if (openParenIdx - 1 > -1 && legalMathOperators.includes(conf[openParenIdx - 1].toString())) {
 | 
			
		||||
      // Update total and details of parenSolve
 | 
			
		||||
      parenSolve.total = legalMath[legalMathOperators.indexOf(conf[openParenIdx - 1].toString())](parenSolve.total);
 | 
			
		||||
      parenSolve.details = `${conf[openParenIdx - 1]}${parenSolve.details}`;
 | 
			
		||||
 | 
			
		||||
      conf.splice(openParenIdx - 1, 2, parenSolve);
 | 
			
		||||
      // shift openParenIdx as we have just removed something before it
 | 
			
		||||
      openParenIdx--;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Determining if we need to add in a multiplication sign to handle implicit multiplication (like "(4)2" = 8)
 | 
			
		||||
    // insertedMult flags if there was a multiplication sign inserted before the parens
 | 
			
		||||
    let insertedMult = 0;
 | 
			
		||||
    // Check if a number was directly before openParenIdx and slip in the "*" if needed
 | 
			
		||||
    if (openParenIdx - 1 > -1 && !signs.includes(conf[openParenIdx - 1].toString())) {
 | 
			
		||||
      insertedMult = 1;
 | 
			
		||||
      conf.splice(openParenIdx, 0, '*');
 | 
			
		||||
      // shift openParenIdx as we have just added something before it
 | 
			
		||||
      openParenIdx++;
 | 
			
		||||
    }
 | 
			
		||||
    // Check if a number is directly after the closing paren and slip in the "*" if needed
 | 
			
		||||
    // openParenIdx is used here as the conf array has already been collapsed down
 | 
			
		||||
    if (openParenIdx + 1 + insertedMult < conf.length && !signs.includes(conf[openParenIdx + 1 + insertedMult].toString())) {
 | 
			
		||||
      conf.splice(openParenIdx + 1 + insertedMult, 0, '*');
 | 
			
		||||
    if (openParenIdx + 1 < conf.length && !signs.includes(conf[openParenIdx + 1].toString())) {
 | 
			
		||||
      conf.splice(openParenIdx + 1, 0, '*');
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue