Here's another cellular autonomy program
I've found that having a buffer, and what you do with it, is one of the most important things for this type of program.
I've used an array to store two versions of the world, a buffer and active version. This allows the program to make changes to the world that don't effect the cells that have yet to be checked.
The sand tap only exists in one version of the world, and so the line of falling sand is dotted.
remstart
~~~~~~~~~~~~~~~~~~~~~~~~~
Sand Simulation
~~~~~~~~~~~~~~~~~~~~~~~~~
There are 4 different cell types:
* Empty Cells
* Tap Cells
Taps produce sand cells in the square below (if empty)
* Sand Cells
Sand falls to the square below, if it comes into contact with a foreign
cell type it will remain there, if it collides with another sand cell it will try to
move off diagonally down to one side (right has priority), if neither side is open it will stay where it is
* Wall Cells
Wall cells stop sand from spilling out
~~~~~~~~~~~~~~~~~~~~~~~~~
remend
`Setup
hide mouse
sync on
`Define Active Screen Position
sx=100 : sy=100
`Make Cell Array
DIM cell(1,49,49)
active=0
empty=0 : sand=1 : solid=2 : tap=3
`make boundaries
for a = 0 to 1
for s = 0 to 49
cell(a,0,s)=solid
cell(a,49,s)=solid
cell(a,s,49)=solid
next s
`ledge
for x = 5 to 14
cell(a,x,30)=solid
cell(a,x+5,40)=solid
next x
next a
`make tap
cell(0,10,4)=tap
`colours
DIM colour(3)
colour(0)=rgb(40,40,40)
colour(1)=rgb(255,255,100)
colour(2)=rgb(128,0,128)
colour(3)=rgb(255,0,0)
`square scale
scale=5
`~~~~~~~~~~~~~~~~~~~~
` Main Loop
`~~~~~~~~~~~~~~~~~~~~
do
for y = 0 to 49
for x = 0 to 49
`Tap
if cell(active,x,y)=tap
if y<49
if cell(active,x,y+1)=empty then cell(active,x,y+1)=sand
endif
endif
`Sand
if cell(active,x,y)=sand
if y<49
`drop sand
if cell(active,x,y+1)=empty
cell(1-active,x,y)=empty : cell(1-active,x,y+1)=sand
else
if x<49
if cell(active,x+1,y+1)=empty
cell(1-active,x,y)=empty : cell(1-active,x+1,y+1)=sand
else
if x>0
if cell(active,x-1,y+1)=empty
cell(1-active,x,y)=empty : cell(1-active,x-1,y+1)=sand
else
cell(1-active,x,y)=sand
endif
endif
endif
endif
endif
endif
endif
`*DISPLAY
ink colour( cell(active,x,y) ),0
box sx+(x*scale),sy+(y*scale),sx+(x*scale)+scale,sy+(y*scale)+scale
next x
next y
active=1-active
sync
loop
[edit]
Sand! version 3
I've tidied it up a bit (cell detection is still horrible with lots of if statements) and it will now scale the grid to fit in the screen. I haven't let the user adjust the grid's size but I've labelled the variables in the code so you can change them.
remstart
~~~~~~~~~~~~~~~~~~~~~~~~~
Sand Simulation
~~~~~~~~~~~~~~~~~~~~~~~~~
There are 4 different cell types:
* Empty Cells
* Tap Cells
Taps produce sand cells in the square below (if empty)
* Sand Cells
Sand falls to the square below, if it comes into contact with a foreign
cell type it will remain there, if it collides with another sand cell it will try to
move off diagonally down to one side (right has priority), if neither side is open it will stay where it is
* Wall Cells
Wall cells stop sand from spilling out
~~~~~~~~~~~~~~~~~~~~~~~~~
remend
`Setup
sync on
`Define Active Screen Position
sw=screen width() : sh=screen height()
sx=50 : sy=100
`Make Cell Array
maxx=39 : maxy=79 : `** THESE VARIABLES ARE THE SIZE OF THE WORLD **
if maxx>sw+10 then maxx=sw-10
if maxy>sh+10 then maxy=sh-10
DIM cell(1,maxx,maxy)
active=0
empty=0 : sand=1 : solid=2 : tap=3
`cell size
scale=0
repeat
inc scale,1
until maxx*(scale+1)+sx > sw-(2*scale) or maxy*(scale+1)+sy > sh-(2*scale)
`colours
DIM colour(3)
colour(0)=rgb(40,40,40)
colour(1)=rgb(255,255,100)
colour(2)=rgb(128,0,128)
colour(3)=rgb(255,0,0)
`~~~~~~~~~~~~~~~~~~~~
` EDITOR
`~~~~~~~~~~~~~~~~~~~~
`blank
ink colour(empty),0
box sx,sy,sx+(maxx*scale),sy+(maxy*scale)
`make solid frame
ink colour(solid),0
for a = 0 to 1
for y = 0 to maxy
for x = 0 to maxx
cell(a,x,maxy)=solid
cell(a,0,y)=solid
cell(a,maxx,y)=solid
box sx+(x*scale),sy+(maxy*scale),sx+(x*scale)+scale,sy+(maxy*scale)+scale
box sx+(0*scale),sy+(y*scale),sx+(0*scale)+scale,sy+(y*scale)+scale
box sx+(maxx*scale),sy+(y*scale),sx+(maxx*scale)+scale,sy+(y*scale)+scale
next x
next y
next a
DO
mx=(mousex()-sx)/scale : my=(mousey()-sy)/scale : mc=mouseclick()
if mc>0 and mc<3
if mx>=0 and mx<=maxx
if my>=0 and my<=maxy
cell(0,mx,my)=mc+1
if mc=1 then cell(1,mx,my)=mc+1
`draw cell
ink colour( cell(0,mx,my) ),0
box sx+(mx*scale),sy+(my*scale),sx+(mx*scale)+scale,sy+(my*scale)+scale
endif
endif
endif
if returnkey()=1 then exit
text 0,0,"Left Click to place solid cells, Right click to place a sand tap."
text 0,20,"PRESS RETURN TO BEGIN SIMULATION"
sync
LOOP
`~~~~~~~~~~~~~~~~~~~~
` Main Loop
`~~~~~~~~~~~~~~~~~~~~
hide mouse
cls
do
for y = 0 to maxy
for x = 0 to maxx
`Tap
if cell(active,x,y)=tap
if y<maxy
if cell(active,x,y+1)=empty then cell(active,x,y+1)=sand
endif
endif
`Sand
if cell(active,x,y)=sand
sandx=0 : sandy=0
`if cell is above the bottom of grid
if y<maxy
if cell(active,x,y+1)=empty : `cell below empty
sandy=+1
else
if x<maxx and cell(active,x+1,y+1)=empty
sandx=+1 : sandy=+1
else
if x>0 and cell(active,x-1,y+1)=empty then sandx=-1 : sandy=+1
endif
endif
endif
`update sand position
cell(1-active,x,y)=empty : `empty old position
cell(1-active,x+sandx,y+sandy)=sand : `fill new position
endif
`*DISPLAY
ink colour( cell(active,x,y) ),0
box sx+(x*scale),sy+(y*scale),sx+(x*scale)+scale,sy+(y*scale)+scale
next x
next y
active=1-active
sync
loop
