-
-
Save latentflip/3970282 to your computer and use it in GitHub Desktop.
Conways Game of Life in CoffeeScript
This file contains 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
# Utility methods | |
flatten_nested_array = (array) -> | |
[].concat array... | |
includes = (item, coll) -> | |
item = key_to_array(item) | |
for potential_match in coll | |
return true if item[0] == potential_match[0] && item[1] == potential_match[1] | |
false | |
key_to_array = (string) -> | |
return string if typeof string != 'string' | |
splitted = string.split(',') | |
[parseInt(splitted[0]), parseInt(splitted[1])] | |
# Main | |
# world is a set of live cells | |
# map all the neighbours of live cells in the world | |
# reduce to the frequencies of the neighbours occuring i.e. [1, 1] occurs 4 times | |
# reduce with conway rules: (2 & 3 and alive survives) or (3 and dead becomes alive) | |
neighbours_of = (x, y) -> | |
[[x-1, y+1], [x, y+1], [x+1, y+1], | |
[x-1, y ], [x+1, y ], | |
[x-1, y-1], [x, y-1], [x+1, y-1]] | |
frequencies = (all_neighbouring_cells) -> | |
frequencies_found = {} | |
for candidate_cell in all_neighbouring_cells | |
frequencies_found[candidate_cell] ||= 0 | |
frequencies_found[candidate_cell]++ | |
frequencies_found | |
neighbour_frequencies = (world) -> | |
neighbours = (neighbours_of(cell[0], cell[1]) for cell in world) | |
neighbours = flatten_nested_array(neighbours) | |
frequencies(neighbours) | |
survives = (num_of_neighbours, is_alive) -> | |
return true if is_alive and (num_of_neighbours == 2 or num_of_neighbours == 3) | |
return true if !is_alive and num_of_neighbours == 3 | |
false | |
evolve = (world) -> | |
nf = neighbour_frequencies(world) | |
survivors = key_to_array(cell) for cell, count of nf when survives(count, includes(cell, world)) | |
game_loop = (world, times_to_evolve, listener) -> | |
evolved = 0 | |
interval = null | |
iteration = -> | |
listener(world) | |
world = evolve(world) | |
evolved++ | |
clearInterval interval if times_to_evolve && evolved>times_to_evolve | |
interval = setInterval iteration, 400 | |
class Grid | |
constructor: (x,y) -> | |
@svg = d3.select('body').append('svg') | |
.attr('width', 5*x) | |
.attr('height', 5*y) | |
render: (data) => | |
rects = @svg.selectAll('rect') | |
.data(data, (d) -> "#{d[0]},#{d[1]}") | |
rects.enter().append('rect') | |
.attr('width', 0) | |
.attr('height', 0) | |
.attr('x', (d)->2.5+d[0]*5) | |
.attr('y', (d)->2.5+d[1]*5) | |
.transition().duration(400) | |
.attr('width', 5) | |
.attr('height', 5) | |
.attr('x', (d)->d[0]*5) | |
.attr('y', (d)->d[1]*5) | |
rects.exit().remove() | |
appendScript = (src, cb) -> | |
script = document.createElement('script') | |
script.type = 'text/javascript' | |
script.async = true | |
script.onload = cb | |
script.src = src | |
document.getElementsByTagName('head')[0].appendChild(script) | |
appendScript 'http://code.jquery.com/jquery-1.8.2.min.js', -> | |
appendScript 'http://cdnjs.cloudflare.com/ajax/libs/d3/2.10.0/d3.v2.min.js', -> | |
$ -> | |
world = [[0, 1], [1, 1], [2, 1], [2,2], [3,3], [3,2]] | |
g = new Grid(40,40) | |
game_loop(world, 5, g.render) | |
# prints | |
# ["0,1", "1,1", "2,1"] | |
# ["1,2", "1,1", "1,0"] | |
# ["0,1", "1,1", "2,1"] | |
# ["1,2", "1,1", "1,0"] | |
# ["0,1", "1,1", "2,1"] |
This file contains 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
// Generated by CoffeeScript 1.3.3 | |
(function() { | |
var Grid, appendScript, change_listener, evolve, flatten_nested_array, frequencies, game_loop, includes, key_to_array, neighbour_frequencies, neighbours_of, survives, | |
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; | |
flatten_nested_array = function(array) { | |
var _ref; | |
return (_ref = []).concat.apply(_ref, array); | |
}; | |
includes = function(item, coll) { | |
var potential_match, _i, _len; | |
item = key_to_array(item); | |
for (_i = 0, _len = coll.length; _i < _len; _i++) { | |
potential_match = coll[_i]; | |
if (item[0] === potential_match[0] && item[1] === potential_match[1]) { | |
return true; | |
} | |
} | |
return false; | |
}; | |
key_to_array = function(string) { | |
var splitted; | |
if (typeof string !== 'string') { | |
return string; | |
} | |
splitted = string.split(','); | |
return [parseInt(splitted[0]), parseInt(splitted[1])]; | |
}; | |
neighbours_of = function(x, y) { | |
return [[x - 1, y + 1], [x, y + 1], [x + 1, y + 1], [x - 1, y], [x + 1, y], [x - 1, y - 1], [x, y - 1], [x + 1, y - 1]]; | |
}; | |
frequencies = function(all_neighbouring_cells) { | |
var candidate_cell, frequencies_found, _i, _len; | |
frequencies_found = {}; | |
for (_i = 0, _len = all_neighbouring_cells.length; _i < _len; _i++) { | |
candidate_cell = all_neighbouring_cells[_i]; | |
frequencies_found[candidate_cell] || (frequencies_found[candidate_cell] = 0); | |
frequencies_found[candidate_cell]++; | |
} | |
return frequencies_found; | |
}; | |
neighbour_frequencies = function(world) { | |
var cell, neighbours; | |
neighbours = (function() { | |
var _i, _len, _results; | |
_results = []; | |
for (_i = 0, _len = world.length; _i < _len; _i++) { | |
cell = world[_i]; | |
_results.push(neighbours_of(cell[0], cell[1])); | |
} | |
return _results; | |
})(); | |
neighbours = flatten_nested_array(neighbours); | |
return frequencies(neighbours); | |
}; | |
survives = function(num_of_neighbours, is_alive) { | |
if (is_alive && (num_of_neighbours === 2 || num_of_neighbours === 3)) { | |
return true; | |
} | |
if (!is_alive && num_of_neighbours === 3) { | |
return true; | |
} | |
return false; | |
}; | |
evolve = function(world) { | |
var cell, count, nf, survivors, _results; | |
nf = neighbour_frequencies(world); | |
_results = []; | |
for (cell in nf) { | |
count = nf[cell]; | |
if (survives(count, includes(cell, world))) { | |
_results.push(survivors = key_to_array(cell)); | |
} | |
} | |
return _results; | |
}; | |
game_loop = function(world, times_to_evolve, listener) { | |
var evolved, interval, iteration, _i, _results; | |
evolved = 0; | |
interval = null; | |
iteration = function() { | |
listener(world); | |
world = evolve(world); | |
evolved++; | |
if (times_to_evolve && evolved > times_to_evolve) { | |
return clearInterval(interval); | |
} | |
}; | |
interval = setInterval(iteration, 400); | |
_results = []; | |
for (_i = 1; 1 <= times_to_evolve ? _i <= times_to_evolve : _i >= times_to_evolve; 1 <= times_to_evolve ? _i++ : _i--) { | |
listener(world); | |
_results.push(world = evolve(world)); | |
} | |
return _results; | |
}; | |
change_listener = function(new_world) { | |
var cell; | |
return console.log((function() { | |
var _i, _len, _results; | |
_results = []; | |
for (_i = 0, _len = new_world.length; _i < _len; _i++) { | |
cell = new_world[_i]; | |
_results.push(cell.toString()); | |
} | |
return _results; | |
})()); | |
}; | |
Grid = (function() { | |
function Grid(x, y) { | |
this.render = __bind(this.render, this); | |
this.svg = d3.select('body').append('svg').attr('width', 5 * x).attr('height', 5 * y); | |
} | |
Grid.prototype.render = function(data) { | |
var rects; | |
rects = this.svg.selectAll('rect').data(data, function(d) { | |
return "" + d[0] + "," + d[1]; | |
}); | |
rects.enter().append('rect').attr('width', 0).attr('height', 0).attr('x', function(d) { | |
return 2.5 + d[0] * 5; | |
}).attr('y', function(d) { | |
return 2.5 + d[1] * 5; | |
}).transition().duration(400).attr('width', 5).attr('height', 5).attr('x', function(d) { | |
return d[0] * 5; | |
}).attr('y', function(d) { | |
return d[1] * 5; | |
}); | |
return rects.exit().remove(); | |
}; | |
return Grid; | |
})(); | |
appendScript = function(src, cb) { | |
var script; | |
script = document.createElement('script'); | |
script.type = 'text/javascript'; | |
script.async = true; | |
script.onload = cb; | |
script.src = src; | |
return document.getElementsByTagName('head')[0].appendChild(script); | |
}; | |
appendScript('http://code.jquery.com/jquery-1.8.2.min.js', function() { | |
return appendScript('http://cdnjs.cloudflare.com/ajax/libs/d3/2.10.0/d3.v2.min.js', function() { | |
return $(function() { | |
var g, world; | |
world = [[0, 1], [1, 1], [2, 1], [2, 2], [3, 3], [3, 2]]; | |
g = new Grid(40, 40); | |
return game_loop(world, 5, g.render); | |
}); | |
}); | |
}); | |
}).call(this); |
This file contains 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
<script src='https://raw.github.com/gist/3970282/23e9325966140a6923e3e0e409079996b342b3ee/gol.js'></script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment