## Help with Conway's Game of Life

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Prole
Posts: 9
Joined: Thu Apr 17, 2014 10:17 pm

### Help with Conway's Game of Life

Hey LOVErs!

I've been trying to write Conway's Game of Life https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life in lua/love for the last couple days, and I've felt like I was making progress...
...today I was working on the logic of the game, and I do not understand why it's not working as intended! Instead of the cells evolving like they should, they are always moving to the left (while evolving, somehow)! I've been trying to decide if I should scrap what I've done so far, and try again with a clear mind and a blank canvas, but I would really appreciate it if someone would help me out, and tell me what is causing this strange occurrence...

Here is the code I have so far:

Code: Select all

math.randomseed (math.sqrt (os.time () * os.time ()))

cells = {}

cells.map = {}

cells.x = 80
cells.y = 60

cells.w = love.graphics.getWidth () / cells.x
cells.h = love.graphics.getHeight () / cells.y

for i = 1, cells.x do
cells.map[i] = {}

for j = 1, cells.y do
if math.random (2) == 1 then
cells.map[i][j] = 0
else
cells.map[i][j] = 1
end
end
end

cells.newMap = {}

for i = 1, cells.x do
cells.newMap[i] = {}
for j = 1, cells.y do
cells.newMap[i][j] = {}
end
end

function cells.getNeighbors (_cells_map, _i, _j)
cells_map = _cells_map

x = _i
y = _j

if x == 1 or y == 1 then
ul = 0
else
ul = cells_map[x-1][y-1]
end
if y == 1 then
uu = 0
else
uu = cells_map[x][y-1]
end
if x == cells.x or y == 1 then
ur = 0
else
ur = cells_map[x+1][y-1]
end
if x == 1 then
ll = 0
else
ll = cells_map[x-1][y]
end
if x == cells.x then
rr = 0
else
rr = cells_map[x+1][y]
end
if x == 1 or y == cells.y then
dl = 0
else
dl = cells_map[x-1][y+1]
end
if y == cells.y then
dd = 0
else
dd = cells_map[x][y+1]
end
if x == cells.x or y == cells.y then
dr = 0
else
dr = cells_map[x+1][y+1]
end

living = (
ul + uu + ur
+ ll + 0  + rr
+ dr + dd + dr
)
return living
end

function cells.update ()
for i = 1, cells.x do
for j = 1, cells.y do
cells.getNeighbors (cells.map, i, j)
if cells.map[i][j] == 1 then
if living == 0 or living == 1 then
cells.newMap[i][j] = 0
elseif living == 2 or living == 3 then
cells.newMap[i][j] = 1
elseif living > 3 and living < 9 then
cells.newMap[i][j] = 0
else
--cells.newMap[i][j] = 1
end
end
if cells.map[i][j] == 0 then
if living == 3 then
cells.newMap[i][j] = 1
else
cells.newMap[i][j] = 0
end
end
if i == cells.x and j == cells.y then
cells.map = cells.newMap
end
end
end
end

function cells.draw ()
for i = 1, cells.x do
for j = 1, cells.y do
if cells.map[i][j] == 0 then
love.graphics.rectangle ('line', ((cells.w * i) - cells.w), ((cells.h * j) - cells.h), cells.w, cells.h)
else
love.graphics.rectangle ('fill', ((cells.w * i) - cells.w), ((cells.h * j) - cells.h), cells.w, cells.h)
end
end
end
end

return cells

All main.lua does in this case is call the cells.update () and cells.draw () functions from cells.lua... Here is main.lua:

Code: Select all

local cells = require "cells"

end

function love.update (dt)
cells.update ()
end

function love.draw ()
cells.draw ()
--for i = 1, cells.x do
--  for j = 1, cells.y do
--    love.graphics.print (tostring (cells.map[i][j]), 0 + (10 * i) - 10, 0 + (10 * j) - 10)
--  end
--end
end

Anything obvious that I'm neglecting? Should I start over?

Thanks for taking the time to look at my work

