-- CONWAY'S GAME OF LIFE
-- (C) 2010 INPE AND UFOP

ALIVE = 1
DEAD  = 2

attr_value 	= {ALIVE, DEAD}	
attr_color 	= {BLACK, WHITE}
 
TURNS = 300

function random (cs)
	forEachCell (cs, function (cell)
		local v = math.random()
		if v > 0.85 then
			cell.state = ALIVE
		else
			cell.state = DEAD
		end
		
	end)
end

function countAlive(cell)
	local count = 0
	forEachNeighbor(cell, function(cell, neigh)
		if neigh.past.state == ALIVE then
			count = count + 1
		end
	end)
	return count
end

cs = CellularSpace{
	xdim = 50
}

math.randomseed(os.time())
random(cs)
createMooreNeighborhood(cs, "1", false)

lifeLeg = Legend{
		-- Attribute: state
		type = TYPES.NUMBER,
		groupingMode = GROUPING.UNIQUEVALUE,
		slices = 5,
		precision = 6,
		stdDeviation = STDDEVIATION.NONE,
		maximum = 2,
		minimum = 1,
		colorBar1 = {
			{BLACK, ALIVE},
			{WHITE, DEAD}
		},
		colorBar2 = {}
}

cs:createObserver(OBSERVERS.MAP, {"state"}, {lifeLeg})

gameoflife = Automaton {
	it = Trajectory { 
		cs, 
		function(cell)  return true; end,
	},
	State{
    	id = "alive",
		Jump {
			function( event, agent, cell )
				return  (cell.past.state == DEAD)
			end,
			target = "dead" 
		},
		Flow{
			function( event, agent, cell )
				n = countAlive(cell)
				if (n > 3) or (n < 2)  then	cell.state = DEAD end
			end
	    }
	},
         	 	 
	State{
		id = "dead",
		Jump {
			function( event, agent, cell )
				return (cell.past.state == ALIVE)
			end,
			target = "alive"
		},
		Flow{
			function( event, agent, cell )
				n = countAlive(cell)
				if n == 3 then cell.state = ALIVE end
			end
		}
	}
 }
  
env = Environment{	
	id = "env",
	cs1 = cs,
	aut = gameoflife,
	time = Timer{
		Event{ message = function( event )
			print ("tick ", event:getTime())
			cs:synchronize()
			cs:notifyObservers()
			gameoflife:execute(event)
			return true
		end}
	}
}

gameoflife:setTrajectoryStatus(true)

env:execute(TURNS)
