Let's explore cellular automata in a Clerk Notebook.
We start by creating custom viewers for numbers, lists, and vectors.
These viewers are maps that contain a :pred
(predicate) function that Clerk will use to decide which items should be viewed with the :render-fn
that follows. Clerk always uses the first viewer whose predicate matches, so it's possible to override the built-in viewers with whatever we want.
In this case, we want 1
s and 0
s to show up as filled and empty boxes, lists to stack their contents vertically, and vectors to line up their contents horizontally. We achieve this with the html
viewer, which allows us to emit arbitrary hiccup to represent a value.
Now let's test each one to make sure they look the way we want:
Looks good! 😊
Rule 30 is implemented as a set of rules for translating one state to another, which can be represented as a map if transitions in Clojure. This definition maps any vector of three cells to a new value for the middle cell. Later, we'll scan over our state space, applying these rules to every position on the board. (Notice how the built-in map viewer works unchanged with our newly defined number and vector viewers.)
Our first generation is a row with 33 elements. The element at the center is a black square, all other squares are white.
Finally, we can iterate
over first-generation
's state to evolve the state of the whole board over time. Try changing the value passed to take
to render more states! Add a drop
after the take
to sample other points in time! Most of all, have fun.