math = require("math")
-- the game of life class itself
GameOfLife = {}
GameOfLife.__index = GameOfLife
function GameOfLife:Create(grid_size)
local this =
{
grid_size = grid_size or {10,10},
grid = {}
}
setmetatable(this, GameOfLife)
this.size = this.grid_size[1] * this.grid_size[2]
for i=1,this.size do
this.grid[i] = 0
end
return this
end
-- member function to initalize with some random values
function GameOfLife:init_random(p)
for i=1,self.size do
self.grid[i] = (math.random() < p) and 1 or 0
end
end
-- helper function to convert a coordinate {x,y} into a
-- scalar offset
function GameOfLife:to_offset(coord)
return (coord[1]-1) * self.grid_size[2] + (coord[2] -1) + 1
end
-- helper function to access the value of the grid at a coordinate {x,y}
function GameOfLife:at(coord)
return self.grid[self:to_offset(coord)]
end
-- the function to do a step
function GameOfLife:step()
new_grid = {}
for x=1,self.grid_size[1] do
for y=1, self.grid_size[2] do
local c = 0
for xx=-1,1 do
for yy=-1,1 do
nx = x + xx
ny = y + yy
if nx >=1 and ny>=1 and nx <=self.grid_size[1] and ny <=self.grid_size[2] and not (xx==0 and yy ==0) then
c = c + self:at({nx,ny})
end
end
end
local offset = self:to_offset({x,y})
local current_state = self:at({x,y})
new_grid[offset] = 0
if current_state == 0 then
if c == 3 then
new_grid[offset] = 1
end
else
if c==2 or c==3 then
new_grid[offset] = 1
else
new_grid[offset] = 0
end
end
--
end
end
self.grid = new_grid
end
-- helper function to draw the grid as string
function GameOfLife:__tostring()
s = "*"
for y=1, self.grid_size[2] do
s = s .. "--"
end
s = s .. "*\n"
for x=1,self.grid_size[1] do
s = s .. "|"
for y=1, self.grid_size[2] do
local state = self:at({x,y})
if state == 0 then
ss = " "
else
ss = "O"
end
s = s .. ss .. " "
end
s = s .. "|\n"
end
s = s .. "*"
for y=1, self.grid_size[2] do
s = s .. "--"
end
s = s .. "*\n"
return s
end
-- initalize the game of life
grid_size = {20,20}
game_of_life = GameOfLife:Create(grid_size)
game_of_life:init_random(0.5)
-- a tiny gui
function speed_to_interval(speed)
return 1.0 / speed
end
speed = 0.001
hbox = ilua.widgets.hbox()
play = ilua.widgets.play({interval=speed_to_interval(speed), max=1000000})
output = ilua.widgets.output()
step_label = ilua.widgets.label({value="Step: "..tostring(play.value)})
speed_label = ilua.widgets.label({value="Speed: "..tostring(speed)})
speed_slider = ilua.widgets.slider({min=0.001, max=0.5, step=0.01})
hbox:add(play,step_label,speed_label)
speed_slider:register_observer(function(value)
output:captured(function()
speed = value
play.interval = speed_to_interval(speed)
speed_label.value = "Speed: " .. tostring(speed)
end)
end)
play:register_observer(function(value)
if value <= 0.1 then
game_of_life:init_random(0.24)
end
-- use output widget to caputre prints
output:captured(function()
ilua.display.clear_output(false)
step_label.value = "STEP "..tostring(play.value)
game_of_life:step()
print(tostring(game_of_life))
end)
end)
ilua.display.display(hbox,speed_slider, output)