Created
August 1, 2016 14:51
-
-
Save blvrd/758d7d4f9b8630488fddd12190315de1 to your computer and use it in GitHub Desktop.
Game of Life
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var gameOfLife = { | |
width: 12, | |
height: 12, | |
stepInterval: 100, | |
playing: false, | |
intervalObject: null, | |
createAndShowBoard: function(state) { | |
// create <table> element | |
var goltable = document.createElement("tbody"); | |
// build Table HTML | |
var tablehtml = ''; | |
for (var h=0; h<this.height; h++) { | |
tablehtml += "<tr id='row+" + h + "'>"; | |
for (var w=0; w<this.width; w++) { | |
if (state && state[h][w] === 'O') { | |
tablehtml += "<td data-status='alive' class='alive' id='" + w + "-" + h + "'></td>"; | |
} else { | |
tablehtml += "<td data-status='dead' id='" + w + "-" + h + "'></td>"; | |
} | |
} | |
tablehtml += "</tr>"; | |
} | |
goltable.innerHTML = tablehtml; | |
// add table to the #board element | |
var board = document.getElementById('board'); | |
var oldgoltable = document.getElementsByTagName('tbody')[0] | |
if (oldgoltable) { | |
board.replaceChild(goltable, oldgoltable); | |
} else { | |
board.appendChild(goltable); | |
} | |
// once html elements are added to the page, attach events to them | |
this.setupBoardEvents(); | |
}, | |
forEachCell: function (iteratorFunc) { | |
/* | |
Write forEachCell here. You will have to visit | |
each cell on the board, call the "iteratorFunc" function, | |
and pass into func, the cell and the cell's x & y | |
coordinates. For example: iteratorFunc(cell, x, y) | |
*/ | |
var cells = [].slice.call(document.getElementsByTagName('td')) | |
cells.forEach(function(cell) { | |
iteratorFunc.call(gameOfLife, cell) | |
}) | |
}, | |
setupBoardEvents: function() { | |
// each board cell has an CSS id in the format of: "x-y" | |
// where x is the x-coordinate and y the y-coordinate | |
// use this fact to loop through all the ids and assign | |
// them "on-click" events that allow a user to click on | |
// cells to setup the initial state of the game | |
// before clicking "Step" or "Auto-Play" | |
// clicking on a cell should toggle the cell between "alive" & "dead" | |
// for ex: an "alive" cell be colored "blue", a dead cell could stay white | |
// EXAMPLE FOR ONE CELL | |
// Here is how we would catch a click event on just the 0-0 cell | |
// You need to add the click event on EVERY cell on the board | |
var onCellClick = function (e) { | |
// QUESTION TO ASK YOURSELF: What is "this" equal to here? | |
// how to set the style of the cell when it's clicked | |
if (e.target.dataset.status === 'dead') { | |
this.setCellAlive(e.target) | |
} else { | |
this.setCellDead(e.target) | |
} | |
}; | |
var tbody = document.getElementsByTagName('tbody')[0]; | |
tbody.onclick = onCellClick.bind(this); | |
var stepButton = document.getElementById('step_btn') | |
stepButton.onclick = this.step.bind(this) | |
var playButton = document.getElementById('play_btn') | |
playButton.onclick = this.enableAutoPlay.bind(this) | |
var clearButton = document.getElementById('clear_btn') | |
clearButton.onclick = this.clear.bind(this) | |
var randomButton = document.getElementById('reset_btn') | |
randomButton.onclick = this.resetRandom.bind(this) | |
var uploadButton = document.getElementById('uploader') | |
uploadButton.onchange = this.handleFileUpload.bind(this) | |
}, | |
setCellAlive: function(cell) { | |
cell.className = 'alive' | |
cell.dataset.status = 'alive' | |
cell.dataset.nextStatus = null | |
}, | |
setCellDead: function(cell) { | |
cell.className = 'dead' | |
cell.dataset.status = 'dead' | |
cell.dataset.nextStatus = null | |
}, | |
getCoordinates: function(cell) { | |
var coordinates = {} | |
var coordinateArrary = cell.id.split('-') | |
coordinates.x = parseInt(coordinateArrary[0]) | |
coordinates.y = parseInt(coordinateArrary[1]) | |
return coordinates | |
}, | |
setNextCellState: function(cell) { | |
var aliveNeighborsCount = this.getLiveNeighborsCount(cell) | |
var aliveWithLessThanTwoNeighbors = cell.dataset.status === 'alive' && aliveNeighborsCount < 2 | |
var aliveWithGreaterThanThreeNeighbors = aliveNeighborsCount > 3 && cell.dataset.status === 'alive' | |
var aliveWithTwoOrThreeNeighbors = cell.dataset.status === 'alive' && (aliveNeighborsCount === 2 || aliveNeighborsCount === 3) | |
var deadWithThreeNeighbors = cell.dataset.status === 'dead' && aliveNeighborsCount === 3 | |
if (aliveWithLessThanTwoNeighbors || aliveWithGreaterThanThreeNeighbors) { | |
cell.dataset.nextStatus = 'dead' | |
} else if (aliveWithTwoOrThreeNeighbors || deadWithThreeNeighbors) { | |
cell.dataset.nextStatus = 'alive' | |
} | |
}, | |
getLiveNeighborsCount(cell) { | |
var coordinates = this.getCoordinates(cell) | |
var neighbors = [] | |
neighbors.push(this.getCellValue(coordinates.x, coordinates.y-1)) | |
neighbors.push(this.getCellValue(coordinates.x+1, coordinates.y-1)) | |
neighbors.push(this.getCellValue(coordinates.x+1, coordinates.y)) | |
neighbors.push(this.getCellValue(coordinates.x+1, coordinates.y+1)) | |
neighbors.push(this.getCellValue(coordinates.x, coordinates.y+1)) | |
neighbors.push(this.getCellValue(coordinates.x-1, coordinates.y+1)) | |
neighbors.push(this.getCellValue(coordinates.x-1, coordinates.y)) | |
neighbors.push(this.getCellValue(coordinates.x-1, coordinates.y-1)) | |
return neighbors.filter(function(cell) { | |
return cell === 1 | |
}).length | |
}, | |
getCellValue: function(x, y) { | |
var cell = document.getElementById(x + '-' + y) | |
if (cell !== null && cell.dataset.status === 'alive') { | |
return 1 | |
} else { | |
return 0 | |
} | |
}, | |
updateCell: function(cell) { | |
if (cell.dataset.nextStatus === 'alive') { | |
this.setCellAlive(cell) | |
} else { | |
this.setCellDead(cell) | |
} | |
}, | |
step: function () { | |
// Here is where you want to loop through all the cells | |
// on the board and determine, based on it's neighbors, | |
// whether the cell should be dead or alive in the next | |
// evolution of the game. | |
// | |
// You need to: | |
// 1. Count alive neighbors for all cells | |
// 2. Set the next state of all cells based on their alive neighbors | |
this.forEachCell(this.setNextCellState) | |
this.forEachCell(this.updateCell) | |
}, | |
enableAutoPlay: function () { | |
// Start Auto-Play by running the 'step' function | |
// automatically repeatedly every fixed time interval | |
if (this.playing === false) { | |
this.playing = true | |
this.intervalObject = setInterval(this.step.bind(this), this.stepInterval) | |
} else { | |
this.playing = false | |
this.pause() | |
} | |
}, | |
pause: function() { | |
clearInterval(this.intervalObject) | |
}, | |
clear: function() { | |
this.pause() | |
this.forEachCell(this.setCellDead) | |
}, | |
resetRandom: function() { | |
this.pause() | |
this.forEachCell(function(cell) { | |
if (Math.random() > 0.5) { | |
this.setCellAlive(cell) | |
} else { | |
this.setCellDead(cell) | |
} | |
}) | |
}, | |
handleFileUpload: function(e) { | |
var file = e.target.files[0] | |
var reader = new FileReader() | |
reader.onload = function(event) { | |
console.log(event.target.result) | |
var rows = event.target.result.split('\n').splice(2) | |
this.width = rows[0].length | |
this.height = rows.length | |
this.createAndShowBoard(rows) | |
}.bind(this) | |
reader.readAsText(file) | |
} | |
}; | |
gameOfLife.createAndShowBoard(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment