Skip to content

Instantly share code, notes, and snippets.

@michlbro
Created August 3, 2023 01:18
Show Gist options
  • Save michlbro/f16dec135c4232c3c4fac6e08f9d5a21 to your computer and use it in GitHub Desktop.
Save michlbro/f16dec135c4232c3c4fac6e08f9d5a21 to your computer and use it in GitHub Desktop.
Conway's Game Of Life.
--[[
Conway's Game Of Life.
Created by michlbro.
Mechanics:
1. Underpopulation: less than 2 neighbour cells.
2. Overpopulation: more than 3 neighbour cells.
3. Lives: 2 or 3 neighbour cells.
4. Reproduction: 3 neighbour cells.
Live cell table "origin" starts top left.
USAGE:
```lua
local conway = require(ConwayModule).new() -- conway object
conway:SpawnCell(1, 2) -- (x, y)
print(conway:GetCell(1, 2)) -- "{x, y}" or nil (if cell is dead)
conway:KillCell(1, 2)
conway:Step() -- Next generation.
conway:Clear()
conway:Destroy()
```
API:
```lua
-- Creates a new conway class
Conway.new() -> conway
-- Spawns a new cell at a given x, y coordinates.
conway:SpawnCell(x: number, y: number) -> nil
-- Kills a cell at given a x, y coordinates.
conway:KillCell(x: number, y: number) -> nil
-- Gets a cells index in an array of live cells at a given x, y coordinates.
conway:GetCell(x: number, y: number) -> number?
-- Returns the array of live cells.
conway:GetLiveCells() -> {
[number]: {x: number, y: number}
}
-- Progresses conways game to next generation.
conway:Step() -> nil
-- Removes all live cells.
conway:Clear() -> nil
-- Destroys conways class.
conway:Destroy() -> nil
```
]]
local Conway = {}
local function CheckCellExistance(liveCells, x, y)
for index, cell in pairs(liveCells) do
if cell[1] == x and cell[2] == y then
return index
end
end
return nil
end
function Conway:SpawnCell(x: number, y: number)
if not CheckCellExistance(self.liveCells, x, y) then
table.insert(self.liveCells, {x,y})
end
end
function Conway:KillCell(x: number, y: number)
local index = CheckCellExistance(self.liveCells, x, y)
if index then
table.remove(self.liveCells, index)
end
end
function Conway:GetLiveCells()
return self.liveCells
end
function Conway:GetCell(x: number, y: number): number?
local index = CheckCellExistance(self.liveCells, x, y)
if index then
return index
end
return nil
end
function Conway:Clear()
table.clear(self.liveCells)
end
function Conway:Destroy()
table.clear(self.liveCells)
self.liveCells = nil
self = nil
end
function Conway:Step()
--[[
Instructions:
- Live cell surround table starts top left to bottom right
o (1) For loop through liveCells and create a temporary table with 1 cell radius around them.
- For liveCells tag them in the temporary table
o For loop through temporary table and do neighbour checks.
- For tagged cells, if dead, remove them from liveCells
]]
local liveCells = table.clone(self.liveCells)
-- Create surrounding cell map (1)
local cellMap = {}
for index, cell in liveCells do
local x, y = cell[1], cell[2]
if not cellMap[x] then
cellMap[x] = {}
end
-- add liveCell and tag it
cellMap[x][y] = {true, index} -- {state, previouslyAliveIndex?}
-- add surrounding cell
for xPos = x - 1, x + 1 do
for yPos = y - 1, y + 1 do
-- skip the liveCell
if xPos == x and yPos == y then
continue
end
if not cellMap[xPos] then
cellMap[xPos] = {}
end
cellMap[xPos][yPos] = cellMap[xPos][yPos] or {false}
end
end
end
-- Check neighbour cells and determine cell state (2)
for x, yCol in pairs(cellMap) do
for y, cell in pairs(yCol) do
local _, previouslyAliveIndex = cell[1], cell[2]
local neighbours = 0
for xPos = x - 1, x + 1 do
if not cellMap[xPos] then
continue
end
for yPos = y - 1, y + 1 do
-- skip the liveCell
if xPos == x and yPos == y then
continue
end
if not cellMap[yPos] then
continue
end
neighbours += cellMap[xPos][yPos][1] and 1 or 0
end
end
local result = false
if neighbours == 2 or neighbours == 3 then
result = true
end
if result and not previouslyAliveIndex then
table.insert(self.liveCells, {x, y})
elseif not result and previouslyAliveIndex then
table.remove(self.liveCells, previouslyAliveIndex)
end
end
end
end
local function new()
local self = {}
-- liveCells: { {x,y} }
self.liveCells = {}
setmetatable(self, {
__index = Conway
})
return self
end
return table.freeze(setmetatable({
new = new
}, {
__index = Conway
}))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment