Skip to content

Instantly share code, notes, and snippets.

@richdouglasevans
Forked from i-am-tom/Comonad.js
Last active November 1, 2018 09:00
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save richdouglasevans/0f9a57e5a52b13e93c0c03630165ecd8 to your computer and use it in GitHub Desktop.
Save richdouglasevans/0f9a57e5a52b13e93c0c03630165ecd8 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("Pair", ["_1", "_2"]);
//+ data Store p s = Store (p -> s) p
const Store = tagged("Store", ["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).length; // Ignore dead cells
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