Basic usage

library(cellularautomata)

Create the plot of a cellular automaton

You can generate a cellular automaton using the ca function, specifying the Wolfram rule. For example:

ca(18) |> plot()

ca(30) |> plot()

ca(45) |> plot()

ca(195) |> plot()

The number of rows to be generated are specified with the steps parameter in the ca() function.

The length of the cellular automaton can be specified with the ncols parameter in the ca() function. See below how to specify arbitrary initial states.

Animations

You can get an animation of a cellular automaton using plot(animate = TRUE):

ca(30, ncols = 20, steps = 30) |> plot(animate = TRUE)

Get the rule definition

You can get the visual representation of the definition of a rule with wolfram_rule_def():

wolfram_rule_def(18)

wolfram_rule_def(30)

wolfram_rule_def(45)

wolfram_rule_def(195)

The first line in each box is a possible input, and the second line is the output of the function. For example, Rule 30 is defined as:

111 -> 0
110 -> 0
101 -> 0
100 -> 1
011 -> 1
010 -> 1
001 -> 1
000 -> 0

The function wolfram_rule() gives the output of the rule as a numeric vector:

wolfram_rule(30)
#> [1] 0 0 0 1 1 1 1 0

Multiple plots at once

To generate multiple plots in one go, you can wrap the ca(rule) |> plot() inside a purrr::map() call and then pipe the resulting list into patchwork::wrap_plots().

For example, you can generate a preview of all the 256 rules this way:

all_rules <- purrr::map(0:255, \(rule){
    ca(rule,
       ncols = 30,
       steps = 30) |> 
      plot()
  }) |> 
  patchwork::wrap_plots(nrow = 32)

ggplot2::ggsave("all-cellular-automata.png", 
       plot = all_rules,
       width = 12, 
       height = 48)

This will create a long png file with all the rules.

Specify the initial state

You can define how long the cellular automaton line is using the ncols parameter in the ca() function. Alternatively, you can define an arbitrary initial state, which will determine how long the line is.

By default, the initial state has a single filled cell in the middle of an empty row. You can specify different initial states using the initialstate parameter in the ca() function. The initialstate needs to be a vector of 0s and 1s. When you specify the initialstate, the ncols is calculated as length(initialstate).

For example, here we are running Rule 30 for 10 steps from several random initial states:

# sample rule 30 from different random starting points
purrr::map(1:25, \(i){
    ca(30, 
       initialstate = sample(c(0, 1), size = 10, replace = TRUE), 
       steps = 10) |> 
      plot(title = NULL)
  }) |> 
  patchwork::wrap_plots()

The function sample(c(0, 1), size = 10, replace = TRUE) generates a random vector of 0s and 1s of length 10.

Wrap the line, or don’t

By default the line is wrapped around, meaning it is actually a circle, with the end connected to the beginning.

You can turn off wrapping with wrap = FALSE in the ca() function, which will keep the first and the last cells always empty.

Given the circular default, you can also plot the cellular automaton in polar coordinates, adding the circle = TRUE option to plot(). To make the time flow from the center to the outer edges, set time_flow = "up" as well.

ca(193, steps = 50) |> plot(time_flow = "up", circle = TRUE)

This also works for animations:

ca(193, ncols = 25, steps = 100) |> plot(circle = TRUE, animate = TRUE)