ルール
4つの4を使って、答えが1から10までの数になる数式を作る。
ただし演算子は足し算、引き算、掛け算、割り算、数と数の結合(※)のみOK。
(※ 例えば4と4を横に並べて44と見なすこと)
(自分の)考え方
[a, b, c, d]からxを作る。
=> [e, f, g]からxを作る。(eは[a, b, c, d]の2要素を加工した値、f,gは残りの2要素)
=> [h, i]からxを作る。(hは[e, f, g]の2要素を加工した値、iは残りの1要素)
終わり
実装
ソース
function 計算式を求める(計算式の配列, 答えの値, _再帰呼び出しか) {
const 再帰呼び出しか = _再帰呼び出しか === undefined ? false : _再帰呼び出しか;
for (let i = 0; i < 計算式の配列.length - 1; i++) {
for (let j = i + 1; j < 計算式の配列.length; j++) {
const 計算式1 = 計算式の配列[i];
const 計算式2 = 計算式の配列[j];
const 残りの計算式の配列 = (function() {
const 計算式の配列_クローン = 計算式の配列.concat();
計算式の配列_クローン.splice(j, 1);
計算式の配列_クローン.splice(i, 1);
return 計算式の配列_クローン;
})();
const 演算子達 = [足し算, 引き算, 引き算_交換, 掛け算, 割り算, 割り算_交換, 数字結合, 数字結合_交換];
for (let k = 0; k < 演算子達.length; k++) {
const 演算子 = 演算子達[k];
const 計算式の一部分 = 演算子(計算式1, 計算式2);
let 計算結果;
try {
計算結果 = eval(計算式の一部分);
}
catch (e) {
continue;
}
// 無限、NaNは無視する。
if (isFinite(計算結果) === false) continue;
if (計算式の配列.length === 2) {
if (計算結果 === 答えの値) {
return 再帰呼び出しか ? 計算式の一部分 : 邪魔な括弧を消す(計算式の一部分);
}
}
else {
const 新たな計算式の配列 = 残りの計算式の配列.concat(計算式の一部分);
const 計算式 = 計算式を求める(新たな計算式の配列, 答えの値, true);
if (計算式 !== null) {
return 再帰呼び出しか ? 計算式 : 邪魔な括弧を消す(計算式);
}
}
}
}
}
return null;
}
// ※ IE11でも動かしたいのでアロー演算子は使用していません。
function 足し算(a, b) {return "(" + a + "+" + b + ")";}
function 引き算(a, b) {return "(" + a + "-" + b + ")";}
function 引き算_交換(a, b) {return "(" + b + "-" + a + ")";}
function 掛け算(a, b) {return "(" + a + "*" + b + ")";}
function 割り算(a, b) {return "(" + a + "/" + b + ")";}
function 割り算_交換(a, b) {return "(" + b + "/" + a + ")";}
function 数字結合(a, b) {return String(a) + String(b);}
function 数字結合_交換(a, b) {return String(b) + String(a);}
function 邪魔な括弧を消す(計算式) {
if (計算式 === null) return null;
if (計算式[0] === "(" && 計算式[計算式.length - 1] === ")") {
return 計算式.slice(1).slice(0, -1);
}
return 計算式;
}
実践
console.log("4つの4");
for (let num = 1; num <= 10; num++) {
console.log(num + ": " + 計算式を求める([4, 4, 4, 4], num));
}
console.log("おまけ");
console.log("10: " + 計算式を求める([1, 1, 5, 8], 10));
console.log("100: " + 計算式を求める([1, 2, 3, 4, 5, 6, 7, 8, 9], 100));
console.log("810: " + 計算式を求める([1, 1, 4, 5, 1, 4], 810));
出力
4つの4
1: (4+4)/(4+4)
2: (4*4)/(4+4)
3: (4+(4+4))/4
4: 4+(4*(4-4))
5: (4+(4*4))/4
6: 4+((4+4)/4)
7: (4+4)-(4/4)
8: (4+4)+(4-4)
9: (4+4)+(4/4)
10: (44-4)/4
おまけ
10: 8/(1-(1/5))
100: (9+(1+2))-((5+6)*((3+4)-(7+8)))
810: 5*((4*41)-(1+1))
OK
チラ裏
今回のプログラムはただ単に目的の答えを求めるだけのプログラムなのでいろいろとゴミです。
頭のいい人は速くするためにメモ化したり、可読性をあげるために素敵な命名をしてください。