# conway's game of life # # set up a matrix of cells, mostly 0s with a few 1s nrows <- 10 ncols <- 10 alive <- matrix(0, nrows, ncols) alive[3,3:5] <- 1 # set up a blank plot # make it big enough to take what we'll plot par(mar=c(2,2,0,0)) plot(0,0, type="n", xlab="", ylab="", axes=F, xlim=c(0.5,nrows+0.5), ylim=c(0.5,ncols+0.5), asp=1) axis(side=1, at=1:10) axis(side=2, at=1:10) for(i in 1:nrows){ for(j in 1:ncols){ rect(j-0.5,i-0.5,j+0.5,i+0.5, col=alive[i,j] + 1, border="cyan") }} # do the neighbour counting neebs <- matrix(NA, nrows, ncols) for(i in 1:nrows){ for(j in 1:ncols){ # worry about the corners first if(i==1 & j==1){ neebs[i,j] <- alive[i+1,j] + alive[i,j+1] + alive[i+1,j+1]} if(i==1 & j==ncols){ neebs[i,j] <- alive[i,j-1] + alive[i+1,j-1] + alive[i+1,j]} if(i==nrows & j==1){ neebs[i,j] <- alive[i-1,j] + alive[i,j+1] + alive[i-1,j+1]} if(i==nrows & j==ncols){ neebs[i,j] <- alive[i-1,j-1] + alive[i,j-1] + alive[i-1,j]} # now the edges if(i==1 & (j!=1 & j!=ncols) ){ neebs[i,j] <- sum(alive[i+1,(j-1):(j+1)]) + alive[i,j-1] + alive[i,j+1]} if(i==ncols & (j!=1 & j!=ncols) ){ neebs[i,j] <- sum(alive[i-1,(j-1):(j+1)]) + alive[i,j-1] + alive[i,j+1]} if((i!=nrows & i!=1 ) & j==1){ neebs[i,j] <- sum(alive[(i-1):(i+1), j+1]) + alive[i-1,j] + alive[i+1,j]} if((i!=nrows & i!=1 ) & j==ncols){ neebs[i,j] <- sum(alive[(i-1):(i+1), j-1]) + alive[i-1,j] + alive[i+1,j]} # and finally, the regular cells if((i!=nrows & i!=1 ) & (j!=1 & j!=ncols) ){ neebs[i,j] <- sum(alive[i+1,(j-1):(j+1)]) + sum(alive[i-1,(j-1):(j+1)]) + sum(alive[i,c(j-1,j+1)])} }} # check! By adding text to the existing plot for(i in 1:nrows){ for(j in 1:ncols){ text(j,i, neebs[i,j], col="white") }} # now do the updates alive.new <- matrix(NA, nrows, ncols) for(i in 1:nrows){ for(j in 1:ncols){ if(alive[i,j]==1 & neebs[i,j]<2){alive.new[i,j] <- 0} if(alive[i,j]==1 & neebs[i,j] %in% 2:3){alive.new[i,j] <- 1} if(alive[i,j]==1 & neebs[i,j]>3){alive.new[i,j] <- 0} if(alive[i,j]==0 & neebs[i,j]==3){alive.new[i,j] <- 1} if(alive[i,j]==0 & neebs[i,j]!=3){alive.new[i,j] <- 0} }} alive <- alive.new # and re-plot for(i in 1:nrows){ for(j in 1:ncols){ rect(j-0.5,i-0.5,j+0.5,i+0.5, col=alive[i,j] + 1, border="cyan") }} # could wrap all of the code above in a for() loop # slightly nice to wrap all of in a function, then use that do.update <- function(alive){ neebs <- matrix(NA, nrows, ncols) for(i in 1:nrows){ for(j in 1:ncols){ # worry about the corners first if(i==1 & j==1){ neebs[i,j] <- alive[i+1,j] + alive[i,j+1] + alive[i+1,j+1]} if(i==1 & j==ncols){ neebs[i,j] <- alive[i,j-1] + alive[i+1,j-1] + alive[i+1,j]} if(i==nrows & j==1){ neebs[i,j] <- alive[i-1,j] + alive[i,j+1] + alive[i-1,j+1]} if(i==nrows & j==ncols){ neebs[i,j] <- alive[i-1,j-1] + alive[i,j-1] + alive[i-1,j]} # now the edges if(i==1 & (j!=1 & j!=ncols) ){ neebs[i,j] <- sum(alive[i+1,(j-1):(j+1)]) + alive[i,j-1] + alive[i,j+1]} if(i==ncols & (j!=1 & j!=ncols) ){ neebs[i,j] <- sum(alive[i-1,(j-1):(j+1)]) + alive[i,j-1] + alive[i,j+1]} if((i!=nrows & i!=1 ) & j==1){ neebs[i,j] <- sum(alive[(i-1):(i+1), j+1]) + alive[i-1,j] + alive[i+1,j]} if((i!=nrows & i!=1 ) & j==ncols){ neebs[i,j] <- sum(alive[(i-1):(i+1), j-1]) + alive[i-1,j] + alive[i+1,j]} # and finally, the regular cells if((i!=nrows & i!=1 ) & (j!=1 & j!=ncols) ){ neebs[i,j] <- sum(alive[i+1,(j-1):(j+1)]) + sum(alive[i-1,(j-1):(j+1)]) + sum(alive[i,c(j-1,j+1)])} }} # now do the updates alive.new <- matrix(NA, nrows, ncols) for(i in 1:nrows){ for(j in 1:ncols){ if(alive[i,j]==1 & neebs[i,j]<2){alive.new[i,j] <- 0} if(alive[i,j]==1 & neebs[i,j] %in% 2:3){alive.new[i,j] <- 1} if(alive[i,j]==1 & neebs[i,j]>3){alive.new[i,j] <- 0} if(alive[i,j]==0 & neebs[i,j]==3){alive.new[i,j] <- 1} if(alive[i,j]==0 & neebs[i,j]!=3){alive.new[i,j] <- 0} }} # return what we want - the last line evaluated alive.new } refresh.grid <- function(alive){ for(i in 1:nrows){ for(j in 1:ncols){ rect(j-0.5,i-0.5,j+0.5,i+0.5, col=alive[i,j] + 1, border="cyan") }} invisible() # for when your function doesn't return anything } # now use the functions nrows <- 50 ncols <- 50 set.seed(2013) # Battle of Wimbledon Center Court alive <- matrix(rbinom(nrows * ncols, 1, 0.4), nrows, ncols) #setup plot par(mar=c(2,2,0,0)) plot(0,0, type="n", xlab="", ylab="", xlim=c(0.5,nrows+0.5+5), ylim=c(0.5,ncols+0.5), asp=1) # go! (with an added counter) for(k in 1:100){ alive <- do.update(alive) refresh.grid(alive) legend("bottomright", bg="white", legend=paste("step",k), lty=0) }