0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

make10パズルを解く

Last updated at Posted at 2023-12-09

記事概要

JSでmake10パズルを解く。
make10とは ⇓

4桁の数字を一桁の数字4つとみなし、これに四則演算などを用いて10を作る遊び。

wikiより

スクリプト

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('*************************************')
0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?