/**
* File : automation/arith/Arith.js
* Created : 28/05/2015
* By : Francesc Busquets <francesc@gmail.com>
*
* JClic.js
* An HTML5 player of JClic activities
* https://projectestac.github.io/jclic.js
*
* @source https://github.com/projectestac/jclic.js
*
* @license EUPL-1.2
* @licstart
* (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)
*
* Licensed under the EUPL, Version 1.1 or -as soon they will be approved by
* the European Commission- subsequent versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
*
* You may obtain a copy of the Licence at:
* https://joinup.ec.europa.eu/software/page/eupl
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the Licence is distributed on an "AS IS" basis, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* Licence for the specific language governing permissions and limitations
* under the Licence.
* @licend
* @module
*/
/* global Intl */
import $ from 'jquery';
import AutoContentProvider from '../AutoContentProvider.js';
import { getNumber, getBoolean, getAttr, setAttr, attrForEach } from '../../Utils.js';
//
// Miscellaneous constants used by Arith:
const
NMAXLOOPS = 60,
OPSTR = ['+', '-', String.fromCharCode(215), ':'],
RES = -12345,
// Use comma as a decimal separator, based on current locale settings
// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl
DOTASCOMMA = Intl && Intl.NumberFormat().format(1.1).indexOf(',') > 0;
/**
* Arith provides randomly generated mental arithmetics operations, ready to be used in JClic activities.
*
* The operations can be additions, subtractions, multiplications or divides. The unknown of these
* operations can be the result of the operation (`A op B = ?`), any of the two operators
* (`A op ? = C` or `? op B = C`) or also the operator itself (`A ? B = C`).
* @extends module:automation/AutoContentProvider.AutoContentProvider
*/
export class Arith extends AutoContentProvider {
/**
* Arith constructor
*/
constructor() {
super();
this.className = '@arith.Arith';
this.numericContent = true;
this.opA = new Arith.Operator();
this.opB = new Arith.Operator();
}
/**
* Formats the number with a fixed number of decimals, optionally filling the result with leading
* zeroes to have a fixed number of digits.
* @param {number} val - The value to format
* @param {number} dec - Number of decimals
* @param {number} pre - Minimal number of digits before dot.
* @returns {string}
*/
static DecFormat(val, dec, pre) {
let result = val.toFixed(dec);
if (pre) {
let n = result.indexOf('.');
if (n < 0)
n = result.length;
for (; n < pre; n++)
result = `0${result}`;
}
return result;
}
/**
* Loads the object settings from a specific JQuery XML element
* @override
* @param {external:jQuery} $xml - The XML element to parse
*/
setProperties($xml) {
$xml.children().each((_n, child) => {
const $node = $(child);
let xNum = '';
switch (child.nodeName) {
case 'operand':
switch ($node.attr('id')) {
case 'A':
this.opA.setProperties($node);
break;
case 'B':
this.opB.setProperties($node);
break;
}
break;
case 'operations':
this.use_add = getBoolean($node.attr('plus'));
this.use_subst = getBoolean($node.attr('minus'));
this.use_mult = getBoolean($node.attr('multiply'));
this.use_div = getBoolean($node.attr('divide'));
break;
case 'unknown':
this.exp_abx = getBoolean($node.attr('result'));
this.exp_xbc = getBoolean($node.attr('first'));
this.exp_axc = getBoolean($node.attr('last'));
this.exp_axbc = getBoolean($node.attr('operand'));
this.exp_caxb = getBoolean($node.attr('inverse'));
break;
case 'result':
xNum = $node.attr('from');
this.resultLimInf = getNumber(xNum === 'x' ? 0 : xNum, this.resultLimInf);
xNum = $node.attr('to');
this.resultLimSup = getNumber(xNum === 'x' ? 0 : xNum, this.resultLimSup);
this.resultCarry = getBoolean($node.attr('notCarry'), this.resultCarry);
this.resultNoDup = !getBoolean($node.attr('duplicates'), !this.resultNoDup);
let s = $node.attr('order');
this.resultOrder = s === 'ascending' ? 'SORTASC' : s === 'descending' ? 'SORTDESC' : 'NOSORT';
s = $node.attr('condition');
this.opCond = s === 'firstBig' ? 'AGB' : s === 'lastBig' ? 'BGA' : 'INDIF';
break;
}
});
return this;
}
/**
* Gets a object with the basic attributes needed to rebuild this instance excluding functions,
* parent references, constants and also attributes retaining the default value.
* The resulting object is commonly usued to serialize elements in JSON format.
* @returns {object} - The resulting object, with minimal attrributes
*/
getAttributes() {
return getAttr(this, [
'className',
'opA', 'opB', // Operator
'use_add', 'use_subst', 'use_mult', 'use_div',
'exp_abx|true', 'exp_axc|false', 'exp_xbc|false', 'exp_axbc|false', 'exp_caxb|false',
'resultLimInf|0', 'resultLimSup|9999', 'resultCarry|false', 'resultNoDup|false', 'resultOrder|NOSORT',
'opCond|INDIF'
]);
}
/**
* Reads the properties of this Arith object from a dataset
* @param {object} data - The data object to be parsed
* @returns {object}
*/
setAttributes(data) {
return setAttr(this, data, [
'className',
{ key: 'opA', fn: Arith.Operator },
{ key: 'opB', fn: Arith.Operator },
'use_add', 'use_subst', 'use_mult', 'use_div',
'exp_abx', 'exp_axc', 'exp_xbc', 'exp_axbc', 'exp_caxb',
'resultLimInf', 'resultLimSup', 'resultCarry', 'resultNoDup', 'resultOrder',
'opCond',
]);
}
/**
* Fills the `n` parameter (an {@link module:automation/arith/Arith.Num Num}) with a value in accordance with the
* specifications of `op` (an {@link module:automation/arith/Arith.Operator Operator}), between two limits.
* @param {module:automation/arith/Arith.Num} n - The number
* @param {module:automation/arith/Arith.Operator} op - The operator
* @param {number} limInf2 - Lower limit
* @param {number} limSup2 - Upper limit
* @returns {boolean} - `true` if all was OK
*/
genNum(n, op, limInf2, limSup2) {
let solved = false;
n.c = op.numDec;
const exp = n.c === 0 ? 1 : n.c === 1 ? 10 : 100;
let ls = op.limSup;
if (limSup2 !== RES && limSup2 < ls)
ls = limSup2;
let li = op.limInf;
if (limInf2 !== RES && limInf2 > li)
li = limInf2;
if (op.fromList > 0) {
n.vf = op.lst[Math.floor(Math.random() * op.fromList)];
solved = true;
}
if (!solved) {
const r = Math.floor(Math.random() * 100);
if (op.wZero && r <= 10) {
n.vf = 0;
solved = true;
} else if (op.wOne && r > 10 && r <= 20) {
n.vf = 1;
solved = true;
} else if (op.wMinusOne && r > 20 && r <= 30) {
n.vf = -1;
solved = true;
}
}
if (!solved) {
if (li > ls) {
const k = li;
li = ls;
ls = k;
}
let rang = Math.floor(ls - li + 1);
if (rang < 0)
rang = 1;
let v = (Math.floor(Math.random() * rang) + li) * exp;
if (exp > 1)
v += Math.floor(Math.random() * exp);
n.vf = v / exp;
}
return true;
}
/**
* Fills the provided {@link module:automation/arith/Arith.Operator Operator} with real values
* @param {module:automation/arith/Arith.Operator} o - The operator to use to generate the operation
* @returns {boolean} - `true` if all was OK
*/
genOp(o) {
let i, ri2, rs2, q, va, vb, bufa, bufb;
const
ops = [],
rlinf = this.resultLimInf,
rlsup = this.resultLimSup;
let nops = 0;
if (this.use_add)
ops[nops++] = 'SUM';
if (this.use_subst)
ops[nops++] = 'REST';
if (this.use_mult)
ops[nops++] = 'MULT';
if (this.use_div)
ops[nops++] = 'DIV';
const op = ops[Math.floor(Math.random() * nops)];
switch (op) {
case 'SUM':
for (i = 0; i < NMAXLOOPS; i++) {
this.genNum(o.numA, this.opA, this.RES, rlsup);
ri2 = o.numA.vf < rlinf ? rlinf - Math.floor(o.numA.vf) : this.RES;
rs2 = rlsup - Math.floor(o.numA.vf);
switch (this.opCond) {
case 'AGB':
if (rs2 === this.RES || rs2 > o.numA.vf)
rs2 = Math.floor(o.numA.vf);
break;
case 'BGA':
if (ri2 === this.RES || ri2 < o.numA.vf)
ri2 = Math.floor(o.numA.vf);
break;
}
this.genNum(o.numB, this.opB, ri2, rs2);
o.numR.vf = o.numA.vf + o.numB.vf;
if (o.numR.vf >= rlinf && o.numR.vf <= rlsup)
break;
}
o.numR.c = o.numA.c > o.numB.c ? o.numA.c : o.numB.c;
o.op = 0;
if (this.resultCarry && o.numA.vf > 0 && o.numB.vf > 0) {
q = o.numR.c === 2 ? 100 : o.numR.c === 1 ? 10 : 1;
bufa = Arith.DecFormat(Math.floor(o.numA.vf * q + 0.5), 0, 10).split('');
bufb = Arith.DecFormat(Math.floor(o.numB.vf * q + 0.5), 0, 10).split('');
for (i = 0; i < 10; i++)
if (bufa[i] !== '0' || bufb[i] !== '0')
break;
for (; i < 10; i++) {
va = parseInt(bufa[i]);
vb = parseInt(bufb[i]);
if (va + vb < 10)
continue;
while (va + vb > 9) {
if (va > vb)
va = va > 0 ? Math.floor(Math.random() * va) : 0;
else
vb = vb > 0 ? Math.floor(Math.random() * vb) : 0;
}
bufa[i] = va.toFixed(0);
bufb[i] = vb.toFixed(0);
}
o.numA.vf = parseInt(bufa.join('')) / q;
o.numB.vf = parseInt(bufb.join('')) / q;
// Corrected 2019/02/11: Factors should be multiplied by 'q'!
// INCORRECT: o.numR.vf = Math.floor(o.numA.vf + o.numB.vf + 0.5) / q
o.numR.vf = Math.floor(o.numA.vf * q + o.numB.vf * q + 0.5) / q;
}
break;
case 'REST':
for (i = 0; i < NMAXLOOPS; i++) {
this.genNum(o.numA, this.opA, rlinf, this.RES);
ri2 = o.numA.vf > rlsup ? Math.floor(o.numA.vf - rlsup) : this.RES;
rs2 = Math.floor(o.numA.vf - rlinf);
switch (this.opCond) {
case 'AGB':
if (rs2 === this.RES || rs2 > o.numA.vf)
rs2 = Math.floor(o.numA.vf);
break;
case 'BGA':
if (ri2 === this.RES || ri2 < o.numA.vf)
ri2 = Math.floor(o.numA.vf);
break;
}
this.genNum(o.numB, this.opB, ri2, rs2);
o.numR.vf = o.numA.vf - o.numB.vf;
if (o.numR.vf >= rlinf && o.numR.vf <= rlsup)
break;
}
o.numR.c = o.numA.c > o.numB.c ? o.numA.c : o.numB.c;
o.op = 1;
if (this.resultCarry && o.numA.vf > 0 && o.numB.vf > 0 && o.numA.vf >= o.numB.vf) {
q = o.numR.c === 2 ? 100 : o.numR.c === 1 ? 10 : 1;
bufa = Arith.DecFormat(Math.floor(o.numA.vf * q + 0.5), 0, 10).split('');
bufb = Arith.DecFormat(Math.floor(o.numB.vf * q + 0.5), 0, 10).split('');
for (i = 0; i < 10; i++)
if (bufb[i] !== '0')
break;
for (; i < 10; i++) {
va = parseInt(bufa[i]);
vb = parseInt(bufb[i]);
if (va >= vb)
continue;
vb = va > 0 ? Math.floor(Math.random() * va) : 0;
bufb[i] = vb.toFixed(0);
}
o.numA.vf = parseInt(bufa.join('')) / q;
o.numB.vf = parseInt(bufb.join('')) / q;
// Corrected 2019/02/11: Factors should be multiplied by 'q'!
// o.numR.vf = Math.floor(o.numA.vf - o.numB.vf + 0.5) / q
o.numR.vf = Math.floor(o.numA.vf * q - o.numB.vf * q + 0.5) / q;
}
break;
case 'MULT':
for (i = 0; i < NMAXLOOPS; i++) {
this.genNum(o.numA, this.opA, this.RES, this.RES);
ri2 = this.opB.limInf;
rs2 = this.opB.limSup;
switch (this.opCond) {
case 'AGB':
if (rs2 > o.numA.vf)
rs2 = Math.floor(o.numA.vf);
break;
case 'BGA':
if (ri2 < o.numA.vf)
ri2 = Math.floor(o.numA.vf);
break;
}
this.genNum(o.numB, this.opB, ri2, rs2);
o.numR.vf = o.numA.vf * o.numB.vf;
if (o.numR.vf >= rlinf && o.numR.vf <= rlsup)
break;
}
o.numR.c = o.numA.c + o.numB.c;
o.op = 2;
break;
case 'DIV':
for (i = 0; i < NMAXLOOPS; i++) {
this.genNum(o.numA, this.opA, this.RES, this.RES);
ri2 = this.opB.limInf;
rs2 = this.opB.limSup;
switch (this.opCond) {
case 'AGB':
if (rs2 > o.numA.vf)
rs2 = Math.floor(o.numA.vf);
break;
case 'BGA':
if (ri2 < o.numA.vf)
ri2 = Math.floor(o.numA.vf);
break;
}
this.genNum(o.numB, this.opB, ri2, rs2);
if (o.numB.vf !== 0 &&
Math.abs(o.numA.vf) >= Math.abs(o.numB.vf) &&
(o.numR.vf = o.numA.vf / o.numB.vf) >= rlinf &&
o.numR.vf <= rlsup)
break;
}
if (o.numB.vf === 0)
o.numB.vf = 1;
o.numR.vf = o.numA.vf / o.numB.vf;
i = o.numA.c - o.numB.c;
q = Math.pow(10, i);
o.numA.vf *= q;
o.numR.vf *= q;
o.numR.vf = Math.floor(o.numR.vf);
o.numA.vf = o.numR.vf * o.numB.vf;
o.numA.vf /= q;
o.numR.vf /= q;
o.numR.c = i > 0 ? i : 0;
o.op = 3;
break;
default:
return false;
}
return true;
}
/**
* Fills the provided ActiveBagContentKit with randomly generated operations
* @override
* @param {module:automation/AutoContentProvider.ActiveBagContentKit} kit - The composite object to be filled with data.
* @returns {boolean} - `true` if all was OK
*/
process(kit) {
let nRows = kit.nRows,
nCols = kit.nCols,
content = kit.content, //Array of ActiveBagContent
useIds = kit.useIds,
i, j, k,
o, op = [], // Array of Arith.Operation
tipus = [],
numTipus, tipX,
tipInv = this.exp_caxb,
va = '', vb = '', vc = '', operator = '',
stra = [], strb = [], strc = [],
nColsB = nCols, nRowsB = nRows,
nCells = nRows * nCols,
ass = null;
if (nRows <= 0 || nCols <= 0 ||
content === null || content.length < 1 || content[0] === null)
return false;
if (nCells < 2)
return false;
numTipus = 0;
if (this.exp_abx)
tipus[numTipus++] = 'ABX';
if (this.exp_axc)
tipus[numTipus++] = 'AXC';
if (this.exp_xbc)
tipus[numTipus++] = 'XBC';
if (this.exp_axbc)
tipus[numTipus++] = 'AXBC';
if (numTipus === 0)
return false;
for (i = 0; i < nCells; i++) {
o = new Arith.Operation();
for (j = 0; j < NMAXLOOPS; j++) {
this.genOp(o);
if (this.resultNoDup) {
for (k = 0; k < i; k++) {
if (o.numR.vf === op[k].numR.vf)
break;
}
if (k === i)
break;
} else
break;
}
op[i] = o;
}
if (this.resultOrder !== 0) {
for (i = nCells - 1; i > 0; i--) {
for (j = 0; j < i; j++) {
if (this.resultOrder === 'SORTASC' && op[j].numR.vf > op[j + 1].numR.vf ||
this.resultOrder === 'SORTDESC' && op[j].numR.vf < op[j + 1].numR.vf) {
// Switch values
o = op[j];
op[j] = op[j + 1];
op[j + 1] = o;
}
}
}
}
for (i = 0; i < nCells; i++) {
tipX = tipus[Math.floor(Math.random() * numTipus)];
va = Arith.DecFormat(op[i].numA.vf, op[0].numA.c);
vb = Arith.DecFormat(op[i].numB.vf, op[0].numB.c);
vc = Arith.DecFormat(op[i].numR.vf, op[0].numR.c);
operator = OPSTR[op[i].op];
// Use the special blank space ASCII 160 (\xA0) instead of regular blank spaces
if (tipInv)
strc[i] = `${vc}\xA0=\xA0${va}\xA0${operator}\xA0${vb}`;
else
strc[i] = `${va}\xA0${operator}\xA0${vb}\xA0=\xA0${vc}`;
switch (tipX) {
case 'AXC':
strb[i] = vb;
stra[i] = tipInv ? `${vc}\xA0=\xA0${va}\xA0${operator}\xA0?` : `${va}\xA0${operator}\xA0?\xA0=\xA0${vc}`;
break;
case 'XBC':
strb[i] = va;
stra[i] = tipInv ? `${vc}\xA0=\xA0?\xA0${operator}\xA0${vb}` : `?\xA0${operator}\xA0${vb}\xA0=\xA0${vc}`;
break;
case 'AXBC':
strb[i] = operator;
stra[i] = tipInv ? `${vc}\xA0=\xA0${va}\xA0?\xA0${vb}` : `${va}\xA0?\xA0${vb}\xA0=\xA0${vc}`;
break;
default:
strb[i] = vc;
stra[i] = tipInv ? `?\xA0=\xA0${va}\xA0${operator}\xA0${vb}` : `${va}\xA0${operator}\xA0${vb}\xA0=`;
break;
}
}
if (useIds) {
ass = [];
let strbx = [];
k = 0;
for (i = 0; i < nCells; i++) {
for (j = 0; j < k; j++)
if (strb[i] === strbx[j])
break;
if (j === k) {
strbx[k] = strb[i];
ass[i] = k;
k++;
} else
ass[i] = j;
}
strb = [];
for (i = 0; i < k; i++)
strb[i] = strbx[i];
if (nRowsB * nColsB !== k) {
let distH = false;
switch (k) {
case 6:
nRowsB = distH ? 2 : 3;
nColsB = distH ? 3 : 2;
break;
case 8:
nRowsB = distH ? 2 : 4;
nColsB = distH ? 4 : 2;
break;
case 9:
nRowsB = 3;
nColsB = 3;
break;
case 10:
nRowsB = distH ? 2 : 5;
nColsB = distH ? 5 : 2;
break;
case 12:
nRowsB = distH ? 3 : 4;
nColsB = distH ? 4 : 3;
break;
case 14:
nRowsB = distH ? 2 : 7;
nColsB = distH ? 7 : 2;
break;
case 15:
nRowsB = distH ? 3 : 5;
nColsB = distH ? 3 : 5;
break;
case 16:
nRowsB = 4;
nColsB = 4;
break;
case 18:
nRowsB = distH ? 6 : 3;
nColsB = distH ? 3 : 6;
break;
case 20:
nRowsB = distH ? 4 : 5;
nColsB = distH ? 5 : 4;
break;
default:
nRowsB = distH ? 1 : k;
nColsB = distH ? k : 1;
break;
}
}
}
// Added 2019/02/11
// Use comma instead of dot for decimal separator, accordingly to current locale
if (DOTASCOMMA) {
function replaceDot(s) { return s.replace(/\./g, ','); }
stra = stra.map(replaceDot);
strb = strb.map(replaceDot);
strc = strc.map(replaceDot);
}
content[0].setTextContent(stra, nCols, nRows);
if (ass !== null)
content[0].setIds(ass);
if (content.length > 1 && content[1] !== null) {
content[1].setTextContent(strb, nColsB, nRowsB);
content[1].getShaper().reset(nColsB, nRowsB);
}
if (content.length > 2 && content[2] !== null)
content[2].setTextContent(strc, nCols, nRows);
return true;
}
}
Object.assign(Arith.prototype, {
//
// Operations use two operators:
/**
* First operator
* @name module:automation/arith/Arith.Arith#opA
* @type {module:automation/arith/Arith.Operator} */
opA: null,
/**
* Second operator
* @name module:automation/arith/Arith.Arith#opB
* @type {module:automation/arith/Arith.Operator} */
opB: null,
/**
* Allow additions
* @name module:automation/arith/Arith.Arith#use_add
* @type {boolean} */
use_add: true,
/**
* Allow subtractions
* @name module:automation/arith/Arith.Arith#use_subst
* @type {boolean} */
use_subst: false,
/**
* Allow multiplications
* @name module:automation/arith/Arith.Arith#use_mult
* @type {boolean} */
use_mult: false,
/**
* Allow divides
* @name module:automation/arith/Arith.Arith#use_div
* @type {boolean} */
use_div: false,
/**
* Allow expressions of type `A op B = X`
* @name module:automation/arith/Arith.Arith#exp_abx
* @type {boolean} */
exp_abx: true,
/**
* Allow expressions of type `A op X = C`
* @name module:automation/arith/Arith.Arith#exp_axc
* @type {boolean} */
exp_axc: false,
/**
* Allow expressions of type `X op B = C`
* @name module:automation/arith/Arith.Arith#exp_xbc
* @type {boolean} */
exp_xbc: false,
/**
* Allow expressions of type `A x B = C`
* @name module:automation/arith/Arith.Arith#exp_axbc
* @type {boolean} */
exp_axbc: false,
/**
* Allow inverse expressions, like `C = A op B`
* @name module:automation/arith/Arith.Arith#exp_caxb
* @type {boolean} */
exp_caxb: false,
/**
* Lower limit of the result
* @name module:automation/arith/Arith.Arith#resultLimInf
* @type {number} */
resultLimInf: 0,
/**
* Upper limit of the result
* @name module:automation/arith/Arith.Arith#resultLimSup
* @type {number} */
resultLimSup: 9999,
/**
* Allow carry operations
* @see {@link https://en.wikipedia.org/wiki/Carry_(arithmetic)}
* @name module:automation/arith/Arith.Arith#resultCarry
* @type {boolean} */
resultCarry: false,
/**
* Avoid operations with the same result
* @name module:automation/arith/Arith.Arith#resultNoDup
* @type {boolean} */
resultNoDup: false,
/**
* Type of sorting of results. Possible values are: 'NOSORT', 'SORTASC' and 'SORTDESC'
* @name module:automation/arith/Arith.Arith#resultOrder
* @type {string} */
resultOrder: 'NOSORT',
/**
* Sorting of the operands in commutative operations. Possible values are: 'AGB' (_A greater than B_),
* 'BGA' (_B greater tan A_) and 'INDIF' (default)
* @name module:automation/arith/Arith.Arith#opCond
* @type {string} */
opCond: 'INDIF',
});
/**
* Operator is an Utility class used by Arith to encapsulate the properties and methods related
* to the members of the operations.
*/
Arith.Operator = class {
constructor() {
}
/**
* Loads Operator settings from a specific JQuery XML element
* @param {external:jQuery} $xml - The XML element to parse
*/
setProperties($xml) {
// Read attributes
attrForEach($xml.get(0).attributes, (name, val) => {
switch (name) {
case 'decimals':
this.numDec = Number(val);
break;
case 'values':
this.lst = val.split(' ').map(v => Number(v));
this.fromList = this.lst.length;
break;
case 'from':
this.limInf = Number(val === 'x' ? 0 : val);
break;
case 'to':
this.limSup = Number(val === 'x' ? 0 : val);
break;
}
$xml.children().each((_n, child) => {
const $node = $(child);
switch (child.nodeName) {
case 'include':
this.wZero = getBoolean($node.attr('zero'));
this.wOne = getBoolean($node.attr('one'));
this.wMinusOne = getBoolean($node.attr('minusOne'));
break;
}
});
});
return this;
}
/**
* Gets a object with the basic attributes needed to rebuild this instance excluding functions,
* parent references, constants and also attributes retaining the default value.
* The resulting object is commonly usued to serialize elements in JSON format.
* @returns {object} - The resulting object, with minimal attrributes
*/
getAttributes() {
return getAttr(this, [
'limInf', 'limSup',
'numDec|0',
'wZero|false', 'wOne|false', 'wMinusOne|false',
'fromList|0', 'lst',
]);
}
/**
* Reads the properties of this operator from a dataset
* @param {object} data - The data object to be parsed
* @returns {module:automation/arith/Arith.Arith}
*/
setAttributes(data) {
return setAttr(this, data, [
'limInf', 'limSup',
'numDec',
'wZero', 'wOne', 'wMinusOne',
'fromList', 'lst',
]);
}
};
Object.assign(Arith.Operator.prototype, {
/**
* Lower limit
* @name module:automation/arith/Arith.Arith.Operator#limInf
* @type {number} */
limInf: 0,
/**
* Upper limit
* @name module:automation/arith/Arith.Arith.Operator#limSup
* @type {number} */
limSup: 10,
/**
* Number of decimal places
* @name module:automation/arith/Arith.Arith.Operator#numDec
* @type {number} */
numDec: 0,
/**
* Including 0
* @name module:automation/arith/Arith.Arith.Operator#wZero
* @type {boolean} */
wZero: false,
/**
* Including 1
* @name module:automation/arith/Arith.Arith.Operator#wOne
* @type {boolean} */
wOne: false,
/**
* Including -1
* @name module:automation/arith/Arith.Arith.Operator#wMinusOne
* @type {boolean} */
wMinusOne: false,
/**
* Take values from list. This member stores the list length.
* @name module:automation/arith/Arith.Arith.Operator#fromList
* @type {number} */
fromList: 0,
/**
* The list of possible values
* @name module:automation/arith/Arith.Arith.Operator#lst
* @type {number[]} */
lst: [],
});
Arith.Num = class {
constructor() {
this.vf = 0.0; // The number value
this.c = 0; // Number of decimals to be used when representing the number
}
format() {
return Arith.DecFormat(this.vf, this.c);
}
};
Arith.Operation = class {
constructor() {
this.numA = new Arith.Num();
this.numB = new Arith.Num();
this.numR = new Arith.Num();
this.op = 0;
}
};
// Register class in AutoContentProvider.CLASSES
export default AutoContentProvider.registerClass('@arith.Arith', Arith);