Page 1 of 1

Conway's Game of Life, slow update

Posted: Sun Oct 08, 2017 8:22 am
by Teptai
Hi, i made a simple version of Conway's Game of Life but the bigger the grid is the slower it updates. How can i make the calculation cycle faster so i can update the grid every second?

Code: Select all

function love.load()

--https://forums.coronalabs.com/topic/27482-copy-not-direct-reference-of-table/
-- Creates a complete/deep copy of the data
function deepCopy(object)
    local lookup_table = {}
    local function _copy(object)
        if type(object) ~= "table" then
            return object
        elseif lookup_table[object] then
            return lookup_table[object]
        end
        local new_table = {}
        lookup_table[object] = new_table
        for index, value in pairs(object) do
            new_table[_copy(index)] = _copy(value)
        end
        return setmetatable(new_table, getmetatable(object))
    end
    return _copy(object)
end

map = {
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0},
	{ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0},
	{ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0},
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0},
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0},
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},
	{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{ 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0},
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0},
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1},
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}
}

tempmap = deepCopy(map)
gridMax = #map
gridX = 1
gridY = 1
count = 0
deadCount = 0
generation = 1
tick = 0

end
 
function love.update(dt)
	tick = tick + dt
	if (tick > 1) then	
		love.loop()
	end
end

function love.loop()

	--main loop
	do					
		--check north
		if (map[gridX][gridY] == 1 and gridY > 1) then			
			if (map[gridX][gridY - 1] == 1) then
				count = count + 1
			end
		elseif (map[gridX][gridY] == 0 and gridY > 1) then			
			if (map[gridX][gridY - 1] == 1) then
				deadCount = deadCount + 1
			end
		end	
		--check east
		if (map[gridX][gridY] == 1 and gridX < gridMax) then			
			if (map[gridX + 1][gridY] == 1) then
				count = count + 1
			end
		elseif (map[gridX][gridY] == 0 and gridX < gridMax) then			
			if (map[gridX + 1][gridY] == 1) then
				deadCount = deadCount + 1
			end
		end
		--check south
		if (map[gridX][gridY] == 1 and gridY < gridMax) then			
			if (map[gridX][gridY + 1] == 1) then
				count = count + 1
			end
		elseif (map[gridX][gridY] == 0 and gridY < gridMax) then			
			if (map[gridX][gridY + 1] == 1) then
				deadCount = deadCount + 1
			end
		end	
		--check west
		if (map[gridX][gridY] == 1 and gridX > 1) then			
			if (map[gridX - 1][gridY] == 1) then
				count = count + 1
			end
		elseif (map[gridX][gridY] == 0 and gridX > 1) then			
			if (map[gridX - 1][gridY] == 1) then
				deadCount = deadCount + 1
			end
		end		
		--check ne
		if (map[gridX][gridY] == 1 and gridX < gridMax and gridY > 1) then			
			if (map[gridX + 1][gridY - 1] == 1) then
				count = count + 1
			end
		elseif (map[gridX][gridY] == 0 and gridX < gridMax and gridY > 1) then			
			if (map[gridX + 1][gridY - 1] == 1) then
				deadCount = deadCount + 1
			end
		end		
		--check se
		if (map[gridX][gridY] == 1 and gridX < gridMax and gridY < gridMax) then			
			if (map[gridX + 1][gridY + 1] == 1) then
				count = count + 1
			end
		elseif (map[gridX][gridY] == 0 and gridX < gridMax and gridY < gridMax) then			
			if (map[gridX + 1][gridY + 1] == 1) then
				deadCount = deadCount + 1
			end
		end		
		--check sw
		if (map[gridX][gridY] == 1 and gridX > 1 and gridY < gridMax) then			
			if (map[gridX - 1][gridY + 1] == 1) then
				count = count + 1
			end
		elseif (map[gridX][gridY] == 0 and gridX > 1 and gridY < gridMax) then			
			if (map[gridX - 1][gridY + 1] == 1) then
				deadCount = deadCount + 1
			end
		end			
		--check nw
		if (map[gridX][gridY] == 1 and gridX > 1 and gridY > 1) then			
			if (map[gridX - 1][gridY - 1] == 1) then
				count = count + 1
			end
		elseif (map[gridX][gridY] == 0 and gridX > 1 and gridY > 1) then			
			if (map[gridX - 1][gridY - 1] == 1) then
				deadCount = deadCount + 1
			end
		end
		
		--check if cell lives or dies			
		if(map[gridX][gridY] == 1 and count < 2) then
			tempmap[gridX][gridY] = 0
		elseif (map[gridX][gridY] == 1 and count <= 3 and count > 1) then
			tempmap[gridX][gridY] = 1
		elseif (map[gridX][gridY] == 1 and count > 3) then
			tempmap[gridX][gridY] = 0
		--check if dead cell reanimates			
		elseif (map[gridX][gridY] == 0 and deadCount == 3) then
			tempmap[gridX][gridY] = 1
		elseif (map[gridX][gridY] == 0 and deadCount ~= 3) then
			tempmap[gridX][gridY] = 0			
		end
		
		--check if there's grid positions left, if not then start over		
		if (gridX >= gridMax and gridY < gridMax) then
			gridX = 1
			gridY = gridY + 1
			count = 0
			deadCount = 0
		elseif (gridX >= gridMax and gridY >= gridMax) then
			gridX = 1
			gridY = 1
			count = 0
			deadCount = 0
			map = deepCopy(tempmap)
			generation = generation + 1
			tick = 0
		else
			gridX = gridX + 1
			count = 0
			deadCount = 0
		end
	end

