Game Of Life

In this example below you will see how to do a Game Of Life with some HTML / CSS and Javascript

Thumbnail
This awesome code was written by 0damian, you can see more from this user in the personal repository.
You can find the original code on Codepen.io
Copyright 0damian ©

Technologies

  • HTML
  • CSS
  • JavaScript
<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  <title>Game Of Life</title>
  
  
  
      <link rel="stylesheet" href="css/style.css">

  
</head>

<body>

  <div id="app"></div>
  <script src='https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react-dom.min.js'></script>

  

    <script  src="js/index.js"></script>




</body>

</html>

/*Downloaded from https://www.codeseek.co/0damian/game-of-life-pEqWRv */
body {
  background: #e5e5e5;
  padding: 1em;
  font-family: 'Open Sans', sans-serif;
}
body h1, body h2, body a, body p, body span {
  font-weight: 200;
  color: #555;
}
body h1, body h2, body a {
  display: table;
  margin: 0 auto 0.5em;
  padding-bottom: 0.1em;
  border-bottom: 1px solid #555;
}
body a {
  text-decoration: none;
  margin: 1em auto;
}
body a:hover {
  color: royalblue;
  border-bottom: 1px solid royalblue;
}
body div.explain {
  display: table;
  margin: 0 auto;
}
body div.explain * {
  display: inline-block;
}
body div.explain span {
  margin: 0 0.5em;
}
body div.explain p {
  border-left: 1px solid #555;
  padding-left: 0.5em;
}
body div.grid {
  text-align: center;
  margin-bottom: 1em;
  line-height: 0.8em;
}
body svg {
  width: 0.8em;
  height: auto;
}
body div.ctrl {
  display: table;
  margin: 0 auto;
}
body div.ctrl input[type='button'] {
  margin: 0 1em;
  background: #e5e5e5;
  border: 1px solid #555;
  color: #555;
  font-size: 1em;
}
body div.ctrl input[type='button']:hover {
  cursor: pointer;
  background: royalblue;
  border: 1px solid royalblue;
  color: #e5e5e5;
}
body div.ctrl input[type='button']:disabled, body div.ctrl input[type='button']:disabled:hover {
  background: #e5e5e5;
  border: 1px solid #b5b5b5;
  color: #b5b5b5;
}
body div.ctrl input[type='button'].active {
  border: 1px solid royalblue;
}


