ｍake10パズルを解く

# 記事概要
JSでmake10パズルを解く。  
make10とは  ⇓
> 4桁の数字を一桁の数字4つとみなし、これに四則演算などを用いて10を作る遊び。
> 
<a href="https://ja.wikipedia.org/wiki/%E3%83%86%E3%83%B3%E3%83%91%E3%82%BA%E3%83%AB" target="_blank">wiki</a>より


# スクリプト
```js
const calcAll = (a, q) => {
    let ANSER_LIST = []

    // 配列入れ替え
    const shuffleArray = (inputArray) => {
        return inputArray.sort(() => Math.random() - 0.5)
    }

    // 2次元配列作成
    const arrayCreation = (q) => {
        let results = [q]

        for (const qIndex in q) {
            let _results = results
            results = []
            _results.forEach((qList) => {
                // 渡されたINDEXより後ろを固定して列を再作成
                const result = qList.slice(qIndex).map((v1, i1) => {
                    const r2 = qList.slice(qIndex).filter((v2, i2) => i2 != i1)
                    return qList.slice(0, qIndex).concat([v1]).concat(r2)
                })
                results = results.concat(result)
            })
        }

        // 重複排除
        results = [...new Set(results.map(JSON.stringify))].map(JSON.parse)

        return results
    }

    // 与えられた数字の組み合わせリスト
    let calcNumList = arrayCreation(q)

    // 毎回違う個体になるように配列のシャッフル
    calcNumList = shuffleArray(calcNumList)

    // 四則演算の組み合わせリスト
    const calcSymbolList = []
    for (let i = 0; i < 4 ** (q.length - 1); i++) {
        const d = (Array(q.length - 1).fill(0).join('') + String(i.toString(4))).slice(-(q.length - 1)).split('')
            .map(v => v = v.replace(/0/g, '+').replace(/1/g, '-').replace(/2/g, '*').replace(/3/g, '/'))
        calcSymbolList.push(d)
    }

    // 逆ポーランド記法から中置記法に変換（検算用）
    const rpnToInfix = (expression) => {
        const stack = []
        const isOperator = (token) => ['+', '-', '*', '/'].includes(token)
        const isHigherPrecedence = (op1, op2) => {
            const precedence = { '+': 1, '-': 1, '*': 2, '/': 2 }
            return precedence[op1] >= precedence[op2]
        }
        const tokens = expression.split('')
        for (const token of tokens) {
            if (!isOperator(token)) {
                // 数値の場合、そのままスタックにプッシュ
                stack.push(token)
            } else {
                // 演算子の場合、スタックから適切な数のオペランドをポップし、中置記法の形に変換してスタックにプッシュ
                const operand2 = stack.pop()
                const operand1 = stack.pop()
                const infixExpression = `(${operand1}${token}${operand2})`
                stack.push(infixExpression)
            }
        }
        return stack.pop()
    }

    calcNumList.some((v1, i1) => {
        calcSymbolList.some((v2, i2) => {
            // 計算式を作成
            let formulaString = v1[0]
            for (let i3 = 0; i3 < v2.length; i3++) {
                if (v2[i3] === '+') {
                    formulaString = `${formulaString}${v2[i3]}${v1[i3 + 1]}`
                } else if (v2[i3] === '-') {
                    formulaString = `${formulaString}${v2[i3]}${v1[i3 + 1]}`
                } else if (v2[i3] === '*') {
                    formulaString = `${formulaString}${v2[i3]}${v1[i3 + 1]}`
                } else if (v2[i3] === '/') {
                    formulaString = `${formulaString}${v2[i3]}${v1[i3 + 1]}`
                }
            }

            // 式を配列に
            const ary1 = formulaString.split('')

            // 四則演算のINDEX（奇数が四則演算）
            const ary2 = arrayCreation(ary1.reduce((l, v, i) => { if (i % 2) { l.push(i) }; return l }, []))

            ary2.some((ary3) => {
                const ary5 = formulaString.split('')
                // 逆ポーランド記法文字列に変換
                let polandStr = ''
                ary3.some((ary4, idx4) => {
                    const num1 = Number(ary5[ary4 - 1])
                    const num2 = Number(ary5[ary4 + 1])
                    if (num1 && num2) {
                        polandStr = idx4 === 0 ? `${num1}${num2}${ary5[ary4]}` : ary3[idx4] > ary3[idx4 - 1] ? `${polandStr}${num1}${num2}${ary5[ary4]}` : `${num1}${num2}${ary5[ary4]}${polandStr}`
                    } else if (num1) {
                        polandStr = `${num1}${polandStr}${ary5[ary4]}`
                    } else if (num2) {
                        polandStr = `${polandStr}${num2}${ary5[ary4]}`
                    } else {
                        polandStr = `${polandStr}${ary5[ary4]}`
                    }
                    ary5[ary4 - 1] = null
                    ary5[ary4 + 0] = null
                    ary5[ary4 + 1] = null
                })

                if (a === eval(rpnToInfix(polandStr))) {
                    ANSER_LIST.push([rpnToInfix(polandStr), polandStr])
                    return true
                }
            })
            if (ANSER_LIST.length > 0) {
                return true
            }
        })
        if (ANSER_LIST.length > 0) {
            return true
        }
    })
    // 重複排除
    ANSER_LIST = Array.from(new Set(ANSER_LIST))
    return ANSER_LIST
}

// const a = 19
// const q = [2, 3, 6, 6]
const a = 14
const q = [1, 3, 4, 8, 8, 9]
console.log('q =>', q)
console.log('a =>', a)
console.log('*************************************')
let r = calcAll(a, q)
console.log('r =>', r[0][0], '=', eval(r[0][0]))
console.log('*************************************')
r = calcAll(a, q)
console.log('r =>', r[0][0], '=', eval(r[0][0]))
console.log('*************************************')
r = calcAll(a, q)
console.log('r =>', r[0][0], '=', eval(r[0][0]))
console.log('*************************************')
r = calcAll(a, q)
console.log('r =>', r[0][0], '=', eval(r[0][0]))
console.log('*************************************')
r = calcAll(a, q)
console.log('r =>', r[0][0], '=', eval(r[0][0]))
console.log('*************************************')
```