2017-04-17 15:10:04 -04:00
|
|
|
const Cast = require('../util/cast.js');
|
|
|
|
const MathUtil = require('../util/math-util.js');
|
2016-08-11 18:47:34 -04:00
|
|
|
|
2017-04-17 19:42:48 -04:00
|
|
|
class Scratch3OperatorsBlocks {
|
|
|
|
constructor (runtime) {
|
|
|
|
/**
|
|
|
|
* The runtime instantiating this block package.
|
|
|
|
* @type {Runtime}
|
|
|
|
*/
|
|
|
|
this.runtime = runtime;
|
|
|
|
}
|
|
|
|
|
2016-06-09 14:29:07 -04:00
|
|
|
/**
|
2017-04-17 19:42:48 -04:00
|
|
|
* Retrieve the block primitives implemented by this package.
|
|
|
|
* @return {object.<string, Function>} Mapping of opcode to Function.
|
2016-06-09 14:29:07 -04:00
|
|
|
*/
|
2017-04-17 19:42:48 -04:00
|
|
|
getPrimitives () {
|
|
|
|
return {
|
|
|
|
operator_add: this.add,
|
|
|
|
operator_subtract: this.subtract,
|
|
|
|
operator_multiply: this.multiply,
|
|
|
|
operator_divide: this.divide,
|
|
|
|
operator_lt: this.lt,
|
|
|
|
operator_equals: this.equals,
|
|
|
|
operator_gt: this.gt,
|
|
|
|
operator_and: this.and,
|
|
|
|
operator_or: this.or,
|
|
|
|
operator_not: this.not,
|
|
|
|
operator_random: this.random,
|
|
|
|
operator_join: this.join,
|
|
|
|
operator_letter_of: this.letterOf,
|
|
|
|
operator_length: this.length,
|
|
|
|
operator_mod: this.mod,
|
|
|
|
operator_round: this.round,
|
|
|
|
operator_mathop: this.mathop
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
add (args) {
|
|
|
|
return Cast.toNumber(args.NUM1) + Cast.toNumber(args.NUM2);
|
|
|
|
}
|
|
|
|
|
|
|
|
subtract (args) {
|
|
|
|
return Cast.toNumber(args.NUM1) - Cast.toNumber(args.NUM2);
|
|
|
|
}
|
|
|
|
|
|
|
|
multiply (args) {
|
|
|
|
return Cast.toNumber(args.NUM1) * Cast.toNumber(args.NUM2);
|
|
|
|
}
|
|
|
|
|
|
|
|
divide (args) {
|
|
|
|
return Cast.toNumber(args.NUM1) / Cast.toNumber(args.NUM2);
|
|
|
|
}
|
|
|
|
|
|
|
|
lt (args) {
|
|
|
|
return Cast.compare(args.OPERAND1, args.OPERAND2) < 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
equals (args) {
|
|
|
|
return Cast.compare(args.OPERAND1, args.OPERAND2) === 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
gt (args) {
|
|
|
|
return Cast.compare(args.OPERAND1, args.OPERAND2) > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
and (args) {
|
|
|
|
return Cast.toBoolean(args.OPERAND1) && Cast.toBoolean(args.OPERAND2);
|
|
|
|
}
|
|
|
|
|
|
|
|
or (args) {
|
|
|
|
return Cast.toBoolean(args.OPERAND1) || Cast.toBoolean(args.OPERAND2);
|
|
|
|
}
|
|
|
|
|
|
|
|
not (args) {
|
|
|
|
return !Cast.toBoolean(args.OPERAND);
|
|
|
|
}
|
|
|
|
|
|
|
|
random (args) {
|
|
|
|
const nFrom = Cast.toNumber(args.FROM);
|
|
|
|
const nTo = Cast.toNumber(args.TO);
|
|
|
|
const low = nFrom <= nTo ? nFrom : nTo;
|
|
|
|
const high = nFrom <= nTo ? nTo : nFrom;
|
|
|
|
if (low === high) return low;
|
|
|
|
// If both arguments are ints, truncate the result to an int.
|
|
|
|
if (Cast.isInt(args.FROM) && Cast.isInt(args.TO)) {
|
|
|
|
return low + parseInt(Math.random() * ((high + 1) - low), 10);
|
|
|
|
}
|
|
|
|
return (Math.random() * (high - low)) + low;
|
|
|
|
}
|
|
|
|
|
|
|
|
join (args) {
|
|
|
|
return Cast.toString(args.STRING1) + Cast.toString(args.STRING2);
|
|
|
|
}
|
|
|
|
|
|
|
|
letterOf (args) {
|
|
|
|
const index = Cast.toNumber(args.LETTER) - 1;
|
|
|
|
const str = Cast.toString(args.STRING);
|
|
|
|
// Out of bounds?
|
|
|
|
if (index < 0 || index >= str.length) {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
return str.charAt(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
length (args) {
|
|
|
|
return Cast.toString(args.STRING).length;
|
|
|
|
}
|
|
|
|
|
|
|
|
mod (args) {
|
|
|
|
const n = Cast.toNumber(args.NUM1);
|
|
|
|
const modulus = Cast.toNumber(args.NUM2);
|
|
|
|
let result = n % modulus;
|
|
|
|
// Scratch mod is kept positive.
|
|
|
|
if (result / modulus < 0) result += modulus;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
round (args) {
|
|
|
|
return Math.round(Cast.toNumber(args.NUM));
|
|
|
|
}
|
|
|
|
|
|
|
|
mathop (args) {
|
|
|
|
const operator = Cast.toString(args.OPERATOR).toLowerCase();
|
|
|
|
const n = Cast.toNumber(args.NUM);
|
|
|
|
switch (operator) {
|
|
|
|
case 'abs': return Math.abs(n);
|
|
|
|
case 'floor': return Math.floor(n);
|
|
|
|
case 'ceiling': return Math.ceil(n);
|
|
|
|
case 'sqrt': return Math.sqrt(n);
|
|
|
|
case 'sin': return parseFloat(Math.sin((Math.PI * n) / 180).toFixed(10));
|
|
|
|
case 'cos': return parseFloat(Math.cos((Math.PI * n) / 180).toFixed(10));
|
|
|
|
case 'tan': return MathUtil.tan(n);
|
|
|
|
case 'asin': return (Math.asin(n) * 180) / Math.PI;
|
|
|
|
case 'acos': return (Math.acos(n) * 180) / Math.PI;
|
|
|
|
case 'atan': return (Math.atan(n) * 180) / Math.PI;
|
|
|
|
case 'ln': return Math.log(n);
|
|
|
|
case 'log': return Math.log(n) / Math.LN10;
|
|
|
|
case 'e ^': return Math.exp(n);
|
|
|
|
case '10 ^': return Math.pow(10, n);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2016-08-11 12:05:58 -04:00
|
|
|
|
2016-06-09 14:29:07 -04:00
|
|
|
module.exports = Scratch3OperatorsBlocks;
|