/*Downloaded from https://www.codeseek.co/0damian/game-of-life-pEqWRv */
var GameOfLife = React.createClass({
  displayName: 'GameOfLife',

  getInitialState: function getInitialState() {
    return {
      width: Number(this.props.width),
      interval: 250,
      count: 0,
      active: false
    };
  },
  componentWillMount: function componentWillMount() {
    this.setState({
      gridArray: this.makeGridArray(this.props.width)
    });
  },
  makeGridArray: function makeGridArray(width) {
    var maxX = width,
        maxY = width - 30,
        max = maxX * maxY,
        gridArray = [],
        i,
        j,
        cell,
        neighbours;
    for (i = 1; i <= maxY; i++) {
      for (j = 1; j <= maxX; j++) {
        var neighbours = this.getNeighbours([j, i]);
        cell = {
          x: j,
          y: i,
          status: 'dead',
          neighbours: neighbours
        };
        gridArray.push(cell);
      }
    }
    var seed = seedArray.sort();
    for (var k = 0; k < gridArray.length; k++) {
      if (seed.indexOf(k) > -1) {
        gridArray[k].status = 'newborn';
        seed.shift();
      }
    }
    return gridArray;
  },
  getNeighbours: function getNeighbours(arr) {
    var x = arr[0],
        y = arr[1],
        output;
    output = [{ x: x, y: y - 1 }, { x: x + 1, y: y - 1 }, { x: x + 1, y: y }, { x: x + 1, y: y + 1 }, { x: x, y: y + 1 }, { x: x - 1, y: y + 1 }, { x: x - 1, y: y }, { x: x - 1, y: y - 1 }];
    for (var i = 0; i < 8; i++) {
      if (!output[i].x) output[i].x = this.state.width;
      if (output[i].x > this.state.width) output[i].x = 1;
      if (!output[i].y) output[i].y = this.state.width - 30;
      if (output[i].y > this.state.width - 30) output[i].y = 1;
    }
    return output;
  },
  playPauseGame: function playPauseGame(e) {
    e.preventDefault();
    if (e.target.value == 'play') {
      this.setState({
        active: true
      });
      this.cycle = setInterval(this.cycleLife, this.state.interval);
    } else {
      clearInterval(this.cycle);
      this.setState({
        active: false
      });
    }
  },
  clearGame: function clearGame(e) {
    e.preventDefault();
    this.setState({
      gridArray: this.makeGridArray(this.state.width),
      count: 0
    });
  },
  resizeGrid: function resizeGrid(e) {
    e.preventDefault();
    var newWidth = Number(e.target.name);
    if (this.state.width != newWidth) {
      this.setState({
        width: Number(e.target.name),
        gridArray: this.makeGridArray(newWidth)
      });
    }
  },
  setInterval: function setInterval(e) {
    e.preventDefault();
    if (this.state.interval != Number(e.target.name)) {
      this.setState({
        interval: e.target.name
      });
    }
  },
  handleCellClick: function handleCellClick(data) {
    var newGrid = this.state.gridArray;
    for (var k = 0; k < newGrid.length; k++) {
      if (newGrid[k].x == data.x && newGrid[k].y == data.y) {
        newGrid[k].status == 'dead' ? newGrid[k].status = 'newborn' : newGrid[k].status = 'dead';
        this.setState({
          gridArray: newGrid
        });
        break;
      }
    }
  },
  cycleLife: function cycleLife() {
    var grid = this.state.gridArray,
        toBirth = [],
        toKill = [],
        toMature = [];
    for (var l = 0; l < grid.length; l++) {
      var livingNeighbours = 0;
      for (var m = 0; m < grid[l].neighbours.length; m++) {
        var arrIndex = (grid[l].neighbours[m].y - 1) * this.state.width + grid[l].neighbours[m].x - 1;
        if (grid[arrIndex].status != 'dead') livingNeighbours++;
      }
      if (grid[l].status == 'dead' && livingNeighbours == 3) toBirth.push(l);else if (grid[l].status != 'dead') {
        if (livingNeighbours < 2 || livingNeighbours > 3) toKill.push(l);else toMature.push(l);
      }
    }
    toBirth.map(function (cell) {
      grid[cell].status = 'newborn';
    });
    toKill.map(function (cell) {
      grid[cell].status = 'dead';
    });
    toMature.map(function (cell) {
      grid[cell].status = 'mature';
    });
    var count = this.state.count;
    this.setState({
      gridArray: grid,
      count: count + 1
    });
  },
  render: function render() {
    var cells = this.state.gridArray.map(function (cell) {
      return React.createElement(Cell, {
        x: cell.x,
        y: cell.y,
        status: cell.status,
        neighbours: cell.neighbours,
        gridWidth: this.state.width,
        onCellClick: this.handleCellClick
      });
    }, this);
    return React.createElement(
      'main',
      null,
      React.createElement(
        'h1',
        null,
        'Game of Life'
      ),
      React.createElement(
        'div',
        { className: 'ctrl ctrl-one' },
        React.createElement('input', {
          type: 'button',
          className: this.state.active ? 'active' : '',
          alt: 'play',
          value: this.state.active ? "pause" : "play",
          onClick: this.playPauseGame
        }),
        React.createElement('input', {
          type: 'button',
          value: 'clear',
          disabled: this.state.active,
          onClick: this.clearGame
        })
      ),
      React.createElement(
        'div',
        { className: 'explain' },
        React.createElement(
          'svg',
          { viewBox: '0 0 10 10' },
          React.createElement('circle', {
            cx: '5',
            cy: '5',
            r: '5',
            fill: '#b5b5b5'
          })
        ),
        React.createElement(
          'span',
          null,
          'dead'
        ),
        React.createElement(
          'svg',
          { viewBox: '0 0 10 10' },
          React.createElement('circle', {
            cx: '5',
            cy: '5',
            r: '5',
            fill: 'royalblue'
          })
        ),
        React.createElement(
          'span',
          null,
          'newborn'
        ),
        React.createElement(
          'svg',
          { viewBox: '0 0 10 10' },
          React.createElement('circle', {
            cx: '5',
            cy: '5',
            r: '5',
            fill: 'orangered'
          })
        ),
        React.createElement(
          'span',
          null,
          'mature'
        ),
        React.createElement(
          'p',
          {
            style: { textAlign: 'center' }
          },
          'life cycle: ' + this.state.count
        )
      ),
      React.createElement(
        'div',
        { className: 'grid' },
        cells
      ),
      React.createElement(
        'div',
        { className: 'ctrl ctrl-two' },
        React.createElement(
          'h2',
          null,
          'grid'
        ),
        React.createElement('input', {
          type: 'button',
          value: 'small',
          name: '50',
          onClick: this.resizeGrid
        }),
        React.createElement('input', {
          type: 'button',
          value: 'medium',
          name: '70',
          onClick: this.resizeGrid
        }),
        React.createElement('input', {
          type: 'button',
          value: 'large',
          name: '90',
          onClick: this.resizeGrid
        })
      ),
      React.createElement(
        'div',
        { className: 'ctrl ctrl-two' },
        React.createElement(
          'h2',
          null,
          'speed'
        ),
        React.createElement('input', {
          type: 'button',
          value: 'slow',
          name: '1000',
          disabled: this.state.active,
          onClick: this.setInterval
        }),
        React.createElement('input', {
          type: 'button',
          value: 'medium',
          name: '250',
          disabled: this.state.active,
          onClick: this.setInterval
        }),
        React.createElement('input', {
          type: 'button',
          value: 'fast',
          name: '100',
          disabled: this.state.active,
          onClick: this.setInterval
        })
      ),
      React.createElement(
        'a',
        {
          href: 'https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life',
          target: '_blank'
        },
        'what is this?'
      )
    );
  }
});