end

function love.draw()

	--draw map
	for y=1, #map do
		for x=1, #map[y] do
			if map[y][x] == 1 then
				love.graphics.setColor(20, 248, 242)
				love.graphics.rectangle("fill", x * 32, y * 32, 32, 32)
			else
				love.graphics.rectangle("line", x * 32, y * 32, 32, 32)
			end
		end
	end
	
	--draw infotext
	love.graphics.setColor(20, 248, 242)
	love.graphics.print("gridX " .. gridX, 700, 30)
	love.graphics.print("gridY " .. gridY, 700, 45)
	love.graphics.print("gridMax " .. gridMax, 700, 60)	
	love.graphics.print("generation " .. generation, 700, 75)	
	love.graphics.print("tick " .. tick, 700, 90)
end
 
function love.keypressed(key)
	if key == "escape" then
		love.event.quit()
	end
end
 

Re: Conway's Game of Life, slow update

Posted: Sun Oct 08, 2017 8:32 pm
by grump
You're updating only one grid cell per update call: love.update gets called only once per frame. You probably want to update the whole thing instead by making two loops that iterate over the grid.

Code: Select all

for gridY = 1, gridMax do
    for gridX = 1, gridMax do 
       .....
    end
end
Your code is kind of strange. You're not supposed to put everything in love.load. And while not exactly wrong, it makes little sense to put random functions in the love table, like you did with love.loop.

Re: Conway's Game of Life, slow update

Posted: Mon Oct 09, 2017 12:47 pm
by Teptai
Hi, thanks for your reply, i got it to work as intended with your for loop. Thank you. Here's the updated code and .love file if anyone's intrested. Any other suggestions to make the code better?

Code: Select all

function love.load()

--https://forums.coronalabs.com/topic/27482-copy-not-direct-reference-of-table/
-- Creates a complete/deep copy of the data
function deepCopy(object)
    local lookup_table = {}
    local function _copy(object)
        if type(object) ~= "table" then
            return object
        elseif lookup_table[object] then
            return lookup_table[object]
        end
        local new_table = {}
        lookup_table[object] = new_table
        for index, value in pairs(object) do
            new_table[_copy(index)] = _copy(value)
        end
        return setmetatable(new_table, getmetatable(object))
    end
    return _copy(object)
end

map = {
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0},
	{ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0},
	{ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0},
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0},
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0},
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},
	{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{ 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0},
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0},
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1},
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}
}

tempmap = deepCopy(map)
gridMax = #map
gridX = 1
gridY = 1
count = 0
deadCount = 0
generation = 1
tick = 0
mouseX = 0
mouseY = 0
lifeTime = 0.5

end
 
function love.update(dt)
	tick = tick + dt
	if (tick > lifeTime) then	
		mainLoop()
	end
	
	function love.mousepressed(x, y)
			mouseX = x
			mouseY = y
	end
end

