Skip to content

Instantly share code, notes, and snippets.

@rfprod
Last active April 22, 2017 15:50
Show Gist options
  • Save rfprod/34c96dadd916f063495c to your computer and use it in GitHub Desktop.
Save rfprod/34c96dadd916f063495c to your computer and use it in GitHub Desktop.
Game of Life
<div class="container-fluid nopadding">
<nav class="navbar navbar-inverse navbar-fixed-top topnav" role="navigation">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#toggle-nav" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand font-effect-neon" target=_blank href="http://codepen.io/rfprod"><span class="glyphicon glyphicon-wrench"></span> RFProd</a>
</div>
<div class="collapse navbar-collapse" id="toggle-nav">
<div class="container-fluid">
<ul class="nav navbar-nav navbar-right font-effect-emboss">
<li class="nav-tabs"><a href="#gameoflife"><span class="glyphicon glyphicon-th"></span> GAME OF LIFE</a></li>
<li class="nav-tabs"><a href="https://gist.github.com/rfprod/34c96dadd916f063495c" target=_blank><span class="glyphicon glyphicon-download-alt" ></span> GIST</a></li>
</ul>
</div>
</div>
</nav>
<a name="gameoflife"></a>
<div class="home">
<div class="container-fluid">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<h2><span class="glyphicon glyphicon-th"></span> Game of Life</h2>
<div id="output">
Output
</div>
<span class="credits">info <a href="https://en.wikipedia.org/wiki/Conway's_Game_of_Life" target=_blank>what is game of life</a><br/>licence <a href="http://www.gnu.org/licenses/gpl-3.0.en.html" target=_blank>GPL 3.0</a></span>
</div>
</div>
</div>
</div>
"use strict";
$(document).on('ready',() => {
(function refreshAll(){
const ControlsAndGridContainer = React.createClass({
render: () => {
return (
<span>
<div className="btn-group btn-group-justified">
<a href="#" id="start" className="btn btn-success">Start</a>
<a href="#" id="pause" className="btn btn-warning">Pause</a>
<a href="#" id="reset" className="btn btn-danger">Reset</a>
</div>
<div id="random-patterns-selector">
<h4>Random patterns</h4>
<div className="btn-group btn-group-justified">
<a href="#" id="gliders" className="pattern-selector btn btn-info active">Gliders</a>
<a href="#" id="LWSS1" className="pattern-selector btn btn-info">LWSS1</a>
<a href="#" id="LWSS2" className="pattern-selector btn btn-info">LWSS2</a>
<a href="#" id="LWSS3" className="pattern-selector btn btn-info">LWSS3</a>
</div>
</div>
<div className="well well-sm">Generations: <span className="gen-counter">0</span>
<p id="user-tip">Cells can be added manually while the game plays.</p></div>
<table className="table table-bordered" id="grid"></table>
</span>
);
}
});
ReactDOM.render(<ControlsAndGridContainer />,document.getElementById('output'));
const cellsInRow = 50;
const rowsCount = cellsInRow/2;
//console.log('cells in a row: '+cellsInRow+' | rows count: '+rowsCount);
let markup = [], rowMarkup = [];
const Grid = React.createClass({
render: function() {
for(let j=0; j<cellsInRow; j++){
rowMarkup.push(<td className="grid-unit" onClick={this.handleClick} id={j}></td>);
}
for (let i=0, cirHalved=cellsInRow/2; i<cirHalved; i++){
markup.push(<tr className="row" id={i}>{rowMarkup}</tr>);
}
return (
<tbody>{markup}</tbody>
);
}
});
ReactDOM.render(<Grid />,document.getElementById('grid'));
const gridUnits = document.getElementsByClassName('grid-unit');
const patternSelectors = document.getElementsByClassName('pattern-selector');
let deadCells = [], liveCells = [];
// init live cells
let randomPatternName = "gliders";
let gridUnitClass = undefined, addr = undefined;
for (let i=0, gul=gridUnits.length; i<gul; i++){
gridUnits[i].addEventListener('click', function(){
//console.log('clicked: '+this.className+" | row: "+this.parentNode.id+" col: "+this.id);
gridUnitClass = this.className;
if (gridUnitClass === 'grid-unit') {
this.className = 'grid-unit immature';
liveCells.push(this.parentNode.id+"-"+this.id);
//console.log(JSON.stringify(liveCells));
}
if (gridUnitClass === 'grid-unit immature'){
this.className = 'grid-unit';
addr = this.parentNode.id+"-"+this.id;
liveCells.splice(liveCells.indexOf(addr),1);
//console.log(JSON.stringify(liveCells));
}
if (liveCells.length === 0){
document.getElementById("random-patterns-selector").className = "visible";
}else{
document.getElementById("random-patterns-selector").className = "hidden";
}
});
}
let patternSelectorID = undefined;
for (let i=0, psl1=patternSelectors.length; i<psl1; i++){
patternSelectors[i].addEventListener('click', function(){
patternSelectorID = this.id;
this.className = 'pattern-selector btn btn-info active';
for (let j=0, psl2=patternSelectors.length; j<psl2; j++){
if (patternSelectors[j].id != patternSelectorID) patternSelectors[j].className = "pattern-selector btn btn-info";
}
//console.log('selected pattern name: '+patternSelectorID);
randomPatternName = patternSelectorID;
});
}
let cellsAddresses = [], neighboursAddresses = [];
let survivedCells = [], revivedCells = [];
function changeCellsStates(){
// init dead and revived cells
deadCells.length = 0;
revivedCells.length = 0;
for (let cai=0, cal=cellsAddresses.length; cai<cal; cai++){
deadCells.push(cellsAddresses[cai]);
}
let liveCellIndex = undefined;
for (let lci=0, lcl=liveCells.length; lci<lcl; lci++){
liveCellIndex = deadCells.indexOf(liveCells[lci]);
if (liveCellIndex != -1) {
if (liveCellIndex == deadCells.length - 1) deadCells.pop();
else if (liveCellIndex == 0) deadCells.shift();
else deadCells.splice(liveCellIndex,1);
}
}
// raise dead - find index of cell address to revive if it has 3 alive neighbours
let raisingCellAddr = undefined, counter = undefined;
for (let nai = 0, nal = neighboursAddresses.length; nai<nal; nai++){
counter = 0;
for (let naEli=0, naEll=neighboursAddresses[nai].length;naEli<naEll;naEli++){
if (liveCells.indexOf(neighboursAddresses[nai][naEli]) != -1) counter++;
}
if (counter == 3){
raisingCellAddr = cellsAddresses[nai].split("-");
//console.log('neighboursAddresses: '+JSON.stringify(neighboursAddresses[wr]));
//console.log('neighbour address: '+neighboursAddresses[wr][wrel]+' cellsAddresses index: '+wr+' live neighbours counter: '+counter);
document.getElementsByClassName("row")[raisingCellAddr[0]].childNodes.item(raisingCellAddr[1]).className = "grid-unit immature";
revivedCells.push(cellsAddresses[nai]);
}
}
// init survided cells
survivedCells.length = 0;
// kill live cells
let element = undefined,
cellAddr = undefined,
indexOfalive = undefined,
aliveNeighboursCounter = undefined,
currentNeighbours = undefined;
for (let index=0, lcln=liveCells.length; index<lcln; index++){
element = liveCells[index];
//console.log('element: '+element);
cellAddr = element.split("-");
indexOfalive = cellsAddresses.indexOf(element);
//console.log('indexOfalive: '+indexOfalive);
if (indexOfalive != -1) {
aliveNeighboursCounter = 0;
currentNeighbours = neighboursAddresses[indexOfalive];
//console.log('currentNeighbours: '+JSON.stringify(currentNeighbours));
for (let h=0, cnl=currentNeighbours.length; h<cnl; h++){
// indexOfAliveNeighbour
if (liveCells.indexOf(currentNeighbours[h]) != -1){
aliveNeighboursCounter++;
}
}
if (aliveNeighboursCounter < 2){
//console.log('underpopulation dying cell address: '+cellAddr);
document.getElementsByClassName("row")[cellAddr[0]].childNodes.item(cellAddr[1]).className = "grid-unit";
}else
if (aliveNeighboursCounter == 2 || aliveNeighboursCounter == 3){
//console.log('cell lives to next generation: '+cellAddr);
survivedCells.push(element);
}else
if (aliveNeighboursCounter > 3){
//console.log('overpopulation dying cell address: '+cellAddr);
document.getElementsByClassName("row")[cellAddr[0]].childNodes.item(cellAddr[1]).className = "grid-unit";
}
//console.log('survivedCells: '+JSON.stringify(survivedCells));
//console.log('aliveNeighboursCounter: '+aliveNeighboursCounter);
}
}
// update live cells
liveCells.length = 0;
for (let sci=0, scl=survivedCells.length; sci<scl; sci++){
liveCells.push(survivedCells[sci]);
}
for (let rcli=0, rclil=revivedCells.length; rcli<rclil; rcli++){
liveCells.push(revivedCells[rcli]);
}
//console.log('liveCells: '+JSON.stringify(liveCells));
}
function getGridAddresses(){
if (cellsAddresses.length === 0 || neighboursAddresses.length === 0){
let cell = undefined,
neighbourRows = undefined,
neighbourColumns = undefined,
tmpNeighboursAddresses = undefined,
rowElmnt = undefined,
colElmnt = undefined,
neighbour = undefined;
for (let r=0; r<rowsCount; r++){ // rows
for (let c=0; c<cellsInRow; c++){ // columns
cell = document.getElementsByTagName('tr')[r].getElementsByTagName('td')[c];
neighbourRows = [], neighbourColumns = [];
if (r === 0) neighbourRows = [rowsCount-1,r,r+1];
else if (r === rowsCount-1) neighbourRows = [r-1,r,0];
else neighbourRows = [r-1,r,r+1];
if (c === 0) neighbourColumns = [cellsInRow-1,c,c+1];
else if (c === cellsInRow-1) neighbourColumns = [c-1,c,0];
else neighbourColumns = [c-1,c,c+1];
tmpNeighboursAddresses = [];
for (let y=0, yl=neighbourRows.length; y<yl; y++){
rowElmnt = neighbourRows[y];
for (let z=0, zl=neighbourColumns.length; z<zl; z++){
colElmnt = neighbourColumns[z];
neighbour = document.getElementsByTagName('tr')[rowElmnt].getElementsByTagName('td')[colElmnt];
tmpNeighboursAddresses.push(neighbour.parentNode.id+"-"+neighbour.id);
}
}
cellsAddresses.push(tmpNeighboursAddresses[4]);
tmpNeighboursAddresses.splice(4,1); // exclude cell itself, consider only neighbours
neighboursAddresses.push(tmpNeighboursAddresses);
}
}
}
}
getGridAddresses();
function autoInitLiveCells(arrayPointer){
const fiveGliders = ['2-0','2-1','2-2','1-2','0-1','2-10','2-11','2-12','1-12','0-11','2-20','2-21','2-22','1-22','0-21','2-30','2-31','2-32','1-32','0-31','2-40','2-41','2-42','1-42','0-41'];
const threeLWSS1 = ['0-0','0-3','1-4','2-0','2-4','3-1','3-2','3-3','3-4','0-10','0-13','1-14','2-10','2-14','3-11','3-12','3-13','3-14','0-20','0-23','1-24','2-20','2-24','3-21','3-22','3-23','3-24'];
const threeLWSS2 = ['0-0','0-3','1-4','2-0','2-4','3-1','3-2','3-3','3-4','15-0','15-3','16-4','17-0','17-4','18-1','18-2','18-3','18-4'];
const threeLWSS3 = ['0-0','0-3','1-4','2-0','2-4','3-1','3-2','3-3','3-4','10-0','10-3','11-4','12-0','12-4','13-1','13-2','13-3','13-4','20-0','20-3','21-4','22-0','22-4','23-1','23-2','23-3','23-4'];
const figuresObject = {'gliders':fiveGliders,'LWSS1':threeLWSS1,'LWSS2':threeLWSS2,'LWSS3':threeLWSS3};
let figureCellAddr = undefined;
for (let ic=0, icl=figuresObject[arrayPointer].length; ic<icl; ic++){
figureCellAddr = figuresObject[arrayPointer][ic].split("-");
liveCells.push(figuresObject[arrayPointer][ic]);
document.getElementsByClassName("row")[figureCellAddr[0]].childNodes.item(figureCellAddr[1]).className = "grid-unit immature";
}
}
let turn = false, generation = 0, generationsCounter = $('.gen-counter');
function startGame(){
if (turn === false){
if (generation === 0) console.log('game started');
else console.log('game continued');
document.getElementById("random-patterns-selector").className = "hidden";
let turnTimeout = 250;
turn = setInterval(function(){
generation++;
if (generation >= 150 && generation < 250) turnTimeout = 275;
if (generation >= 250 && generation < 350) turnTimeout = 300;
if (generation >= 350 && generation < 450) turnTimeout = 325;
if (generation >= 450 && generation < 550) turnTimeout = 350;
if (generation >= 550 && generation < 650) turnTimeout = 375;
if (generation >= 650 && generation < 750) turnTimeout = 400;
if (generation >= 750 && generation < 850) turnTimeout = 425;
if (generation >= 850 && generation < 950) turnTimeout = 450;
if (generation >= 950 && generation < 1050) turnTimeout = 475;
if (generation >= 1050) turnTimeout = 500;
generationsCounter.html(generation);
if (liveCells.length === 0) {
if (generation > 1) {
alert("GAME OVER: EVERYONE'S DEAD");
console.log('game reset');
clearInterval(turn);
turn = false;
generation = 0;
liveCells.length = 0;
deadCells.length = 0;
revivedCells.length = 0;
generationsCounter.html(generation);
document.getElementById("random-patterns-selector").className = "visible";
}else autoInitLiveCells(randomPatternName);
}
changeCellsStates();
},turnTimeout);
}else console.log('gameplay is already in progress');
}
function pauseGame(){
console.log('game paused');
clearInterval(turn);
turn = false;
}
function resetGame(){
console.log('game reset');
clearInterval(turn);
turn = false;
generation = 0;
liveCells.length = 0;
deadCells.length = 0;
revivedCells.length = 0;
generationsCounter.html(generation);
document.getElementById("random-patterns-selector").className = "visible";
for (let i=0, guln=gridUnits.length; i<guln; i++){
gridUnits[i].className = 'grid-unit';
}
}
$('#start').on('click', startGame);
$('#pause').on('click', pauseGame);
$('#reset').on('click', resetGame);
})();
});
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/react/0.14.7/react.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/react/0.14.7/react-dom.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
$black: #000000
$white: #ffffff
$lightred: #ffcccc
$red: #ff0000
body
color: $black
font-family: 'Play', sans-serif
font-size: 2.2em
overflow-x:hidden
.nopadding
padding: 0
.navbar-brand
font-size: 1em
.home
min-height: 100vh
padding-top: 8vh
height: auto !important
h2
text-align: center
font-weight: bold
#output
text-align: center
width: 100%
height: auto !important
#user-tip
font-size: 0.75em
.hidden
display: none
#grid
background-color: $black
.row
.grid-unit
width: 5px
height: 5px
padding: 0px
.immature
background-color: $lightred
.mature
background-color: $red
.grid-unit:hover
background-color: $white
a
text-decoration: none
.credits
display: block
text-align: center
font-size: 0.75em
a:hover
text-decoration: none
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" />
<link href="//cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.3/animate.min.css" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css?family=Play&effect=neon" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment