Skip to content

Instantly share code, notes, and snippets.

@i-am-tom
Created June 19, 2017 20:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save i-am-tom/e71b6624df574e06088f74fdb1317d9d to your computer and use it in GitHub Desktop.
Save i-am-tom/e71b6624df574e06088f74fdb1317d9d to your computer and use it in GitHub Desktop.
Code for Game of Life from the Comonad article.
const { tagged } = require('daggy')
const Pair = tagged('_1', '_2')
//+ data Store p s = Store (p -> s) p
const Store = tagged('lookup', 'pointer')
Array.prototype.equals = function (that) {
return this.length === that.length
&& this.every((x, i) => x.equals ? x.equals(that[i])
: x === that[i])
}
Function.prototype.map = function (f) {
return x => f(this(x))
}
Store.prototype.peek = function (p) {
return this.seek(p).extract()
}
Store.prototype.seek = function (p) {
return Store(this.lookup, p)
}
Store.prototype.map = function (f) {
return Store(this.lookup.map(f),
this.pointer)
}
Store.prototype.extend = function (f) {
const { lookup, pointer } = this
return Store(p => f(Store(lookup, p)),
pointer)
}
Store.prototype.extract = function () {
return this.lookup(this.pointer)
}
// GAME OF LIFE //
let start = [
[ true, true, false, false ],
[ true, false, true, false ],
[ true, false, false, true ],
[ true, false, true, false ]
]
const Game = Store(
({ _1: x, _2: y }) =>
y in start && x in start[y]
? start[y][x]
: false,
Pair(0, 0))
// What will the current cell be next time?
//+ isSurvivor :: Store (Pair Int Int) Bool
//+ -> Bool
const isSurvivor = store => {
const { _1: x, _2: y } = store.pointer
const neighbours =
[ Pair(x - 1, y - 1), Pair(x, y - 1), Pair(x + 1, y - 1)
, Pair(x - 1, y), Pair(x + 1, y)
, Pair(x - 1, y + 1), Pair(x, y + 1), Pair(x + 1, y + 1) ]
.map(x => store.peek(x))
.filter(x => x) // Ignore dead cells
.length
return neighbours === 3 // Fine either way
|| (store.extract() && neighbours === 2)
}
//- IMPURITIES
const loop = setInterval(() => {
// Get the next step.
const next = Game.extend(isSurvivor)
// Extract the whole result.
const result =
start.map((row, y) =>
row.map((column, x) =>
next.lookup(Pair(x, y))))
// Stop looping if we freeze.
if (start.equals(result))
clearInterval(loop)
// Pretty print the result.
console.log(
result.map(row =>
row.map(column =>
column ? "X" : " ")))
// FORGIVE ME, PADRE. In order to get this example working, I did
// cheat a LITTLE bit. At this point, the initial board is updated,
// so the result next time will be different. If you want to see a
// better idea: https://github.com/puffnfresh/game-of-comonads.js
start = result
console.log()
}, 100)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment