18
\$\begingroup\$

Challenge

You will be given a positive integer n as input. Output should be a pyramid-like sandpile built on the rules specified below:

  • Each integer "falls" downward from the same initial starting point, like sand falling into a conal-shape.
  • Numbers greater than the number directly below it when it hits the sandpile will fall to the right, if able.
  • Numbers less than the number directly below it when it hits the sandpile will fall to the left, if able.
  • Numbers equal to the number directly below it when it hits the sandpile will stay in place.
  • Numbers are able to fall to the left/right if they can move down and to the left/right respectively. That is, if there is already a number below and to the left/right, depending on the direction, the currently falling number does not move.
  • A number will continue to tumble down the sandpile until it cannot be moved into its next position, or hits the floor.

Notes

The initial comparison check only applies to the first encountered integer, not for each successive encounter as it tumbles down the sandpile.

Trailing spaces are okay but trailing new lines are not.

No leading spaces or new lines except where needed to preserve the structure of the sandpile.

You may write a full program or function.

You may assume input will only contain some combination [0-9].

This is , shortest code in bytes will be marked winner by the Ides of March

Examples

1

1


12345

35
124


54321

 13
245


555444333222111

    2
    2
    2
  135
 1345
13445


111222333444555

4
4
4
135
1235
12235


7313623030872935273465247457435345345350

    3
    3
    3
    3
    34
    355
    3644
   239475
  201277445
020373685575
\$\endgroup\$
  • \$\begingroup\$ 555444333222111 is that a mistake that the third 4 will fall left to the first 4? \$\endgroup\$ – andlrc Feb 23 '16 at 0:05
  • \$\begingroup\$ @dev-null numbers will continue to 'tumble', if you will, so long as they are able - remember, the greater/less/equal check only applies to the first encounter. \$\endgroup\$ – CzarMatt Feb 23 '16 at 0:07
4
\$\begingroup\$

JavaScript (ES6), 260 208 bytes

s=>[...s].map(c=>a[g(n,(c>(l=a[n].slice(-1)))-(c<l))]+=c,n=s.length,a=Array(n+n).fill(''),g=(i,d)=>a[i].length>a[i+d].length?g(i+d,d):n)&&[...a[n]].map((_,i)=>a.map(c=>c?c[i]||' ':c).join``).reverse().join`\n`

Edit: Saved 25 bytes by realising that the first character isn't a special case. Saved 15 bytes by using an array of strings instead of an array of arrays of chars. Saved 12 bytes in miscellaneous fixes, including using a literal \n (not shown). That makes this whole 20% shorter! I wanted to get rid of reverse but that costs more than I can then save by replacing map with replace.

Ungolfed:

function sandpile(str) {
    var arr = new Array(str.length * 2); // max width of sandpile is approx. 2√n but this is close enough
    for (i = 0; i < arr.length; i++) arr[i] = '';
    for (i = 0; i < str.length; i++) {
        var digit = str[i];
        var pos = str.length; // start dropping here
        if (digit < str[pos][str[pos].length - 1]) {
            while (str[pos - 1].length < str[pos].length) pos--;
        } else if (digit > str[pos][str[pos].length - 1]) {
            while (str[pos + 1].length < str[pos].length) pos++;
        }
        str[pos] += digit; // drop the digit
    }
    var len = arr[str.length].length; // final height
    // remove the unused columns, and then pad the columns with spaces for the transpose
    for (i = 0; i < arr.length; ) {
        if (!arr[i]) arr.splice(i, 1);
        else arr[i++] += ' '.repeat(len);
    }
    ans = '';
    for (i = len; i-- > 0; ) {
        for (j = 0; j < arr.length; j++) ans += arr[j][i];
        ans += '\n';
    }
    return ans;
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.