const readline = require('readline');


const galtonBox = (layers, balls) => {
  const speed = 100;
  const ball = 'o';
  const peg = '.';
  const result = [];

  const sleep = ms => new Promise(resolve => {
    setTimeout(resolve,ms)
  });

  
  const board = [...Array(layers)]
      .map((e, i) => {
        const sides = Array(layers - i).fill(' ');
        const a = Array(i + 1).fill(peg).join(' ').split('');
        return [...sides, ...a, ...sides];
      });

  
  const emptyRow = () => Array(board[0].length).fill(' ');

  
  const bounce = i => Math.round(Math.random()) ? i - 1 : i + 1;

  
  const show = () => {
    readline.cursorTo(process.stdout, 0, 0);
    readline.clearScreenDown(process.stdout);
    board.forEach(e => console.log(e.join('')));
    result.reverse();
    result.forEach(e => console.log(e.join('')));
    result.reverse();
  };


  
  const appendToResult = idx => {
    const row = result.find(e => e[idx] === ' ');
    if (row) {
      row[idx] = ball;
    } else {
      const newRow = emptyRow();
      newRow[idx] = ball;
      result.push(newRow);
    }
  };

  
  const iter = () => {
    let hasNext = false;
    [...Array(bordSize)].forEach((e, i) => {
      const rowIdx = (bordSize - 1) - i;
      const idx = board[rowIdx].indexOf(ball);
      if (idx > -1) {
        board[rowIdx][idx] = ' ';
        const nextRowIdx = rowIdx + 1;
        if (nextRowIdx < bordSize) {
          hasNext = true;
          const nextRow = board[nextRowIdx];
          nextRow[bounce(idx)] = ball;
        } else {
          appendToResult(idx);
        }
      }
    });
    return hasNext;
  };

  
  const addBall = () => {
    board[0][apex] = ball;
    balls = balls - 1;
    return balls;
  };

  board.unshift(emptyRow());
  result.unshift(emptyRow());

  const bordSize = board.length;
  const apex = board[1].indexOf(peg);

  
  (async () => {
    while (addBall()) {
      await sleep(speed).then(show);
      iter();
    }
    await sleep(speed).then(show);
    while (iter()) {
      await sleep(speed).then(show);
    }
    await sleep(speed).then(show);
  })();


};

galtonBox(12, 50);