I am an experienced R programmer, but beginner with programming automata scripts (in fact I just learned about them recently). I've produced a script that calculates (based on some minimal rules from the wikipedia page on Conway's game of life) the grid-like position for any given starting position. I am fairly confident that it's working at least as far as the data, but I can't figure out the best way to kind of animate or make these plots change in the viewer- in fact I have no idea what the best way to visualize a sort of NxM grid in this way.
library(dplyr)
grid <- matrix(0,nrow=8,ncol=8) %>% as.data.frame()
positions <- c(1,2,3,4,5,6,7,8)
colnames(grid) <- positions
input_row <- 4
input_col <- 4
grid[input_row-1,input_col] <- 1
grid[input_row,input_col+1] <- 1
grid[input_row+1,input_col+1] <- 1
grid[input_row+1,input_col] <- 1
grid[input_row+1,input_col-1] <- 1
capture_index <- NULL
for(cycle in 1:5){
for(row in 1:nrow(grid)){
for(col in 1:ncol(grid)){
input_row <- row
input_col <- col
neighbor_1 <- grid[input_row-1,input_col-1]
neighbor_2 <- grid[input_row-1,input_col]
neighbor_3 <- grid[input_row-1,input_col + 1]
neighbor_4 <- grid[input_row,input_col-1]
neighbor_5 <- grid[input_row,input_col+1]
neighbor_6 <- grid[input_row+1,input_col-1]
neighbor_7 <- grid[input_row+1,input_col]
neighbor_8 <- grid[input_row+1,input_col + 1]
neighbor_sum <- sum(neighbor_1,neighbor_2,neighbor_3,
neighbor_4,neighbor_5,neighbor_6,
neighbor_7,neighbor_8)
capture_index <- rbind(capture_index,data.frame(row,col,
current_state = grid[row,col],
neighbor_sum))
}
}
capture_index[is.na(capture_index)] <- 0
process <- capture_index %>% mutate(is_alive = current_state == 1) %>%
mutate(living_survive = ifelse(is_alive == TRUE & neighbor_sum %in% c(2,3),
'STAY ALIVE','NOTHING')) %>%
mutate(dead_born = ifelse(is_alive == FALSE & neighbor_sum ==3,
'BE BORN','NOTHING'))
process$neighbor_sum[is.na(process$neighbor_sum)] <- 0
process$dead_born[is.na(process$dead_born)] <- 'NOTHING'
#Next Steps
process <- process %>% mutate(next_state =
ifelse(is_alive == FALSE & dead_born == 'BE BORN',
1,
ifelse(is_alive == TRUE & living_survive == 'STAY ALIVE',
1,0)))
for(i in 1:nrow(process)){
grid[process[i,'row'],process[i,'col']] <- process[i,'next_state']
}
}
For whatever # of cycles you choose, the final result will be a 'grid' object that reflects the new positioning based on rules. The current setting just iterates until they all reach some area in the bottom-right and collapse to a square- but of course this all changes with your initial set up and iteration strategy.
It would be nice making this algorithm somewhat visual.
Thanks in advance! This is my first time submitting a question or answer on stackoverflow- I hope it was okay and any feedback is appreciated!
An obvious choice would be to use gganimate to animate a geom_tile of your grid. The easiest way to do this is to store each iteration of grid
in a list.
For example, if you create an empty list called result_list
before your line for(cycle in 1:5)
, then make the final line in this loop result_list[[cycle]] <- grid
, you will store each iteration.
To get these into a format that can be used by gganimate, you will need to pivot each data frame then bind them together, like this:
df <- bind_rows(lapply(result_list, function(x) {
tidyr::pivot_longer(x, everything(), names_to = 'x') %>%
mutate(y = rep(8:1, each = 8))
}), .id = 'time')
Then the plotting code is fairly straighforward:
library(gganimate)
ggplot(df, aes(x, y, fill = factor(value))) +
geom_tile(color = 'gray80') +
scale_fill_manual(values = c('white', 'black')) +
coord_equal() +
theme_void() +
theme(legend.position = 'none') +
transition_states(as.numeric(df$time), transition_length = 0)