ivan
Party member
Posts: 1606
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

### Re: Help with Conway's Game of Life

permadeth wrote:Anything obvious that I'm neglecting? Should I start over?
Hi and welcome to the forums.
One thing I would say is that, Conway's Game of Life is fairly abstract
so if you want to make a module for it, I would remove any Love2D functionality
from that module. This way, your 'cells' module would be pure Lua (with no dependencies).
Things like "cells.draw" and "love.graphics.getWidth" don't really belong in your abstract 'cells' module.
Separating the logic from the rendering will allow you to swap the front-end easily.

zorg
Party member
Posts: 2985
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

### Re: Help with Conway's Game of Life

Code: Select all

local living = (
ul + uu + ur
+ ll + 0  + rr
+ dr + dd + dr
)
and local living = here

Code: Select all

for i = 1, cells.x do
for j = 1, cells.y do
local living = cells.getNeighbors (cells.map, i, j)
Try that, see if it works or not
Me and my stuff True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.

ivan
Party member
Posts: 1606
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

### Re: Help with Conway's Game of Life

Code: Select all

function cells.getNeighbors (_cells_map, _i, _j)
cells_map = _cells_map

x = _i
y = _j

if x == 1 or y == 1 then
ul = 0
else
ul = cells_map[x-1][y-1]
end
if y == 1 then
uu = 0
else
uu = cells_map[x][y-1]
end
if x == cells.x or y == 1 then
ur = 0
else
ur = cells_map[x+1][y-1]
end
if x == 1 then
ll = 0
else
ll = cells_map[x-1][y]
end
if x == cells.x then
rr = 0
else
rr = cells_map[x+1][y]
end
if x == 1 or y == cells.y then
dl = 0
else
dl = cells_map[x-1][y+1]
end
if y == cells.y then
dd = 0
else
dd = cells_map[x][y+1]
end
if x == cells.x or y == cells.y then
dr = 0
else
dr = cells_map[x+1][y+1]
end

living = (
ul + uu + ur
+ ll + 0  + rr
+ dr + dd + dr
)
return living
end
This is a fun function to solve using iteration:

Code: Select all

-- 8 adjacent cells
local dirs = { {-1,-1}, {0,-1}, {1,-1}, {-1,0}, {1,0}, {-1,1}, {0,1}, {1,1} }

function cells.getNeighbors(map, i, j)
local v = 0
for _, dir in ipairs(dirs) do
local i2, j2 = i + dir[1], j + dir[2]
-- check if the neighbor is off the map
if i2 >= 1 and i2 <= cells.x then
if j2 >= 1 and j2 <= cells.y then
v = v + map[i2][j2]
end
end
end
return v
end

TheMeq
Citizen
Posts: 56
Joined: Fri Sep 02, 2011 9:56 pm
Location: Nottingham, UK

### Re: Help with Conway's Game of Life

You need to create a copy of the board and compare your next generation against that instead of against the current generation as your calculating it. That's why it's going over to the left

Prole
Posts: 9
Joined: Thu Apr 17, 2014 10:17 pm

### Re: Help with Conway's Game of Life

Thank you for all the helpful code and ideas ! I implemented the iterative getNeighbors function, and made the living variable local, as well as the advice of copying the board, before comparing. Right now it does some pretty insane (but kinda neat) things visually.

If anyone's curious, here's the current code:

Code: Select all

math.randomseed (os.time ())

cells = {}

cells.map = {}

cells.x = 80
cells.y = 60

cells.w = 800 / cells.x
cells.h = 600 / cells.y

for i = 1, cells.x do
cells.map[i] = {}

for j = 1, cells.y do
if math.random (10) == 1 then
cells.map[i][j] = 1
else
cells.map[i][j] = 0
end
end
end
end

local dirs = { {-1,-1}, {0,-1}, {1,-1}, {-1,0}, {1,0}, {-1,1}, {0,1}, {1,1} }

