Как сделать число 100 из любого другого шестизначного числа

Подскажите пожалуйста как построить алгоритм работы над шестизначным числом так, что бы узнать можно ли путем математических манипуляций, из цифр которых оно состоит получить 100?
Пример:
050500 ---> (0 + 50 + 50 + 0) == 100
595545 ---> (5 + ((9 * 5) + (5 + 45))) = 100
093342 ---> (0 + ((9 / (3 / 34)) - 2)) = 100
231357 ---> (2 - (3 * (((1 / 3) - 5) * 7))) = 100
...
я нашел статью на Хабр (https://habr.com/ru/post/339654/) в которой приводился аналогичный пример.

Привести 6-значное число к массиву из цифр не проблема.
Например: a = 123456;
тогда String(a).split('').map(e => +e) // output ---> [1,2,3,4,5,6]

А вот как дальше расставлять символы (+, -, /, *) и правильно расставить скобки, я хоть убейте не могу придумать :( Бьюсь над этой задачей уже месяц. Хотел сделать так как описано в статье с Хабр (см выше), но не могу понять как в java script это реализовать? И можно ли вообще в JS создавать подобные "динамические" формулы или за ранее нужно прописывать шаблоны под действия, а уже в них подставлять цифры???

Задайте пожалуйста хоть направление в котором думать.


Ответы (3 шт):

Автор решения: lijil

Пример без скобок.

     let num = '231357'. split ('');
     let opr = ['*','+','/','-'];
     for(let i = 0 ; i < 32 ; i ++ ){
         let part = i . toString ( 2 )
         . padStart ( 5 , '0')
         . split ('')
         . reduce (( s , v , i , a , j = ++ i )=>{ 
             return + v ? `${ s }${ num [ j ]}` 
                 : `${ s }λ${ num [ j ]}`;
         }, num [ 0 ])
         . replace (/(\D|^)0*(\d)/g,'$1$2');
         for(let i = 0 ; i < Math . pow ( 4 , part . split (/\D/). length - 1 ) ; i ++ ){
             let mask = i . toString ( 4 ). padStart ( 5 ,'0');
             let math = part 
             . replace ('λ', opr [ mask [ 4 ]])
             . replace ('λ', opr [ mask [ 3 ]])
             . replace ('λ', opr [ mask [ 2 ]])
             . replace ('λ', opr [ mask [ 1 ]])
             . replace ('λ', opr [ mask [ 0 ]])
             let result = eval (`(function(){return ${ math }})()`);
             if( result === 100 ){
                 console .  log ('%s === %s', math , result );
             }
         }
     }

Код запускается но не во всех браузерах, получаю две ошибки:

EvalError:<br/> "call to eval() blocked by CSP" 

и

(function(){return 0*0*0*0*00})() SyntaxError: Octal literals are not allowed in strict mode.

Подскажите, что с этим можно сделать, и что я делаю не так?


Касательно второй:

. replace (/(\D|^)0*(\d)/,'$1$2');

Тут ошибка была. Эта часть заменяет "073" на "73", т.к. 073 === 59. В "use strict" такая восьмеричная запись числа - ошибка. Без 'g' флага заменялось только первое совпадение. Наглядная польза от strict, без него ошибок нет, а результаты неверные =)

→ Ссылка
Автор решения: IvaMuxa

//let num = '093342'.split('');
let num = prompt().replace(/(\D*)/g,'').split('').slice(0, 6);;
console.log(num.join(""));
let e = [];

for (let i = 0; i < Math.pow(2, num.length - 1); i++) {
  let part = i.toString(2)
    .padStart(num.length-1, '0')
    .split('')
    .reduce((s, v, i, a) => {
      return +v ? `${ s }${ num [ i+1 ]}` :
        `${ s }|${ num [ i+1 ]}`;
    }, num[0]).replace (/(\D|^)0*(\d)/g,'$1$2').split('|');
  let ao = co(part.length-1);
  for (let i = 0; i < Math.pow(4, part.length - 1); i++) {
    let mask = i.toString(4).padStart(part.length - 1, '0').split('');
    ao.forEach(order => {
      let math = or(order.slice(), part.slice(), mask.slice());
      if(100==eval (`(function(){return ${ math }})()`)&& !e.find((s)=>{return s==math})){
        e.push(math);
        document.writeln (`${math} = 100<br/>`);
      }
    });
  }
}
console.log(`найдено ${e.length} вариантов`); 
 
function or(order, nums, funcs){
  order.reduce((s, v, i, a) => {
        let br = (i == a.length-1)?false:true; 
        nums[v] = op(nums[v], nums[v+1], funcs[v], br);
        nums.splice(v+1, 1);
        funcs.splice(v,1);
        for(let iii = i; iii<a.length; iii++){if(a[iii]>v)a[iii]--;}
  },"")
  return nums[0];
}

function op(a,b,o,p){
  let r = "";
  switch(o){
    case "0":
      r = `${a}+${b}`;
      break;
    case "1":
      r = `${a}-${b}`;
      break;
    case "2":
      r = `${a}*${b}`;
      break;
    case "3":
      r = `${a}/${b}`;
      break;
  }
  
  return (p?`(${r})`:`${r}`);
}

function co(l) {
  if (l <= 1) return [];
  let os = [];

  let oo = [];
  while (l) {
    l--;
    oo.push(l);
  }

  for (let i = 0; i < fc(oo.length); i++) {
    let o = oo.slice();
    os[i] = [];
    let ii = i;
    while (o.length) {
      let ff = fc(o.length-1);
      let ix = Math.floor(ii / ff );
      ii -= ix*ff;
      os[i].push(o.splice(ix, 1)[0]);
    }
  }
  return os;
}

function fc(x) {
  let r = 1;
  for (let i = 1; i <= x; ++i) {
    r *= i;
  }
  return r;
}

Теперь визуально идентичные решения с разными порядками выполнения исключаются

→ Ссылка
Автор решения: kvit_ko
function makeHudred(n) {
  const variants = [];
  for (let split of makeSplits('' + n)) {
    for (let operations of makeOperations(split)) {
      for (let order of makeOrders(operations)) {
        variants.push(makeExpression(split, operations, order));
      }
    }
  }
  console.log('Variants in array:', variants.length);
  const filteredVariants = [...new Set(variants)]
  console.log('Variants in filtered array:', filteredVariants.length);
  filteredVariants.forEach(variant => check(variant, 100));
}

function makeSplits(str) {
  const res = [];
  for (let i = 0; i < 2 ** (str.length - 1); i++) {
    const mask = i.toString(2).padStart(str.length - 1, '0');
    const maskArr = [...mask];

    const arr = [str[0]];
    for (let i = 0; i < maskArr.length; i++) {
      if (maskArr[i] == 0) {
        arr[arr.length - 1] += str[i + 1];
      } else {
        arr.push(str[i + 1]);
      }
    }
    res.push(arr);
  }
  return res;
}

function makeOperations(split) {
  const len = split.length - 1;
  const res = [];
  for (let i = 0; i < (len ? 4 ** len : 0); i++) {
    const mask = i.toString(4).padStart(len, '0');
    const maskArr = [...mask];
    res.push(maskArr.map(getSymbol));
  }
  return res;

  function getSymbol(n) {
    switch (+n) {
      case 0: return '+';
      case 1: return '-';
      case 2: return '*';
      case 3: return '/';
    }
  }
};

function makeOrders(operation) {
  const len = operation.length;
  const arr = new Array(len).fill(0).map((_, i) => i);
  return permute(arr);
}

function makeExpression(split, operations, order) {
  const splitC = split.slice(),
    operationsC = operations.slice(),
    orderC = order.slice();
  for (let el of new Array(orderC.length).fill(0).map((_, i) => i)) {
    i = orderC.findIndex(n => n === el);
    splitC[i] = `(${splitC[i]}${operationsC[i]}${splitC[i + 1]})`

    splitC.splice(i + 1, 1)
    operationsC.splice(i, 1)
    orderC.splice(i, 1)
  }

  return splitC.pop();
}

function permute(arr) {
  const res = [];

  const permute = (arr, m = []) => {
    if (!arr.length) return res.push(m);
    for (let i = 0; i < arr.length; i++) {
      const cur = arr.slice();
      const next = cur.splice(i, 1);
      permute(cur.slice(), m.concat(next))
    }
  }

  permute(arr);
  return res;
}

function check(expr, n) {
  const res = eval(expr);
  if (res == n) {
    console.log(`${expr} = ${n}`);
  }
}

Мне попалось такое вот решение

→ Ссылка