Search code examples
javascriptrecursioncomputer-science

How to un-nest this recursive algorithm in javascript?


In the game idle heroes, demon bells can be level 1,2,3,4. A level 4 is made of 4 level 1, a level 3 is made of 3 level 1 and so on.

I want to find all arrangements of db given a fixed number. I made this recursive algorithm in javascript:

Closer with a more simplified approach:

function findDB(numDB, arr) {
  console.log("findDB"+numDB);
  if (numDB == 1) {
    console.log("HERE2");
    return 1;
  } else {
    for (let i = 1; i < numDB; i++) {
      console.log("FOR"+i);
      console.log("COND" +(numDB + (numDB-i)));
      if((numDB + (numDB-i)) > numDB+1)
        continue;
      arr= arr.concat([numDB,[i,findDB(numDB - i, arr)]]);
    }
    return arr;
  }
}
var final = []
var y = findDB(3, final);
console.log(JSON.stringify(y));

Output:

findDB(2) CORRECT!

findDB2
FOR1
COND3
findDB1
HERE2
[2,[1,1]]

FindDB(3) is missing 1,1,1,

findDB3
FOR1
COND5
FOR2
COND4
findDB1
HERE2
[3,[2,1]]

here is intended output for input 1 through 6 (algo needs to scale for any number input)

    /1/ (1)
    /2/ (2),
        (1,1)
    /3/ (3),
        (2,1),
        (1,1,1)
    /4/ (4),
        (3,1),
        (2,2),(2,1,1),
        (1,1,1,1)
    /5/ (4,1),
        (3,2),(3,1,1),
        (2,2,1),(2,1,1,1),
        (1,1,1,1,1)
    /6/ (4,2),(4,1,1),
        (3,3),(3,2,1),(3,1,1,1),
        (2,2,2),(2,2,1,1),(2,1,1,1,1)
        (1,1,1,1,1,1)

Solution

  • Here is a recursive function that produces the results you want. It attempts to break down the input (numDB) into parts up to the maximum number (maxDB, which defaults to 4). It does this by taking the numbers from numDB down to 1 and adding all the possible results from a recursive call to that number, noting that the value of maxDB has to change to be no more than the first number.

    const findDB = function(numDB, maxDB = 4) {
      if (numDB == 0) return [ [] ];
      let result = [];
      let thisDB = Math.min(numDB, maxDB);
      for (let i = thisDB; i > 0; i--) {
        findDB(numDB - i, Math.min(i, thisDB)).forEach(n => {
          result.push([i].concat(n));
        });
      }
      return result;
    }
    ;
    [6, 5, 4, 3, 2, 1].forEach((i) => console.log(JSON.stringify(findDB(i))))
    .as-console-wrapper {
      min-height: 100% !important;
    }

    I've written the above function in the style in your question, with the use of various ES6 Array methods it can be simplified:

    const DBlist = (n) => [...Array(n).keys()].map(k => n - k)
    
    const findDB = (numDB, maxDB = 4) => {
      if (numDB == 0) return [ [] ];
      const thisDB = Math.min(numDB, maxDB);
      return DBlist(thisDB).flatMap((i) => findDB(numDB - i, Math.min(i, thisDB)).map(a => [i, ...a]))
    }
    
    DBlist(6).forEach((n) => console.log(JSON.stringify(findDB(n))))
    .as-console-wrapper {
      min-height: 100% !important;
    }