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) require("lurker").update() 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