JSFiddle - React, Tailwind, and code Playground

by acbabis

HTML

<button class="advance">
  Advance
</button>
<label>Run <input type="checkbox" class="run"></label>
<label>Delay <input type="text" class="delay" value="1000"></label>

SCSS

$cell-width: 15px;
.row {
  height: $cell-width;
}

.cell {
  display: inline-block;
  width: $cell-width;
  height: $cell-width;
  background-color: #999;
  border: solid 1px #666;
}

.cell.alive {
  background-color: yellow;
}

JavaScript

const WIDTH = 20;

let grid = new Array(WIDTH).fill(0).map(() => new Array(WIDTH).fill(false));
const gridDom = buildDom(grid);
const checkbox = document.querySelector('.run');
const delay = document.querySelector('.delay');

function elemHelper(elemName, className) {
  const elem = document.createElement(elemName);
  elem.classList.add(className);
  return elem;
}

function buildDom(grid) {
  const gridDom = elemHelper('div', 'grid');
  grid.map((row) => {
    const rowDom = elemHelper('div', 'row');
    row.forEach(() => rowDom.appendChild(elemHelper('div', 'cell')));
    return rowDom;
  }).forEach((row) => gridDom.appendChild(row));
  document.body.appendChild(gridDom);
  return gridDom;
}

function refresh(grid) {
  Array.from(gridDom.children).forEach(function(row, y) {
    Array.from(row.children).forEach(function(cell, x) {
      cell.classList.toggle('alive', grid[x][y]);
    })
  })
}

function getCell(grid, x, y) {
  const col = grid[x];
  return col && col[y] || false;
}

function getNeighborsCount(grid, x, y) {
  return [
    getCell(grid, x - 1, y - 1),
    getCell(grid, x - 0, y - 1),
    getCell(grid, x + 1, y - 1),
    getCell(grid, x - 1, y + 0),
    getCell(grid, x + 1, y + 0),
    getCell(grid, x - 1, y + 1),
    getCell(grid, x - 0, y + 1),
    getCell(grid, x + 1, y + 1)
  ].filter(Boolean).length;
}

function nextState(grid) {
  return grid.map(function(col, x) {
    return col.map(function(cell, y) {
      const neighborsCount = getNeighborsCount(grid, x, y);
      if (neighborsCount === 2) {
        return cell;
      } else {
        return neighborsCount === 3;
      }
    })
  });
}

function getCoords(cellDom) {
  const rowDom = cellDom.parentElement;
  const gridDom = rowDom.parentElement;
  const x = Array.prototype.indexOf.call(rowDom.children, cellDom);
  const y = Array.prototype.indexOf.call(gridDom.children, rowDom);
  return { x, y };
}

gridDom.addEventListener('click', function(event) {
	const target = event.target;
 ...