function cells.getNeighbors(map, i, j)
local v = 0
for _, dir in ipairs(dirs) do
local i2, j2 = i + dir[1], j + dir[2]
-- check if the neighbor is off the map
if i2 >= 1 and i2 <= cells.x then
if j2 >= 1 and j2 <= cells.y then
v = v + map[i2][j2]
end
end
end
return v
end
--TODO
--You need to create a copy of the board and compare your next generation against that instead of against the current generation as your calculating it. That's why it's going over to the left
function cells.update ()
cells.newMap = cells.map
cells.map = {}
for i = 1, cells.x do
cells.map[i] = {}
for j = 1, cells.y do
--cells.map[i][j] = {}

local living = cells.getNeighbors (cells.newMap, i, j)

if cells.newMap[i][j] == 1 then
if living <2 then
cells.map[i][j] = 0
elseif living == 2 or living == 3 then
cells.map[i][j] = 1
elseif living >3 then
cells.map[i][j] = 0
else
cells.newMap[i][j] = 1
end
elseif cells.newMap[i][j] == 0 then
if living == 3 then
cells.map[i][j] = 1
else
cells.map[i][j] = 0
end
end

end
end

--cells.map = cells.newMap
end

function cells.draw ()
for i = 1, cells.x do
for j = 1, cells.y do
if cells.map[i][j] == 0 then
love.graphics.rectangle ('line', ((cells.w * i) - cells.w), ((cells.h * j) - cells.h), cells.w, cells.h)
else
love.graphics.rectangle ('fill', ((cells.w * i) - cells.w), ((cells.h * j) - cells.h), cells.w, cells.h)
end
end
end
end

return cells


Note that I reduced the frequency in which any cell could potentially be 'alive', from 1/2, to 1/20. This value changes the results significantly, as you might imagine!

I also added a love.timer.sleep (.1) function in the love.update () loop in main.lua. This makes it easier to see what each stage in the evolution is.

This is the last version of the game. I hadn't cleared to original board (cells.map), so it made for some weird possibilities!) Here is a weird image of 4 games of life being played at once Sorry about the bad quality, but you can see in the image that 3 have become still, while one is still going strong, many minutes later! I goofed in the cells.update () function... Anyway, thanks a lot! If you have anything else to point out, I would be happy to get more feedback! Cheers

ivan
Party member
Posts: 1606
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

### Re: Help with Conway's Game of Life

Here a modified version of the game.
Changes:
1.the rules are implemented as a table

Code: Select all

-- rules table
local rules = {}
-- dead cells become alive if there are 3 live neighbors
rules[0] = { [0] = 0, 0, 0, 1, 0, 0, 0, 0, 0 }
-- live cells survive if there are 2 or 3 live neighbors
rules[1] = { [0] = 0, 0, 1, 1, 0, 0, 0, 0, 0 }
2.you can edit the map using the left/right mouse buttons
the simulation is paused while the mouse is down,
so you don't get a lot of control, but it's good for debugging

3.rendering is moved to main.lua and we don't use 'line' since it's slow
Attachments
cgl.love

Prole
Posts: 9
Joined: Thu Apr 17, 2014 10:17 pm

### Re: Help with Conway's Game of Life

ivan wrote:Here a modified version of the game.
Changes:
1.the rules are implemented as a table

Code: Select all

-- rules table
local rules = {}
-- dead cells become alive if there are 3 live neighbors
rules[0] = { [0] = 0, 0, 0, 1, 0, 0, 0, 0, 0 }
-- live cells survive if there are 2 or 3 live neighbors
rules[1] = { [0] = 0, 0, 1, 1, 0, 0, 0, 0, 0 }
2.you can edit the map using the left/right mouse buttons
the simulation is paused while the mouse is down,
so you don't get a lot of control, but it's good for debugging

3.rendering is moved to main.lua and we don't use 'line' since it's slow
That's brilliant! Thanks

I was tinkering with my own code and noticed that line was much much slower indeed.

### Who is online

Users browsing this forum: No registered users and 14 guests