Skip to content

Instantly share code, notes, and snippets.

@johntyree
Created December 11, 2013 23:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save johntyree/7920541 to your computer and use it in GitHub Desktop.
Save johntyree/7920541 to your computer and use it in GitHub Desktop.
// GistID: 7920541
//
//
// In this exercise you should get familiar with closures and
// implement an elementary cellular automaton (CA)
// [http://en.wikipedia.org/wiki/Elementary_cellular_automaton]. Read
// the article before proceeding. Then study closures from
// https://developer.mozilla.org/en/JavaScript/Guide/Closures and make
// sure you understand "Emulating private methods with closures" part
// - the following code will apply this pattern.
//
// Now when you understand what cellular automata and closures are,
// you can take a look at the code below. There are three public methods and a
// method you should implement. Init function of the closure takes
// two arguments: state is an array of integers presenting the initial state of
// the machine, rule is rulenumber used to define the behavior of the
// automaton (see
// http://en.wikipedia.org/wiki/Elementary_cellular_automaton#The_numbering_system).
// In this exercise, the state array of CA is not infinite
// long. Instead, it is a 'cycle' of length state.length. This means
// that state[0] and state[state.length -1] are neigbours of each
// others.
//
// nextState function, given in the template, calculates the next
// generation of the automaton. nextState calls newBit function that
// you should implement.
//
// newBit is the function you should implement. It gets an index as an
// argument and returns if the bit in that index should be turned on
// or off in the next offspring of the CA. This can be calculated
// based on the rule-number and the current state. See next to
// understand how nextBit is used.
//
// Think how you can test your program. NG will test with some unit
// tests and therefore assumes that you don't change the function
// signatures. You can integrate your CA to a custom Html to learn how
// to do this and to test your program locally. Think what kind of
// page you would like to have - how to visualize the behavior of the
// CA and how to select the initial state. You can also use FireBug
// for testing. You are asked to submit a html document that we hope
// you have used to test your program. Testruns can also be found from
// here: http://www.wolframalpha.com/input/?i=rule+30 You can change
// the rule number in the url to get the behavior of different rules.
function p(s) {
console.log(s);
}
function dbg(s) {
// p(s);
}
function makeCA() {
var state = [], rule = 0;
function index_to_neighborhood(index) {
var neighborhood = "";
dbg("For index: " + index);
for (var i = -1; i < 2; i++) {
// Compute index, wrapping left and right
idx = (index + i + state.length) % state.length;
dbg("idx is " + String(idx));
// neighborhood 0, 1, 2 = left, center, right
neighborhood += state[idx];
}
dbg("neighborhood is: " + neighborhood);
return neighborhood;
}
function newBit(index) {
// Use the fact that the rule is literally named after the correspondence
// between states and bits in the next gen. The rule number _is_ a lookup
// table.
// Interpret the neighborhood as a binary int and use it to select the
// bit in the index corresponding to that neighborhood.
// Ex. Val: 8 7 6 5 ...
// Ex. Hoods: 111 110 101 100 ...
// Ex. New State: 0 1 0 0 ...
neighborhood = index_to_neighborhood(index);
neighborhood = parseInt(neighborhood, 2);
bit = (rule >> neighborhood) & 1;
return bit;
}
return {
init: function (state_, rule_) {
state = state_;
rule = rule_;
},
nextState: function () {
var newState = [];
for (var i = 0; i < state.length; i++) {
newState[i] = newBit(i);
}
state = newState;
},
getState: function () {
return state;
}
};
}
function printstate(state) {
p(state.join());
}
function test() {
function f(neighborhood) {
return (110 >> neighborhood) & 1;
}
for (var i = 7; i >= 0; i--) {
p(f(i));
}
}
function run () {
rule = 110;
cells = 100;
rows = 100;
state = [];
for (var i = 0; i < cells; i++) {
state[i] = 0;
}
state[Math.floor(cells / 2)] = 1;
ca = makeCA();
ca.init(state, rule);
printstate(ca.getState());
for (var i = 0; i < rows; i++) {
ca.nextState();
printstate(ca.getState());
}
}
run();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment