require "util" local function initColors() local colorbrewer = require("colorbrewer") COLORS = colorbrewer.random(4) BLACK = { 0, 0, 0, 1 } end local function initScreen() local width, height = love.graphics.getDimensions() WIDTH, HEIGHT = round2even(width), round2even(height) local color = COLORS[#COLORS] color[4] = 0.9 love.graphics.setBackgroundColor(color) end local function initFont() FONT = love.graphics.newFont(16) love.graphics.setFont(FONT) FONT_HEIGHT = FONT:getHeight() PLAYING_WIDTH = FONT:getWidth("playing") PAUSED_WIDTH = FONT:getWidth("paused") end local function initGrid() GRID = {} GRID.mt = {} setmetatable(GRID, GRID.mt) GRID.mt.__index = function(table, key) table[key] = {} table[key].mt = {} setmetatable(table[key], table[key].mt) table[key].mt.__index = function(innerTable, innerKey) innerTable[innerKey] = 1 return innerTable[innerKey] end 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 setmetatable(grid[x], grid[x].mt) end setmetatable(grid, grid.mt) return grid end function love.load(args) UNITS = args[1] or 16 STEPS_PER_FRAME = args[2] or 1 PAUSED = false initColors() initScreen() initFont() initGrid() 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] == 2 then count = count + 1 end end end return count end local function clear(grid, x, y) grid[x][y] = 1 end local function setHead(grid, x, y) grid[x][y] = 2 end local function setTail(grid, x, y) grid[x][y] = 3 end local function setConductor(grid, x, y) grid[x][y] = 4 end local function setSpark(grid, x, y) local n = neighbors(x, y) if n == 1 or n == 2 then setHead(grid, x, y) end end local function updater(state) local match = { -- noop [1] = function(x, y) end, [2] = setTail, [3] = setConductor, [4] = setSpark, } return match[state] end local function stepCell(grid, x, y) local state = GRID[x][y] local update = updater(state) update(grid, x, y) end function love.keypressed(key, _, isrepeat) if key == "space" and not isrepeat then PAUSED = not PAUSED if PAUSED then print("pausing") else print("unpausing") end end end function love.mousepressed(x, y, button) x = (x - (x % UNITS)) y = (y - (y % UNITS)) local state = GRID[x][y] if button == 1 then if state == 1 then print("setting conductor") setConductor(GRID, x, y) else print("clearing") clear(GRID, x, y) end elseif button == 2 then if state == 4 then print("setting head") setHead(GRID, x, y) elseif state == 2 then print("setting conductor") setConductor(GRID, x, y) end end end FRAMELOCK_COUNTER = 0 FRAMELOCK_FPS = 10 function love.update(dt) pcall(function() require("lurker").update() end) if not PAUSED then FRAMELOCK_COUNTER = FRAMELOCK_COUNTER + dt if FRAMELOCK_COUNTER < (1 / FRAMELOCK_FPS) then return end FRAMELOCK_COUNTER = 0 local grid = cloneGrid() for x = 0, WIDTH, UNITS do for y = 0, HEIGHT, UNITS do local state = GRID[x][y] if state ~= 1 then stepCell(grid, x, y) end end end GRID = grid end end local function paintPlayPause() local status, width if PAUSED then status, width = "paused", PAUSED_WIDTH else status, width = "playing", PLAYING_WIDTH end love.graphics.setColor(COLORS[1]) love.graphics.rectangle("fill", -10, HEIGHT - FONT_HEIGHT - 20, width + 30, FONT_HEIGHT + 10, 5, 5) love.graphics.setColor(BLACK) love.graphics.print(status, 10, HEIGHT - FONT_HEIGHT - 15) end local function paintFPS() local fps = tostring(love.timer.getFPS()) .. " FPS" local width = FONT:getWidth(fps) love.graphics.setColor(COLORS[1]) love.graphics.rectangle("fill", WIDTH - width - 10, HEIGHT - FONT_HEIGHT - 20, width + 30, FONT_HEIGHT + 10, 5, 5) love.graphics.setColor(BLACK) love.graphics.print(fps, WIDTH - width - 5, HEIGHT - FONT_HEIGHT - 15) end function love.draw() for x, v in pairs(GRID) do if x ~= "mt" then for y, state in pairs(v) do if y ~= "mt" then local color = COLORS[#COLORS - state + 1] love.graphics.setColor(color) love.graphics.rectangle("fill", x, y, UNITS, UNITS) if state ~= 1 then love.graphics.setColor(BLACK) love.graphics.rectangle("line", x, y, UNITS, UNITS) end end end end end paintFPS() paintPlayPause() end