Conways game of life is a basic cellular automata simulation. In this grid-based simulation the state of a cell, dead or alive, is defined by the number of its direct neighbors:
#| standalone: true
#| viewerHeight: 700
from shiny import *
xdim=80
ydim=25
steps=100
def create_grid(xdim,ydim):return( [[x]*xdim for x in [0]* ydim] )
def neigbors(grid):
neib = create_grid(xdim,ydim)
for i in range(ydim):
for j in range(xdim):
for y in range(i-1,i+2):
for x in range(j-1,j+2):
neib[i][j] += grid[y%ydim][x%xdim]
neib[i][j] = neib[i][j]-grid[i][j]
return(neib)
def step(grid):
neibs = neigbors(grid)
for i in range(ydim):
for j in range(xdim):
if grid[i][j] == 1:
if neibs[i][j] in [2,3]:
grid[i][j] = 1
else:
grid[i][j] = 0
else:
if neibs[i][j] == 3:
grid[i][j] = 1
return(grid)
def populate(grid,coord_array):
coord_range = [(y, x) for y in range(ydim) for x in range(xdim)]
for (y,x) in coord_range:
if (y,x) in coord_array:
grid[y][x]=1
return(grid)
def Vis(grid):
vis = str()
for y in range(ydim):
for x in range(xdim):
if grid[y][x] == 0: vis += '░'
else: vis += '█'
vis += '\n'
return vis
creatures = {
"glider" : [(0,1),(1,2),(2,0),(2,1),(2,2),(10,1),(11,2),(12,0),(12,1),(12,2)],
"blinker" : [(10,10),(10,11),(10,12)],
"ggun" :[(5,1),(5,2),(6,1),(6,2),(5,11),(6,11),(7,11),(4,12),(8,12),(3,13),(9,13),
(3,14),(9,14),(6,15),(4,16),(8,16),(5,17),(6,17),(7,17),(6,18),(3,21),(4,21),
(5,21),(3,22),(4,22),(5,22),(2,23),(6,23),(2,25),(7,25),(1,25),(6,25),(3,35),(4,35),(3,36),(4,36)]
}
# [(15,9),(15,10),(16,9),(16,10),(16,23),(13,21),(13,22),(14,20),(15,19),(16,19),(17,19),(19,21),(19,22),(18,20),(15,25),(16,25),(16,26),(17,25),(18,24),(14,24),(13,29),(13,30),(14,29),(14,30),(15,29),(15,30),(16,31),(12,31),(16,33),(11,33),(17,33),(12,33),(13,43),(13,44),(14,43),(14,44)]
def main(xdim,ydim,steps,creature):
grid = create_grid(xdim,ydim)
populate(grid,creatures[creature])
visus = [Vis(grid)]
for s in range(1,steps):
visus.append(Vis(step(grid)))
return(visus)
app_ui = ui.page_fluid(
ui.row(
ui.input_slider("n", "Step", 0, steps, 0, animate=True),
ui.input_select(
"id", "Creature",
choices={"ggun":"Glidergun","glider":"Glider","blinker":"Blinker"}
) ),
ui.row(
ui.column(
12,
ui.output_text_verbatim("GOL")
)
)
)
def server(input, output, session):
@reactive.Calc
def create_GOL():
return main(xdim,ydim,steps,creature=str(input.id()))
@output
@render.text
def GOL():
return create_GOL()[input.n()]
app = App(app_ui, server)
Shinylive for Python facilitates the deveolpment of shinyapps using python, that can be compiled for the browser using Webassembly.
To populate our World the populate fuction adds living cells at defined locations in the grid, specified by an array of coordinate tuples.
def populate(grid,coord_array): coord_range = [(y, x) for y inrange(ydim) for x inrange(xdim)] for (y,x) in coord_range:if (y,x) in coord_array: grid[y][x]=1return(grid)
The coord_array are stored in a dict called creatures: