Tile Matching Puzzle

A tile matching puzzle written in Preact.

by remarkablemark

HTML

<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/preact/8.2.6/preact.min.js"></script>

CSS

body {
  font-family: "Lucida Grande", Arial, sans-serif;
}

td {
  width: 40px;
  height: 24px;
}

td button {
  font-size: 14px;
  width: 36px;
  height: 21px;
}

.blue {
  color: #408000;
}

.yellow {
  color: #ffc000;
}

.red {
  color: #c00200;
}

.black {
  color: #000000;
}

Babel + JSX

const { h, render, Component } = window.preact; /** @jsx h */

/**
 * Generates a random number between zero and max (exclusive).
 *
 * @param  {Number} max
 * @return {Number}
 */
const random = max => Math.floor(Math.random() * max);

/**
 * Clones an array (depth = 2).
 *
 * @param  {Array} array
 * @return {Array}
 */
const clone = array => array.map(item => item.slice());

/**
 * Maps column to row for two-dimensional array. 
 *
 * @param  {Array} array
 * @return {Array}
 */
const mapColToRow = array => {
  const result = [];
  array.forEach((row, rowIndex) => {
    row.forEach((item, colIndex) => {
      result[colIndex] = result[colIndex] || [];
      result[colIndex][rowIndex] = item;
    });
  });
  return result;
};

/**
 * <TilePuzzle>
 */
class TilePuzzle extends Component {
  constructor(props) {
    super(props);
    this.state = {
      tiles: this.generateTiles(),
      clicks: 0,
      isSolved: false,
    };
  }

  /**
   * Generates two-dimensional tile array.
   *
   * @return {Array}
   */
  generateTiles = () => {
    const { tiles, rowSize, columnSize } = this.props;
    const rows = [];
    const tilesCount = tiles.length;
    for (let r = 0; r < rowSize; r++) {
      const columns = [];
      for (let c = 0; c < columnSize; c++) {
        const randomTile = tiles[random(tilesCount)];
        columns.push(randomTile);
      }
      rows.push(columns);
    }
    return rows;
  };

  /**
   * Removes tile item and then checks left, right, top, and bottom.
   *
   * @param  {Array}  array - The tile array to be mutated.
   * @param  {*}      item  - The tile item value.
   * @param  {Number} row   - The tile row index position.
   * @param  {Number} col   - The tile column index position.
   * @return {Array}
   */
  removeItem(array, item, row, col) {
    if (array[row][col] === undefined) return;
    array[row][col] = undefined;
    // left
    if (array[row][col - 1] === item) {
      this.removeItem(array, item, row, col - 1);
    }
   ...