|
|
This is the classic Conway's Game of Life cellular automata simulation. It demonstrates the use of the advanced Grid component and how it can be tied to a two-dimensional array in the scripting language, and easily changed between multiple arrays. While the performance of the scripting language for large grids is limited, the program is fast enough to be an effective demonstration.
[Click here to see the XML source code]
Here is the zApp XML source code for this application:
Code: |
<?xml version='1.0' encoding='ISO-8859-1' ?>
<!DOCTYPE zapp [
<!ENTITY AppTitle "Zeus Demo: Life Simulation">
<!ENTITY AppAuthor "Zugg Software">
<!ENTITY AppVersion "1.0">
<!ENTITY AppURL "http://www.zuggsoft.com/">
<!ENTITY AppImage "ZAPP">
<!ENTITY AboutBox SYSTEM "aboutbox.xml">
]>
<zapp>
<splash color='#C4D2ED'>
<image image='zapp' deltaleft='8' deltatop='8'/>
<label align='Client' bevelouter='Lowered' autoleft='true' deltaleft='8' width='-8' height='-8' gradienttype='FullVertical' color='#C4D2ED' colorto='#7E98CB'><![CDATA[<b>&AppTitle;</b><br><br>
Version &AppVersion;<br><br>
by &AppAuthor;]]></label>
</splash>
<action name='StartSim' caption='Run/Stop' hint='Run simulation' image='play'>
if StartSim.Checked then
StartSim.Checked = false
StartSim.Hint = "Run simulation"
PauseSim.Hint = "Step simulation"
else
StartSim.Checked = true
StartSim.Hint = "Pause simulation"
PauseSim.Hint = "Pause simulation"
end if
LifeTimer.Enabled = StartSim.Checked
</action>
<action name='PauseSim' caption='Pause/Step' hint='Step simulation' image='pause'>
if StartSim.Checked then
StartSim.Checked = false
StartSim.Hint = "Run simulation"
PauseSim.Hint = "Step simulation"
LifeTimer.Enabled = StartSim.Checked
else
LifeTimer.Execute
end if
</action>
<toolbar name='mainmenu'>
<menu caption='&File'>
<item action='_FileExit'/>
</menu>
<menu caption='&View'>
<item caption='Normal' script='core.themeindex = -1'/>
<item caption='Aqua' script='core.theme = "aqua"'/>
<item action='_ThemeSelect'/>
</menu>
<menu caption='&Actions'>
<item action='StartSim'/>
<item action='PauseSim'/>
<itemsep/>
<item caption='Randomize'>
for i = 0 to UBound(a,1)
for j = 0 to UBound(a,2)
if (math.randomint(0,100) > 70) then
a(i,j) = CellColor.value
b(i,j) = CellColor.value
end if
next
next
grid.datachanged
gen = 0
Status.Text = "Generation: 0"
</item>
<item caption='Clear'>
for i = 0 to UBound(a,1)
for j = 0 to UBound(a,2)
a(i,j) = 0
b(i,j) = 0
next
next
grid.datachanged
gen = 0
Status.Text = "Generation: 0"
</item>
</menu>
<menu caption='&Help'>
<item caption='&About' script='core.execwindow( "About")'/>
</menu>
<itemsep/>
<item action='StartSim'/>
<item action='PauseSim'/>
<itemsep/>
<combo.colors name='CellColor' colors='x11ordered' text='gold' hint='Cell color'/>
<spinedit name='Interval' value='500' minvalue='100' increment='100' width='80' hint='Update interval'/>
</toolbar>
<window name='main' caption='&AppTitle;' left="50" top="80" height="596" width="524">
<toolbar name='mainmenu'/>
<timer name='LifeTimer' interval='=Interval.value' immediate='true'>
sub Generate( oldA, newA)
maxi = UBound(newA,1)
maxj = UBound(newA,2)
for j = 0 to maxj
for x = 0 to 2
if (j+x < 1) or (j+x-1 > maxj) then
z = 0
elseif (oldA(0,j+x-1) > 0) then
z = 1
else
z = 0
end if
prev(x) = 0
prev2(x) = 0
prev3(x) = z
sum(x) = z
next
for i = 0 to maxi
count = 0
for x = 0 to 2
if (i < -1) or (i >= maxi) or (j+x < 1) or (j+x-1 > maxj) then
z = 0
elseif (oldA(i+1,j+x-1) > 0) then
z = 1
else
z = 0
end if
y = sum(x) - prev(x) + z
count = count + y
sum(x) = y
prev(x) = prev2(x)
prev2(x) = prev3(x)
prev3(x) = z
next
z = prev2(1)
count = count - z
if (count < 2) then
y = 0
elseif (count = 2) then
if (z = 0) then y = 0 else y = col
elseif (count = 3) then
y = col
else
y = 0
end if
newA(i,j) = y
next
next
end sub
col = CellColor.Value
if (igen = 0) then
Generate a, b
grid.data = b
igen = 1
else
Generate b, a
grid.data = a
igen = 0
end if
grid.update
gen = gen + 1
Status.Text = "Generation: " & gen
</timer>
<grid name='Grid' Align='client'>
<script event='oncellclick'>
if (zEvent.Button = "Left") then
grid.cell( zEvent.Row, zEvent.Col) = CellColor.Value
elseif (zEvent.Button = "Right") then
grid.cell( zEvent.Row, zEvent.Col) = 0
end if
zEvent.Handled = true
grid.datachanged
</script>
</grid>
<statusbar name='Status' showhelp='false'/>
<script>
dim a(), b()
dim sum(2), prev(2), prev2(2), prev3(2)
redim a(63,63), b(63,63)
for i = 0 to UBound(a,1)
for j = 0 to UBound(a,2)
a(i,j) = 0
b(i,j) = 0
next
next
igen = 0
grid.defkind="color"
grid.rowheight=8
grid.colwidth=8
grid.data=a
grid.gridlines="both"
grid.gridlinecolor="black"
grid.invertselect=false
grid.editing=false
gen = 0
</script>
</window>
&AboutBox;
</zapp> |
Most of the code consists of the script for generating the next generation of the life pattern. The algorithm is hard to read because it was optimized for as much performance as possible. It basically keeps track of running sums across a row rather than computing the neighbors individually. |
|