Add initial group support, only support SUM mode (ie no modifiers allowed)
This commit is contained in:
parent
cb3cb6777d
commit
cbac134f79
|
@ -5,15 +5,16 @@ import config from '~config';
|
||||||
import { ReturnData } from 'artigen/artigen.d.ts';
|
import { ReturnData } from 'artigen/artigen.d.ts';
|
||||||
|
|
||||||
import { CountDetails, RollDistributionMap, RollModifiers } from 'artigen/dice/dice.d.ts';
|
import { CountDetails, RollDistributionMap, RollModifiers } from 'artigen/dice/dice.d.ts';
|
||||||
|
import { handleGroup } from 'artigen/dice/groupHandler.ts';
|
||||||
|
|
||||||
import { loopCountCheck } from 'artigen/managers/loopManager.ts';
|
import { loopCountCheck } from 'artigen/managers/loopManager.ts';
|
||||||
|
|
||||||
import { tokenizeMath } from 'artigen/math/mathTokenizer.ts';
|
import { tokenizeMath } from 'artigen/math/mathTokenizer.ts';
|
||||||
|
|
||||||
import { reduceCountDetails } from 'artigen/utils/counter.ts';
|
import { reduceCountDetails } from 'artigen/utils/counter.ts';
|
||||||
import { closeInternal, cmdSplitRegex, internalWrapRegex, openInternal } from 'artigen/utils/escape.ts';
|
import { closeInternal, closeInternalGrp, internalGrpWrapRegex, internalWrapRegex, openInternal, openInternalGrp } from 'artigen/utils/escape.ts';
|
||||||
import { loggingEnabled } from 'artigen/utils/logFlag.ts';
|
import { loggingEnabled } from 'artigen/utils/logFlag.ts';
|
||||||
import { assertGroupBalance, getMatchingGroupIdx, getMatchingInternalIdx, getMatchingPostfixIdx } from 'artigen/utils/parenBalance.ts';
|
import { assertGroupBalance, getMatchingGroupIdx, getMatchingInternalGrpIdx, getMatchingInternalIdx, getMatchingPostfixIdx } from 'artigen/utils/parenBalance.ts';
|
||||||
import { basicReducer } from 'artigen/utils/reducers.ts';
|
import { basicReducer } from 'artigen/utils/reducers.ts';
|
||||||
|
|
||||||
// tokenizeCmd expects a string[] of items that are either config.prefix/config.postfix or some text that contains math and/or dice rolls
|
// tokenizeCmd expects a string[] of items that are either config.prefix/config.postfix or some text that contains math and/or dice rolls
|
||||||
|
@ -131,38 +132,78 @@ export const tokenizeCmd = (
|
||||||
}
|
}
|
||||||
return [returnData, countDetails, rollDists];
|
return [returnData, countDetails, rollDists];
|
||||||
} else {
|
} else {
|
||||||
// Check for any groups and handle them?
|
// Check for any groups and handle them
|
||||||
const groupParts = cmd
|
const groupParts = cmd
|
||||||
.join('')
|
.join('')
|
||||||
.split(/([{,}])/g)
|
.split(/([{}])/g)
|
||||||
.filter((x) => x);
|
.filter((x) => x);
|
||||||
|
const groupResults: ReturnData[] = [];
|
||||||
if (groupParts.includes('{')) {
|
if (groupParts.includes('{')) {
|
||||||
assertGroupBalance(groupParts);
|
assertGroupBalance(groupParts);
|
||||||
}
|
}
|
||||||
while (groupParts.includes('{')) {
|
while (groupParts.includes('{')) {
|
||||||
loggingEnabled && log(LT.LOG, `Handling Groups | Current cmd: ${JSON.stringify(groupParts)}`);
|
loggingEnabled && log(LT.LOG, `Handling Groups | Current cmd: ${JSON.stringify(groupParts)}`);
|
||||||
const openIdx = groupParts.indexOf('}');
|
|
||||||
const closeIdx = getMatchingGroupIdx;
|
const openIdx = groupParts.indexOf('{');
|
||||||
const temp = cmd.join('').replaceAll('{', '').replaceAll('}', '').replaceAll(',', '');
|
const closeIdx = getMatchingGroupIdx(groupParts, openIdx);
|
||||||
cmd = temp.split(cmdSplitRegex);
|
|
||||||
|
const currentGrp = groupParts.slice(openIdx + 1, closeIdx);
|
||||||
|
|
||||||
|
const [tempData, tempCounts, tempDists] = handleGroup(currentGrp, '', modifiers, previousResults);
|
||||||
|
const data = tempData[0];
|
||||||
|
log(LT.LOG, `Solved Group is back ${JSON.stringify(data)} | ${JSON.stringify(returnData)} ${JSON.stringify(tempCounts)} ${JSON.stringify(tempDists)}`);
|
||||||
|
|
||||||
|
countDetails.push(...tempCounts);
|
||||||
|
rollDists.push(...tempDists);
|
||||||
|
|
||||||
|
// Merge result back into groupParts
|
||||||
|
groupParts.splice(openIdx, closeIdx - openIdx + 1, `${openInternalGrp}${groupResults.length}${closeInternalGrp}`);
|
||||||
|
groupResults.push(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
const cmdForMath = groupParts.join('');
|
const cmdForMath = groupParts.join('');
|
||||||
loggingEnabled && log(LT.LOG, `Tokenizing math ${cmdForMath}`);
|
loggingEnabled && log(LT.LOG, `Tokenizing math ${cmdForMath}`);
|
||||||
|
|
||||||
// Solve the math and rolls for this cmd
|
// Solve the math and rolls for this cmd
|
||||||
const [tempData, tempCounts, tempDists] = tokenizeMath(cmdForMath, modifiers, previousResults);
|
const [tempData, tempCounts, tempDists] = tokenizeMath(cmdForMath, modifiers, previousResults, groupResults);
|
||||||
const data = tempData[0];
|
const data = tempData[0];
|
||||||
loggingEnabled &&
|
loggingEnabled &&
|
||||||
log(LT.LOG, `Solved math is back ${JSON.stringify(data)} | ${JSON.stringify(returnData)} ${JSON.stringify(tempCounts)} ${JSON.stringify(tempDists)}`);
|
log(
|
||||||
|
LT.LOG,
|
||||||
|
`Solved math is back ${JSON.stringify(data)} | ${JSON.stringify(returnData)} ${JSON.stringify(groupResults)} ${
|
||||||
|
JSON.stringify(
|
||||||
|
tempCounts,
|
||||||
|
)
|
||||||
|
} ${JSON.stringify(tempDists)}`,
|
||||||
|
);
|
||||||
|
|
||||||
// Merge counts
|
// Merge counts
|
||||||
countDetails.push(...tempCounts);
|
countDetails.push(...tempCounts);
|
||||||
rollDists.push(...tempDists);
|
rollDists.push(...tempDists);
|
||||||
|
|
||||||
|
// Handle merging group data into initConfig first since a group could "smuggle" a returnData in it
|
||||||
|
const tempInitConf = data.initConfig.split(internalGrpWrapRegex).filter((x) => x);
|
||||||
|
loggingEnabled && log(LT.LOG, `Split solved math into tempInitConf ${JSON.stringify(tempInitConf)}`);
|
||||||
|
while (tempInitConf.includes(openInternalGrp)) {
|
||||||
|
loopCountCheck();
|
||||||
|
|
||||||
|
const openIdx = tempInitConf.indexOf(openInternalGrp);
|
||||||
|
const closeIdx = getMatchingInternalGrpIdx(tempInitConf, openIdx);
|
||||||
|
|
||||||
|
// Take first groupResult out of array
|
||||||
|
const dataToMerge = groupResults.shift();
|
||||||
|
|
||||||
|
// Replace the found pair with the nested tempInitConfig and result
|
||||||
|
tempInitConf.splice(openIdx, closeIdx - openIdx + 1, `${dataToMerge?.initConfig}`);
|
||||||
|
loggingEnabled && log(LT.LOG, `Current tempInitConf state ${JSON.stringify(tempInitConf)}`);
|
||||||
|
}
|
||||||
|
|
||||||
// Handle merging returnData into tempData
|
// Handle merging returnData into tempData
|
||||||
const initConf = data.initConfig.split(internalWrapRegex).filter((x) => x);
|
const initConf = tempInitConf
|
||||||
loggingEnabled && log(LT.LOG, `Split solved math initConfig ${JSON.stringify(initConf)}`);
|
.join('')
|
||||||
|
.split(internalWrapRegex)
|
||||||
|
.filter((x) => x);
|
||||||
|
loggingEnabled && log(LT.LOG, `Split tempInitConfig into initConf ${JSON.stringify(initConf)}`);
|
||||||
while (initConf.includes(openInternal)) {
|
while (initConf.includes(openInternal)) {
|
||||||
loopCountCheck();
|
loopCountCheck();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
import { log, LogTypes as LT } from '@Log4Deno';
|
||||||
|
|
||||||
|
import { ReturnData } from 'artigen/artigen.d.ts';
|
||||||
|
|
||||||
|
import { CountDetails, RollDistributionMap, RollModifiers } from 'artigen/dice/dice.d.ts';
|
||||||
|
|
||||||
|
import { loopCountCheck } from 'artigen/managers/loopManager.ts';
|
||||||
|
|
||||||
|
import { tokenizeMath } from 'artigen/math/mathTokenizer.ts';
|
||||||
|
|
||||||
|
import { closeInternalGrp, openInternalGrp } from 'artigen/utils/escape.ts';
|
||||||
|
import { loggingEnabled } from 'artigen/utils/logFlag.ts';
|
||||||
|
import { getMatchingGroupIdx } from 'artigen/utils/parenBalance.ts';
|
||||||
|
|
||||||
|
export const handleGroup = (
|
||||||
|
groupParts: string[],
|
||||||
|
groupModifiers: string,
|
||||||
|
modifiers: RollModifiers,
|
||||||
|
previousResults: number[],
|
||||||
|
): [ReturnData[], CountDetails[], RollDistributionMap[]] => {
|
||||||
|
const returnData: ReturnData[] = [];
|
||||||
|
const countDetails: CountDetails[] = [];
|
||||||
|
const rollDists: RollDistributionMap[] = [];
|
||||||
|
|
||||||
|
// Nested groups still exist, unwrap them
|
||||||
|
while (groupParts.includes('{')) {
|
||||||
|
loopCountCheck();
|
||||||
|
|
||||||
|
loggingEnabled && log(LT.LOG, `Handling Nested Groups | Current cmd: ${JSON.stringify(groupParts)}`);
|
||||||
|
|
||||||
|
const openIdx = groupParts.indexOf('}');
|
||||||
|
const closeIdx = getMatchingGroupIdx(groupParts, openIdx);
|
||||||
|
|
||||||
|
const currentGrp = groupParts.slice(openIdx + 1, closeIdx);
|
||||||
|
|
||||||
|
const [tempData, tempCounts, tempDists] = handleGroup(currentGrp, '', modifiers, previousResults);
|
||||||
|
const data = tempData[0];
|
||||||
|
loggingEnabled && log(LT.LOG, `Solved Nested Group is back ${JSON.stringify(data)} | ${JSON.stringify(tempCounts)} ${JSON.stringify(tempDists)}`);
|
||||||
|
|
||||||
|
countDetails.push(...tempCounts);
|
||||||
|
rollDists.push(...tempDists);
|
||||||
|
|
||||||
|
// Merge result back into groupParts
|
||||||
|
groupParts.splice(openIdx, closeIdx - openIdx + 1, `${openInternalGrp}${data.rollTotal}${closeInternalGrp}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the items in the groups
|
||||||
|
const commaParts = groupParts
|
||||||
|
.join('')
|
||||||
|
.split(',')
|
||||||
|
.filter((x) => x);
|
||||||
|
|
||||||
|
if (commaParts.length > 1) {
|
||||||
|
loggingEnabled && log(LT.LOG, `In multi-mode ${JSON.stringify(commaParts)} ${groupModifiers}`);
|
||||||
|
// Handle "normal operation" of group
|
||||||
|
const groupResults: ReturnData[] = [];
|
||||||
|
|
||||||
|
for (const part of commaParts) {
|
||||||
|
loopCountCheck();
|
||||||
|
|
||||||
|
loggingEnabled && log(LT.LOG, `Solving commaPart: ${part}`);
|
||||||
|
const [tempData, tempCounts, tempDists] = tokenizeMath(part, modifiers, previousResults, []);
|
||||||
|
const data = tempData[0];
|
||||||
|
|
||||||
|
loggingEnabled && log(LT.LOG, `Solved Math for Group is back ${JSON.stringify(data)} | ${JSON.stringify(tempCounts)} ${JSON.stringify(tempDists)}`);
|
||||||
|
|
||||||
|
countDetails.push(...tempCounts);
|
||||||
|
rollDists.push(...tempDists);
|
||||||
|
groupResults.push(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (groupModifiers) {
|
||||||
|
// Handle the provided modifiers
|
||||||
|
} else {
|
||||||
|
// Sum mode
|
||||||
|
const data = groupResults.reduce((prev, cur) => ({
|
||||||
|
rollTotal: prev.rollTotal + cur.rollTotal,
|
||||||
|
rollPreFormat: '',
|
||||||
|
rollPostFormat: '',
|
||||||
|
rollDetails: prev.rollDetails + ' + ' + cur.rollDetails,
|
||||||
|
containsCrit: prev.containsCrit || cur.containsCrit,
|
||||||
|
containsFail: prev.containsFail || cur.containsFail,
|
||||||
|
initConfig: prev.initConfig + ', ' + cur.initConfig,
|
||||||
|
isComplex: prev.isComplex || cur.isComplex,
|
||||||
|
}));
|
||||||
|
data.initConfig = `{${data.initConfig}}`;
|
||||||
|
data.rollDetails = `{${data.rollDetails}}`;
|
||||||
|
returnData.push(data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
loggingEnabled && log(LT.LOG, `In single-mode ${JSON.stringify(commaParts)} ${groupModifiers}`);
|
||||||
|
if (groupModifiers) {
|
||||||
|
// Handle special case where the group modifiers are applied across the dice rolled
|
||||||
|
// ex from roll20 docs: {4d6+3d8}k4 - Roll 4 d6's and 3 d8's, out of those 7 dice the highest 4 are kept and summed up.
|
||||||
|
} else {
|
||||||
|
// why did you put this in a group, that was entirely pointless
|
||||||
|
loggingEnabled && log(LT.LOG, `Solving commaPart: ${commaParts[0]}`);
|
||||||
|
const [tempData, tempCounts, tempDists] = tokenizeMath(commaParts[0], modifiers, previousResults, []);
|
||||||
|
const data = tempData[0];
|
||||||
|
|
||||||
|
loggingEnabled && log(LT.LOG, `Solved Math for Group is back ${JSON.stringify(data)} | ${JSON.stringify(tempCounts)} ${JSON.stringify(tempDists)}`);
|
||||||
|
|
||||||
|
countDetails.push(...tempCounts);
|
||||||
|
rollDists.push(...tempDists);
|
||||||
|
data.initConfig = `{${data.initConfig}}`;
|
||||||
|
data.rollDetails = `{${data.rollDetails}}`;
|
||||||
|
returnData.push(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [returnData, countDetails, rollDists];
|
||||||
|
};
|
|
@ -11,7 +11,7 @@ import { loopCountCheck } from 'artigen/managers/loopManager.ts';
|
||||||
|
|
||||||
import { mathSolver } from 'artigen/math/mathSolver.ts';
|
import { mathSolver } from 'artigen/math/mathSolver.ts';
|
||||||
|
|
||||||
import { cmdSplitRegex, internalWrapRegex } from 'artigen/utils/escape.ts';
|
import { closeInternalGrp, cmdSplitRegex, internalWrapRegex, openInternalGrp } from 'artigen/utils/escape.ts';
|
||||||
import { legalMathOperators } from 'artigen/utils/legalMath.ts';
|
import { legalMathOperators } from 'artigen/utils/legalMath.ts';
|
||||||
import { loggingEnabled } from 'artigen/utils/logFlag.ts';
|
import { loggingEnabled } from 'artigen/utils/logFlag.ts';
|
||||||
import { assertParenBalance } from 'artigen/utils/parenBalance.ts';
|
import { assertParenBalance } from 'artigen/utils/parenBalance.ts';
|
||||||
|
@ -20,7 +20,12 @@ import { assertParenBalance } from 'artigen/utils/parenBalance.ts';
|
||||||
const minusOps = ['(', '^', '**', '*', '/', '%', '+', '-'];
|
const minusOps = ['(', '^', '**', '*', '/', '%', '+', '-'];
|
||||||
const allOps = [...minusOps, ')'];
|
const allOps = [...minusOps, ')'];
|
||||||
|
|
||||||
export const tokenizeMath = (cmd: string, modifiers: RollModifiers, previousResults: number[]): [ReturnData[], CountDetails[], RollDistributionMap[]] => {
|
export const tokenizeMath = (
|
||||||
|
cmd: string,
|
||||||
|
modifiers: RollModifiers,
|
||||||
|
previousResults: number[],
|
||||||
|
groupResults: ReturnData[],
|
||||||
|
): [ReturnData[], CountDetails[], RollDistributionMap[]] => {
|
||||||
const countDetails: CountDetails[] = [];
|
const countDetails: CountDetails[] = [];
|
||||||
const rollDists: RollDistributionMap[] = [];
|
const rollDists: RollDistributionMap[] = [];
|
||||||
|
|
||||||
|
@ -54,6 +59,18 @@ export const tokenizeMath = (cmd: string, modifiers: RollModifiers, previousResu
|
||||||
} else if (mathConf[i] == parseFloat(curMathConfStr)) {
|
} else if (mathConf[i] == parseFloat(curMathConfStr)) {
|
||||||
// If its a number, parse the number out
|
// If its a number, parse the number out
|
||||||
mathConf[i] = parseFloat(curMathConfStr);
|
mathConf[i] = parseFloat(curMathConfStr);
|
||||||
|
} else if (curMathConfStr.startsWith(openInternalGrp)) {
|
||||||
|
const groupIdx = parseInt(curMathConfStr.substring(1, curMathConfStr.indexOf(closeInternalGrp)));
|
||||||
|
if (groupIdx >= groupResults.length) {
|
||||||
|
throw new Error('InternalGroupMachineBroke');
|
||||||
|
}
|
||||||
|
mathConf[i] = {
|
||||||
|
total: groupResults[groupIdx].rollTotal,
|
||||||
|
details: groupResults[groupIdx].rollDetails,
|
||||||
|
containsCrit: groupResults[groupIdx].containsCrit,
|
||||||
|
containsFail: groupResults[groupIdx].containsFail,
|
||||||
|
isComplex: groupResults[groupIdx].isComplex,
|
||||||
|
};
|
||||||
} else if (curMathConfStr.toLowerCase() === 'e') {
|
} else if (curMathConfStr.toLowerCase() === 'e') {
|
||||||
// If the operand is the constant e, create a SolvedStep for it
|
// If the operand is the constant e, create a SolvedStep for it
|
||||||
mathConf[i] = {
|
mathConf[i] = {
|
||||||
|
|
|
@ -30,3 +30,8 @@ export const cmdSplitRegex = new RegExp(`(${escapePrefixPostfix(config.prefix)})
|
||||||
export const openInternal = '\u2045';
|
export const openInternal = '\u2045';
|
||||||
export const closeInternal = '\u2046';
|
export const closeInternal = '\u2046';
|
||||||
export const internalWrapRegex = new RegExp(`([${openInternal}${closeInternal}])`, 'g');
|
export const internalWrapRegex = new RegExp(`([${openInternal}${closeInternal}])`, 'g');
|
||||||
|
|
||||||
|
// Internal Group is used for marking handled groups
|
||||||
|
export const openInternalGrp = '\u2e20';
|
||||||
|
export const closeInternalGrp = '\u2e21';
|
||||||
|
export const internalGrpWrapRegex = new RegExp(`([${openInternalGrp}${closeInternalGrp}])`, 'g');
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { loopCountCheck } from 'artigen/managers/loopManager.ts';
|
||||||
|
|
||||||
import { MathConf } from 'artigen/math/math.d.ts';
|
import { MathConf } from 'artigen/math/math.d.ts';
|
||||||
|
|
||||||
import { closeInternal, openInternal } from 'artigen/utils/escape.ts';
|
import { closeInternal, closeInternalGrp, openInternal, openInternalGrp } from 'artigen/utils/escape.ts';
|
||||||
import { loggingEnabled } from 'artigen/utils/logFlag.ts';
|
import { loggingEnabled } from 'artigen/utils/logFlag.ts';
|
||||||
|
|
||||||
const checkBalance = (conf: MathConf[], openStr: string, closeStr: string, errorType: string, getMatching: boolean, openIdx: number): number => {
|
const checkBalance = (conf: MathConf[], openStr: string, closeStr: string, errorType: string, getMatching: boolean, openIdx: number): number => {
|
||||||
|
@ -60,5 +60,6 @@ export const assertPrePostBalance = (conf: MathConf[]) => checkBalance(conf, con
|
||||||
// getMatchingXIdx gets the matching X, also partially verifies the conf has balanced X
|
// getMatchingXIdx gets the matching X, also partially verifies the conf has balanced X
|
||||||
export const getMatchingGroupIdx = (conf: MathConf[], openIdx: number): number => checkBalance(conf, '{', '}', 'Group', true, openIdx);
|
export const getMatchingGroupIdx = (conf: MathConf[], openIdx: number): number => checkBalance(conf, '{', '}', 'Group', true, openIdx);
|
||||||
export const getMatchingInternalIdx = (conf: MathConf[], openIdx: number): number => checkBalance(conf, openInternal, closeInternal, 'Internal', true, openIdx);
|
export const getMatchingInternalIdx = (conf: MathConf[], openIdx: number): number => checkBalance(conf, openInternal, closeInternal, 'Internal', true, openIdx);
|
||||||
|
export const getMatchingInternalGrpIdx = (conf: MathConf[], openIdx: number): number => checkBalance(conf, openInternalGrp, closeInternalGrp, 'InternalGrp', true, openIdx);
|
||||||
export const getMatchingParenIdx = (conf: MathConf[], openIdx: number): number => checkBalance(conf, '(', ')', 'Paren', true, openIdx);
|
export const getMatchingParenIdx = (conf: MathConf[], openIdx: number): number => checkBalance(conf, '(', ')', 'Paren', true, openIdx);
|
||||||
export const getMatchingPostfixIdx = (conf: MathConf[], openIdx: number): number => checkBalance(conf, config.prefix, config.postfix, 'PrefixPostfix', true, openIdx);
|
export const getMatchingPostfixIdx = (conf: MathConf[], openIdx: number): number => checkBalance(conf, config.prefix, config.postfix, 'PrefixPostfix', true, openIdx);
|
||||||
|
|
Loading…
Reference in New Issue