JSFiddle - React, Tailwind, and code Playground

by Farzad YZ

HTML

<div id="game"></div>

SCSS

* {
  box-sizing: border-box;
}

ul {
  &:after,
  &:before {
    display: table;
    content: ' ';
  }
  &:after {
    clear: both;
  }
  margin: 50px auto;
}

ul > li {
  border: 1px solid #eee;
  background-color: #fff;
  float: left;
  display: flex;
  justify-content: center;
  align-items: center;
  cursor: pointer;
}

Babel + JSX

function chunkArray(array, chunkSize) {
  var i, j, result = [];
  for (i = 0, j = array.length; i < j; i += chunkSize) {
    result.push(array.slice(i, i + chunkSize));
  }
  return result;
}

function isArrayWinner(array) {
  return array.every((el, i, arr) => {
    if (el == null || (i < arr.length - 1 && arr[i + 1].value == null)) return false;5
    if (i < arr.length - 1) return (el.value === arr[i + 1].value);
    return true;
  })
}

function generateCells(size) {
  let cells = [];

  for (let i = 0; i < size; i++) {
    for (let j = 0; j < size; j++) {
      cells.push({
        x: i,
        y: j,
        id: `${i}${j}`,
        value: null
      })
    }
  }

  return cells;
}

function getCellsMetaData(cells) {
  let diagonal = [],
    offDiagonal = [],
    rows = [],
    cols = [],
    size = Math.sqrt(cells.length);

  // detect diagonal out of cells
  diagonal = cells.filter(cell => cell.x === cell.y);

  // detect anti-diagonal out of cells
  for (let k = 0; k < size; k++) {
    const i = k,
      j = size - k - 1;
    offDiagonal.push({
      x: i,
      y: j,
      id: `${i}${j}`,
      value: null
    });
  }

  // detects rows from cells
  rows = chunkArray(cells, size);

  // detects columns from cells
  cols = rows.map(cellRow => {
    return cellRow.map(cRow => {
      let newCell = {};
      newCell.x = cRow.y;
      newCell.y = cRow.x;
      newCell.id = `${cRow.y}${cRow.x}`;
      newCell.value = cRow.value;

      return newCell;
    })
  });

  return {
    diagonal,
    offDiagonal,
    rows,
    cols
  }

}

function checkForWinner(cells) {
  const {
    diagonal,
    offDiagonal,
    rows,
    cols
  } = getCellsMetaData(cells);

  let winOn, winState;

  // Set winning state
  winState = isArrayWinner(diagonal) || isArrayWinner(offDiagonal) || rows.some(isArrayWinner) || cols.some(isArrayWinner);

  // Set winning on key
  if (isArrayWinner(diagonal)) winOn = 'diagonal';
  else if (isArrayWinner(offDiagonal)) winOn = 'offDiagonal';
...