love-cellular-automata/life/main.lua

186 lines
3.7 KiB
Lua

require("util")
local function initRules(pattern)
local b, s = pattern:match("B(.+)/S(.+)")
B = {}
for c in b:gmatch(".") do
B[tonumber(c)] = true
end
S = {}
for c in s:gmatch(".") do
S[tonumber(c)] = true
end
end
local function initColors()
local colorbrewer = require("colorbrewer")
local scheme = colorbrewer.random(2)
ON = scheme[1]
OFF = scheme[2]
end
local function initScreen()
local width, height = love.graphics.getDimensions()
WIDTH, HEIGHT = round2even(width), round2even(height)
love.graphics.setBackgroundColor(OFF[1], OFF[2], OFF[3], 0.9)
end
local function initFont()
FONT = love.graphics.newFont(16)
love.graphics.setFont(FONT)
FPS_WIDTH = FONT:getWidth("120 FPS")
FPS_HEIGHT = FONT:getHeight()
end
local function initGrid()
GRID = {}
GRID.mt = {}
setmetatable(GRID, GRID.mt)
GRID.mt.__index = function(table, key)
table[key] = {}
return table[key]
end
end
local function cloneGrid()
local grid = {}
for x, v in pairs(GRID) do
grid[x] = {}
for y, set in pairs(v) do
grid[x][y] = set
end
end
setmetatable(grid, grid.mt)
return grid
end
local function drawGlider(x, y)
GRID[x][y] = true
x = x + UNITS
y = y + UNITS
GRID[x][y] = true
x = x + UNITS
GRID[x][y] = true
y = y - UNITS
GRID[x][y] = true
y = y - UNITS
GRID[x][y] = true
end
function love.load(args)
local pattern = args[1] or "B3/S23"
UNITS = args[2] or 8
STEPS_PER_FRAME = args[3] or 1
DRAGGING = false
initRules(pattern)
initColors()
initScreen()
initFont()
initGrid()
drawGlider(80, 80)
end
local function wrap(n, high)
n = n % high
if n < 0 then
n = n + high
end
return n
end
local function neighbors(x, y)
local lowX = x - UNITS
local highX = x + UNITS
local lowY = y - UNITS
local highY = y + UNITS
local count = 0
for i = lowX, highX do
for j = lowY, highY do
i = wrap(i, WIDTH)
j = wrap(j, HEIGHT)
if (i ~= x or j ~= y) and GRID[i][j] then
count = count + 1
end
end
end
return count
end
function love.mousepressed(x, y, button)
if button == 1 then
DRAGGING = true
elseif button == 2 then
x = (x - (x % UNITS))
y = (y - (y % UNITS))
drawGlider(x, y)
end
end
function love.mousereleased()
DRAGGING = false
end
function love.mousemoved(x, y)
if DRAGGING then
x = (x - (x % UNITS))
y = (y - (y % UNITS))
GRID[x][y] = true
end
end
FRAMELOCK_COUNTER = 0
FRAMELOCK_FPS = 30
function love.update(dt)
pcall(function()
require("lurker").update()
end)
FRAMELOCK_COUNTER = FRAMELOCK_COUNTER + dt
if FRAMELOCK_COUNTER < (1 / FRAMELOCK_FPS) then
return
end
FRAMELOCK_COUNTER = 0
for _ = 1, STEPS_PER_FRAME do
local grid = cloneGrid()
for x = 0, WIDTH, UNITS do
for y = 0, HEIGHT, UNITS do
local current = GRID[x][y]
local n = neighbors(x, y)
if current then
if not S[n] then
grid[x][y] = false
end
else
if B[n] then
grid[x][y] = true
end
end
end
end
GRID = grid
end
end
local function paintFPS()
local fps = tostring(love.timer.getFPS()) .. " FPS"
love.graphics.setColor(ON)
love.graphics.rectangle("fill", WIDTH - FPS_WIDTH - 10, HEIGHT - FPS_HEIGHT - 20, FPS_WIDTH + 30, FPS_HEIGHT + 10, 5, 5)
love.graphics.setColor(OFF)
love.graphics.print(fps, WIDTH - FPS_WIDTH - 5, HEIGHT - FPS_HEIGHT - 15)
end
function love.draw()
for x, v in pairs(GRID) do
if x ~= "mt" then
for y, on in pairs(v) do
if on then
love.graphics.setColor(ON)
else
love.graphics.setColor(OFF)
end
love.graphics.rectangle("fill", x, y, UNITS, UNITS)
end
end
end
paintFPS()
end