var Cell = React.createClass({
  displayName: 'Cell',

  handleCellClick: function handleCellClick(e) {
    e.preventDefault();
    this.props.onCellClick({
      x: this.props.x,
      y: this.props.y,
      neighbours: this.props.neighbours
    });
  },
  selectFill: function selectFill() {
    if (this.props.status == 'dead') return '#b5b5b5';else if (this.props.status == 'newborn') return 'royalblue';else return 'orangered';
  },
  render: function render() {
    if (this.props.x == this.props.gridWidth) {
      return React.createElement(
        'span',
        null,
        React.createElement(
          'svg',
          { viewBox: '0 0 10 10' },
          React.createElement('circle', {
            cx: '5',
            cy: '5',
            r: '5',
            fill: this.selectFill(),
            onClick: this.handleCellClick
          })
        ),
        React.createElement('br', null)
      );
    } else {
      return React.createElement(
        'svg',
        { viewBox: '0 0 10 10' },
        React.createElement('circle', {
          cx: '5',
          cy: '5',
          r: '5',
          fill: this.selectFill(),
          onClick: this.handleCellClick
        })
      );
    }
  }
});

var seedArray = [102, 103, 104, 353, 354, 355, 404, 405, 406, 161, 162, 163, 113, 62, 683, 684, 685, 686, 636, 586, 535, 532, 632, 141, 142, 191, 192, 243, 244, 293, 294, 956, 957, 808, 758, 757, 804, 854, 810, 861, 761, 762, 961, 962, 864, 914, 656, 657, 608, 558, 604, 554, 457, 456, 661, 662, 610, 560, 461, 462, 614, 564, 693, 694, 743, 794, 745];

ReactDOM.render(React.createElement(GameOfLife, { width: '50' }), document.getElementById('app'));

Comments