Just something I made when I was bored. 1d Cellular automata are a great example of how simple rules can give rise to complex behaivour. What a cellular automata is is described well here:

http://math.hws.edu/xJava/CA/CA.html
Rules 30, 106 and 110 are my favorites. I think that for every pattern, there's an inverse (swap all white with black), a mirror (flip about the starting node) and an inverse mirror, so even though there are 256 different rules, there are only 64 distinct ones. (don't quote me on that though)

Press up/down to change the ruleset

press right/left to change the starting row to be either random or a single point. Random is usually more interesting.

global w as integer
global h as integer
global rule as integer
rule=0
w=screen width()
h=screen height()-32
dim cells(w,h)
for x=0 to w
for y=0 to h
cells(x,y)=0
next y
next x
cells(500,0)=1
isRandom=0
setFirstRowCentered()
regenerateCellsAndDraw()
do
text 0,0,"Rule "+str$(rule)
text 0,16,"Control w/ arrowkeys: up/down to change rule, left/right to randomize first row"
if leftkey()=1
setFirstRowRandom()
regenerateCellsAndDraw()
wait 50
endif
if rightkey()=1
setFirstRowCentered()
regenerateCellsAndDraw()
wait 50
endif
if upkey()=1
rule=rule+1
if rule>255 then rule=0
regenerateCellsAndDraw()
wait 50
endif
if downkey()=1
rule=rule-1
if rule<0 then rule=255
regenerateCellsAndDraw()
wait 50
endif
loop
end
function clearCells()
for x=0 to w
for y=1 to h
cells(x,y)=0
next y
next x
endfunction
function clearFirstRow()
for x=0 to w
cells(x,0)=0
next x
endfunction
function setFirstRowCentered()
clearFirstRow()
cells(w/2,0)=1
endfunction
function setFirstRowRandom()
for x=0 to w
cells(x,0)=rnd(1)
next x
endfunction
function regenerateCellsAndDraw()
for ch=1 to h
for cx=0 to w
leftblock=getBlockAt(cx-1,ch-1)
midblock=getBlockAt(cx,ch-1)
rightblock=getBlockAt(cx+1,ch-1)
cells(cx,ch)=getRuleAt(leftblock,midblock,rightblock)
next current_xpos
next current_height
cls
lock pixels
for x=0 to w
for y=0 to h
if getBlockAt(x,y)=1
dot x,y+32
endif
next y
next x
unlock pixels
endfunction
function getRuleBit(num)
tmp= (rule>>num)&&1
endfunction tmp
function getRuleAt(leftblock,midblock,rightblock)
if leftblock=1
if midblock=1
if rightblock=1
exitfunction getRuleBit(7) //111
else
exitfunction getRuleBit(6) //110
endif
else
if rightblock=1
exitfunction getRuleBit(5) //101
else
exitfunction getRuleBit(4) //100
endif
endif
else
if midblock=1
if rightblock=1
exitfunction getRuleBit(3) //011
else
exitfunction getRuleBit(2) //010
endif
else
if rightblock=1
exitfunction getRuleBit(1) //001
else
exitfunction getRuleBit(0) //000
endif
endif
endif
endfunction 0
function getBlockAt(x,y)
if x<0 then exitfunction 0
if y<0 then exitfunction 0
if x>w then exitfunction 0
if y>h then exitfunction 0
value=cells(x,y)
endfunction value