javascriptchallenge-response

Double Cola Challenge, JavaScript code wrong?


Five friends are drinking magic cola in an line. When the first friend drinks the cola he disappears, and multiplies into two copies! After that, those new copies go to the end of the line and the next friend drinks the magic cola, repeating the proccess.

For example, imagine we have the following friends:

[Sheldon, Leonard, Penny, Rajesh, Howard]

After Sheldon drinking the first cola, the line will look like this:

[Leonard, Penny, Rajesh, Howard, Sheldon, Sheldon]

After Leonard drinking the cola, the line gets like this:

[Penny, Rajesh, Howard, Sheldon, Sheldon, Leonard, Leonard]

And so on...

My objective is to write a function in JavaScript, that given an array with the names of the people in the line, and a number N, it will return the the name of the N-ith person drinking the magic cola.

So, for example, doing console.log(whoIsNext([Sheldon, Leonard, Penny, Rajesh, Howard], 1)) should return Sheldon.

To achieve this, I made this code:

function whoIsNext(names, r){
  var fistInLine;

  if(r <= names.length){
    return names[r-1];
  }else{

    while(r > names.length){
      fistInLine = names.shift();
      names.push(fistInLine, fistInLine);
    }
    return names[r-1];
  }
}

This function works well for the following case:

names = ["Sheldon", "Leonard", "Penny", "Rajesh", "Howard"];
Test.assertEquals(whoIsNext(names, 1), "Sheldon");

But it fails for the test:

names = ["Sheldon", "Leonard", "Penny", "Rajesh", "Howard"];
Test.assertEquals(whoIsNext(names, 52), "Penny");

And if I try with a really big number, like:

names = ["Sheldon", "Leonard", "Penny", "Rajesh", "Howard"];
Test.assertEquals(whoIsNext(names, 7230702951), "Leonard");

It doesn't even stop running (takes forever).

So obviously, my solution is not only incorrect, it seems to be inneficient as well. How can I fix it?


Solution

  • A zero based recursive proposal which returns the index of the array, here with length base = 5.

                               1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3
    number 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
    index  0 1 2 3 4 0 0 1 1 2 2 3 3 4 4 0 0 0 0 1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4 0 0 0 0 0
    

    It become visible, the pattern is based on 5 and goes up for every round by factor 2.

    5 -> 10- > 20 -> 40
    

    Example of calculation

                    Array after step
                    0 1 2 3 4 5 6 7 8 9 
      0: 0 Sheldon  | 
      1: 1 Leonard  | |
      2: 2 Penny    | | |
      3: 3 Rajesh   | | | |
      4: 4 Howard   | | | | |
      5: 0 Sheldon    | | | | |
      6: 0 Sheldon    | | | | | |
      7: 1 Leonard      | | | | | |
      8: 1 Leonard      | | | | | | |
      9: 2 Penny          | | | | | |
     10: 2 Penny          | | | | | |
     11: 3 Rajesh           | | | | |
     12: 3 Rajesh           | | | | |
     13: 4 Howard             | | | |
     14: 4 Howard             | | | |
     15: 0 Sheldon              | | |
     16: 0 Sheldon              | | |
     17: 0 Sheldon                | |
     18: 0 Sheldon                | |
     19: 1 Leonard                  |
     20: 1 Leonard                  |
     21: 1 Leonard
     22: 1 Leonard
    

    var friends = ['Sheldon', 'Leonard', 'Penny', 'Rajesh', 'Howard'],
        base = friends.length;
    
    function getIndex(n, i) {
        i = i || base;
        if (n < i) {
            return Math.floor(n * base / i);
        }
        return getIndex(n - i, 2 * i);
    }
    
    var i = 0, index;
    
    document.write(friends[getIndex(1 - 1)] + '<br>');          // "Sheldon"
    document.write(friends[getIndex(52 - 1)] + '<br>');         // "Penny"
    document.write(friends[getIndex(7230702951 - 1)] + '<hr>'); // "Leonard"
    
    for (i = 0; i < 200; i++) {
        index = getIndex(i);
        document.write(i + ': ' + index + ' ' + friends[index] + '<br>');
    }