UNPKG

calculator-by-str

Version:

Enter the string formula to get the calculation result.

280 lines (250 loc) 7.6 kB
'use strict'; /** * 此文件 用于生成测试公式 */ /** * 记录当前过程的日志 如果报错可以输出此列表 */ let loglist = [] const myLog = (...arg) => { } /** * 输出记录日志 * @param {...any} arg */ const myLog3 = (...args) => { let list = args loglist.push(list) // console.log(...args) } /** * 打印日志 * @param {...any} args */ const myLog2 = (...args) => { console.log(...args) } const ErrorTree = () => { console.log(loglist) loglist = [] } /** * 加减方法 */ const simple = { ["+"]: (a, b) => a + b, ["-"]: (a, b) => a - b } /** * 乘除方法 */ const simple2 = { ["*"]: (a, b) => a * b, ["/"]: (a, b) => a / b, // ["%"]: (a, b) => a % b } /** * 乘方先算 */ const simple3 = { ["**"]: (a, b) => a ** b } const round = (a) => Math.floor(a + 0.5) const mod = (a, b) => a % b /** * 支持的函数 和值 */ const formulas = { "Math.abs": [Math.abs, 1], "Math.acos": [Math.acos, 1], "Math.asin": [Math.asin, 1], "Math.atan": [Math.atan, 1], "Math.atan2": [Math.atan2, 2], "Math.ceil": [Math.ceil, 1], "Math.cos": [Math.cos, 1], "Math.floor": [Math.floor, 1], "Math.log": [Math.log, 1], "Math.max": [Math.max, 2], // max 为了和其他语言同步 改成两个 如果需要用多个参数 可以把2改成"more" "Math.min": [Math.min, 2], // min 为了和其他语言同步 改成两个 如果需要用多个参数 可以把2改成"more" "Math.pow": [Math.pow, 2], "Math.round": [round, 1], "Math.sin": [Math.sin, 1], "Math.sqrt": [Math.sqrt, 1], "Math.tan": [Math.tan, 1], "Math.mod": [mod, 2], // 非Math方法 "Math.PI": [Math.PI], // "Math.SQRT2": [Math.SQRT2], // "Math.LN10": [Math.LN10], // "Math.LOG10E": [Math.LOG10E], // "Math.LOG2E": [Math.LOG2E], // "Math.SQRT1_2": [Math.SQRT1_2], } /** * 函数类型 */ let FmType = [ simple, simple2, formulas, simple3, ] /** * 随机获取函数类型 * @returns simple or simple2 or formulas */ function getFmType() { return Math.floor(Math.random() * FmType.length) } /** * 根据tp类型 获取任意一种算法Math.* 或者加减乘除 * @param {*} tp * @returns [function,key] or [number,key] */ function getRandomFmByType(tp = 0) { let keys = Object.getOwnPropertyNames(FmType[tp]) let randomKey = keys[Math.floor(Math.random() * keys.length)] myLog(randomKey, tp) // 因为 Math.random = null 所有这里判断一下,不需要Math.random的原因是 测试Math.random不能确定结果是否正确 if (!FmType[tp][randomKey]) { return getRandomFmByType(tp) } return [FmType[tp][randomKey], randomKey] } /** * 获取随机数 * @param {*} num * @returns -num <-> num */ function getRandomNum(num = 100) { return Math.floor(Math.random() * num * 2) - num } /** * 获取随机数 * @param {*} num * @returns -num <-> num */ function getRandomNumAbs(num = 100) { return Math.floor(Math.random() * num) } /** * 生成一个公式和公式的计算结果 * @param {*} fmStr 被包含的公式,有概率不使用 * @param {*} num 值的使用取决于fmStr是否使用 * @returns [fmStr, value] */ function bornOne(fmStr = null, num = null) { let type = getFmType() let [curFmFunc, curFmStr] = getRandomFmByType(type) let pcnt = 2 if (curFmFunc instanceof Array) { [curFmFunc, pcnt] = curFmFunc } myLog3("bornOne ------------ ", { curFmFunc, curFmStr, fmStr }) if (curFmFunc instanceof Function) { let funarg = [] let funStrArg = [] let ok = false if (pcnt == "more") { pcnt = getRandomNumAbs(10) + 2 } let curFmRet = "(" for (let index = 0; index < pcnt; index++) { let oneNum = getRandomNum() let oneFm = oneNum if (is() && fmStr && !ok) { oneNum = num oneFm = fmStr ok = true } funarg.push(oneNum) funStrArg.push(oneFm) if (pcnt == index + 1) { curFmRet = curFmRet + oneFm } else { curFmRet = curFmRet + oneFm + "," } } curFmRet = curFmRet + ")" let retNum = curFmFunc(...funarg) if (type == 2) { curFmRet = curFmStr + curFmRet } else { curFmRet = funStrArg[0] + curFmStr + funStrArg[1] } myLog3("...funarg", { pcnt, funarg, curFmRet, retNum, curFmStr, curFmFunc }) if (retNum == Infinity || retNum == -Infinity || isNaN(retNum)) { myLog3("myLog error", retNum, fmStr, num) return bornOne(fmStr, num) } return [curFmRet, retNum, ok] } else { return [curFmStr, curFmFunc] } } /** * 随机正反面 * @returns */ function is() { return Math.floor(Math.random() * 2) == 0 } /** * 获取复杂组合公式 * @param {*} layer * @returns */ function getRandomFm(layer) { loglist = [] let curfmStr let curNum for (let index = 0; index < layer; index++) { let [fmStr, fmNum, use] = bornOne(curfmStr, curNum) if (use) { curfmStr = "(" + fmStr + ")" curNum = fmNum if (curNum == Infinity || curNum == -Infinity || isNaN(curNum) || !curNum) { return getRandomFm(layer) } } else { let curs = simple if (is()) { curs = simple2 } let keys = Object.getOwnPropertyNames(curs) let key = keys[getRandomNumAbs(keys.length)] // 加减乘除公式 myLog("curfmStr, curNum", key, keys, curs) let curFm // 右公式 let curNumr // 右值 if (curfmStr) { // 之前生成的公式 没有用到 curFm = curfmStr curNumr = curNum } else { // 第一次没有公式 let [cfmStr, cfmNum] = bornOne() curFm = "(" + cfmStr + ")" curNumr = cfmNum } // 加减乘除 curNum = curs[key](fmNum, curNumr) // 生成函数的时候就防止NaN发生 if (curNum == Infinity || curNum == -Infinity || isNaN(curNum) || !curNum) { return getRandomFm(layer) } // 新公式 // myLog3("每次结果1:", { index, curfmStr, curFm, curNumr, curNum }) curfmStr = "(" + "(" + fmStr + ")" + key + curFm + ")" // myLog3("每次结果2:", { index, curfmStr, curFm, curNumr, curNum }) } // myLog(curfmStr, curNum) myLog3("每次结果:" + index, { fmStr, fmNum, use }, "上次结果:", { curfmStr }) } myLog3("curfmStr", [curfmStr, curNum]) curfmStr = curfmStr.slice(1, curfmStr.length - 1) // 去掉两边括号 if (curNum == Infinity || curNum == -Infinity || isNaN(curNum) || !curNum) { return getRandomFm(layer) } return [curfmStr, curNum] } // 还可以优化的点 // 1. 使用栈的方式解析括号 // 2. 优化如果0*(fmStr) 这个时候 fmStr 是可以不计算的 module.exports = { getRandomFm, ErrorTree };