math | | Cell 1 | Search

The code generates all possible permutations of an input array and combines them with operator combinations to create mathematical equations in both standard and nested formats. It uses functions such as spliceClone, permute, solve, and reduce to generate and evaluate these equations, storing the results in variables like permutations, operators, and equations.

Cell 0

// permutation
function spliceClone(arr, i) {
    return (a => a.splice(i, 1).concat(a))
        // call it with a clone to preserve array reference
        ([].concat(arr))
}
function permute(array) {
    return array.reduce((acc, cv, ci, arr) => {
        const spliced = spliceClone(arr, ci);
        // recursive
        const perm = permute(spliced.slice(1))
            .map(p => spliced.slice(0, 1).concat(p));
        return acc.concat(perm);
    }, [].concat(array));
}

var permutations = permute([1,3,4,6])
    .filter(c => c.length === 4);

var op = ['+','-','*','/','^'];
var operators = op.reduce((acc, o) => acc.concat(op.reduce((acc2, o2) => acc2.concat(op.map(o3 => [o2, o3])), []).map(c => [o].concat(c))), [])
    .filter(c => c.length === 3);
//console.log(operators);
function solve(op, p) {
    switch(op) {
        case '+':
            return p[0] + p[1];
        case '-':
            return p[0] - p[1];
        case '*':
            return p[0] * p[1];
        case '/':
            return p[0] / p[1];
        case '^':
            return p[0] ^ p[1];
        case '%':
            return p[0] % p[1];
    }
}
var equations = operators.reduce((acc, o) => {
    return acc.concat(permutations.reduce((acc, p) => {
        acc.push([
            '(', p[0], o[0], p[1], ')', o[1], '(', p[2], o[2], p[3], ')',
            '=',
            solve(o[1], [
                solve(o[0], p),
                solve(o[2], p.slice(2))
            ])
               ]);
        acc.push([
            p[0], o[0], '(', p[1], o[1], '(', p[2], o[2], p[3], ')', ')',
            '=',
            solve(o[0], [
                p[0],
                solve(o[1], [
                p[1],
                solve(o[2], p.slice(2))
            ])
                ])
               ]);
        acc.push([
            '(', '(', p[0], o[0], p[1], ')', o[1], p[2], ')', o[2], p[3],
            '=',
            solve(o[2], [solve(o[1], [
                solve(o[0], p),
                p[2]
                ]),
                p[3]
            ])
               ]);
        return acc;
    }, []));
}, [])

for(var e of equations) { // .filter(e => e[12] === 24)) {
    console.log(e.join(' '))
}

What the code could have been:

/**
 * Generates all permutations of the given array.
 *
 * @param {Array} array The input array.
 * @returns {Array} An array of all permutations of the input array.
 */
function* permute(array) {
    if (array.length === 1) {
        yield array;
    } else {
        for (let i = 0; i < array.length; i++) {
            const rest = array.slice(0, i).concat(array.slice(i + 1));
            for (const perm of permute(rest)) {
                yield [array[i]].concat(perm);
            }
        }
    }
}

/**
 * Creates a new array by removing the element at the given index and concatenating the rest of the array.
 *
 * @param {Array} array The input array.
 * @param {Number} i The index of the element to remove.
 * @returns {Array} A new array with the element at the given index removed.
 */
function spliceClone(array, i) {
    return [...array.slice(0, i),...array.slice(i + 1)];
}

/**
 * Creates a deep clone of the given array.
 *
 * @param {Array} array The input array.
 * @returns {Array} A deep clone of the input array.
 */
function cloneArray(array) {
    return [...array];
}

/**
 * Represents an arithmetic operator.
 */
class Operator {
    constructor(op, precedence) {
        this.op = op;
        this.precedence = precedence;
    }
}

/**
 * Represents a binary expression.
 */
class BinaryExpression {
    constructor(left, op, right) {
        this.left = left;
        this.op = op;
        this.right = right;
    }
}

/**
 * Represents an equation.
 */
class Equation {
    constructor(left, op, right, equals) {
        this.left = left;
        this.op = op;
        this.right = right;
        this.equals = equals;
    }
}

/**
 * Generates all possible equations by combining permutations of a given array with a set of operators.
 *
 * @param {Array} array The array to permute.
 * @param {Array} operators The set of operators to use.
 * @returns {Array} An array of all possible equations.
 */
function generateEquations(array, operators) {
    for (const perm of permute(array)) {
        for (const op1 of operators) {
            for (const op2 of operators) {
                for (let i = 0; i < perm.length - 1; i++) {
                    const left = perm.slice(0, i + 1);
                    const right = perm.slice(i + 1);
                    const equation = new Equation(
                        new BinaryExpression(
                            new BinaryExpression(
                                new BinaryExpression(perm[0], op1.op, perm[1]),
                                op1.op,
                                new BinaryExpression(perm[2], op2.op, perm[3])
                            ),
                            op1.op,
                            new BinaryExpression(perm[4], op2.op, perm[5])
                        ),
                        '=',
                        solve([op1.op, op2.op], perm)
                    );
                    yield equation;
                }
            }
        }
    }
}

/**
 * Evaluates a binary expression.
 *
 * @param {Array} op The operators used in the expression.
 * @param {Array} values The values used in the expression.
 * @returns {Number} The result of the expression.
 */
function solve(op, values) {
    if (op.length === 1) {
        return values[0];
    } else {
        const left = values.slice(0, 2);
        const right = values.slice(2);
        switch (op[0]) {
            case '+':
                return left[0] + left[1];
            case '-':
                return left[0] - left[1];
            case '*':
                return left[0] * left[1];
            case '/':
                return left[0] / left[1];
            case '^':
                return left[0] ^ left[1];
            case '%':
                return left[0] % left[1];
        }
    }
}

// Define the operators and their precedence
const operators = [
    new Operator('^', 2),
    new Operator('*', 2),
    new Operator('/', 2),
    new Operator('%', 2),
    new Operator('+', 1),
    new Operator('-', 1)
];

// Generate all possible equations
const equations = Array.from(generateEquations([1, 3, 4, 6], operators));

// Print the equations
for (const equation of equations) {
    const left = equation.left;
    const right = equation.right;
    const equals = equation.equals;
    const op1 = equation.op;
    const op2 = op1.left.op;
    const op3 = op1.right.op;
    console.log(`(${left} ${op2} ${right.left}) ${op1.op} (${right.right}) ${op3} (${equals})`);
}

Code Breakdown

Function: spliceClone(arr, i)

Function: permute(array)

Variable: permutations

Function: solve(op, p)

Variable: operators

Function: reduce and concat Used in operators Generation

Variable: equations

Function: reduce Used in equations Generation

Equation Generation