function mainLoop()

	for gridY = 1, gridMax do
	
		for gridX = 1, gridMax do 
			
			--check north
			if (map[gridX][gridY] == 1 and gridY > 1) then			
				if (map[gridX][gridY - 1] == 1) then
					count = count + 1
				end
			elseif (map[gridX][gridY] == 0 and gridY > 1) then			
				if (map[gridX][gridY - 1] == 1) then
					deadCount = deadCount + 1
				end
			end	
			--check east
			if (map[gridX][gridY] == 1 and gridX < gridMax) then			
				if (map[gridX + 1][gridY] == 1) then
					count = count + 1
				end
			elseif (map[gridX][gridY] == 0 and gridX < gridMax) then			
				if (map[gridX + 1][gridY] == 1) then
					deadCount = deadCount + 1
				end
			end
			--check south
			if (map[gridX][gridY] == 1 and gridY < gridMax) then			
				if (map[gridX][gridY + 1] == 1) then
					count = count + 1
				end
			elseif (map[gridX][gridY] == 0 and gridY < gridMax) then			
				if (map[gridX][gridY + 1] == 1) then
					deadCount = deadCount + 1
				end
			end	
			--check west
			if (map[gridX][gridY] == 1 and gridX > 1) then			
				if (map[gridX - 1][gridY] == 1) then
					count = count + 1
				end
			elseif (map[gridX][gridY] == 0 and gridX > 1) then			
				if (map[gridX - 1][gridY] == 1) then
					deadCount = deadCount + 1
				end
			end		
			--check ne
			if (map[gridX][gridY] == 1 and gridX < gridMax and gridY > 1) then			
				if (map[gridX + 1][gridY - 1] == 1) then
					count = count + 1
				end
			elseif (map[gridX][gridY] == 0 and gridX < gridMax and gridY > 1) then			
				if (map[gridX + 1][gridY - 1] == 1) then
					deadCount = deadCount + 1
				end
			end		
			--check se
			if (map[gridX][gridY] == 1 and gridX < gridMax and gridY < gridMax) then			
				if (map[gridX + 1][gridY + 1] == 1) then
					count = count + 1
				end
			elseif (map[gridX][gridY] == 0 and gridX < gridMax and gridY < gridMax) then			
				if (map[gridX + 1][gridY + 1] == 1) then
					deadCount = deadCount + 1
				end
			end		
			--check sw
			if (map[gridX][gridY] == 1 and gridX > 1 and gridY < gridMax) then			
				if (map[gridX - 1][gridY + 1] == 1) then
					count = count + 1
				end
			elseif (map[gridX][gridY] == 0 and gridX > 1 and gridY < gridMax) then			
				if (map[gridX - 1][gridY + 1] == 1) then
					deadCount = deadCount + 1
				end
			end			
			--check nw
			if (map[gridX][gridY] == 1 and gridX > 1 and gridY > 1) then			
				if (map[gridX - 1][gridY - 1] == 1) then
					count = count + 1
				end
			elseif (map[gridX][gridY] == 0 and gridX > 1 and gridY > 1) then			
				if (map[gridX - 1][gridY - 1] == 1) then
					deadCount = deadCount + 1
				end
			end
			
			--check if cell lives or dies			
			if(map[gridX][gridY] == 1 and count < 2) then
				tempmap[gridX][gridY] = 0
			elseif (map[gridX][gridY] == 1 and count <= 3 and count > 1) then
				tempmap[gridX][gridY] = 1
			elseif (map[gridX][gridY] == 1 and count > 3) then
				tempmap[gridX][gridY] = 0
			--check if dead cell reanimates			
			elseif (map[gridX][gridY] == 0 and deadCount == 3) then
				tempmap[gridX][gridY] = 1
			elseif (map[gridX][gridY] == 0 and deadCount ~= 3) then
				tempmap[gridX][gridY] = 0			
			end
			
			if (gridX >= gridMax and gridY < gridMax) then
				gridX = 1
				gridY = gridY + 1
				count = 0
				deadCount = 0
			elseif (gridX >= gridMax and gridY >= gridMax) then
				gridX = 1
				gridY = 1
				count = 0
				deadCount = 0
				map = deepCopy(tempmap)
				generation = generation + 1
				tick = 0
			else
				gridX = gridX + 1
				count = 0
				deadCount = 0
			end
		end			
	end
end


function love.draw()

	--draw map
	for y=1, #map do
		for x=1, #map[y] do
			if map[y][x] == 1 then
				love.graphics.setColor(20, 248, 242)
				love.graphics.rectangle("fill", x * 32, y * 32, 32, 32)
			else
				love.graphics.rectangle("line", x * 32, y * 32, 32, 32)
			end
		end
	end
	
	--draw infotext
	love.graphics.setColor(20, 248, 242)
	love.graphics.print("gridX " .. gridX, 700, 30)
	love.graphics.print("gridY " .. gridY, 700, 45)
	love.graphics.print("gridMax " .. gridMax, 700, 60)	
	love.graphics.print("generation " .. generation, 700, 75)	
	love.graphics.print("tick " .. tick, 700, 90)
	love.graphics.print("mouseX " .. mouseX, 700, 105)
	love.graphics.print("mouseY " .. mouseY, 700, 120)
	
end
 
function love.keypressed(key)
	if key == "escape" then
		love.event.quit()
	end	
end
 

Re: Conway's Game of Life, slow update

Posted: Tue Oct 10, 2017 10:38 am
by hamberge
Well you could take deepcopy and map outside of love.load. You don't really need to put function definitions or table definitions in there. Maybe take mousepressed out of update -- this is a callback that will be called whenever the mouse is clicked. Other than that it looks ok. I also don't think you need deepcopy -- I think you can just use nested for loops for your own copy. And you don't need the first deepcopy call in load because you will generate your first tempmap in the first iteration of update.