-- based on -- https://healeycodes.com/virtual-ants -- https://github.com/healeYcodes/virtual-ants/blob/main/index.html require("util") local function rotate(direction, clockwise) local match if clockwise then match = { u = "r", r = "d", d = "l", l = "u", } else match = { u = "l", l = "d", d = "r", r = "u" } end return match[direction] end local function initColors(rules) rules = rules:lower() local colorbrewer = require("colorbrewer") local scheme = colorbrewer.random(#rules) COLORS = {} for i, color in pairs(scheme) do COLORS[i] = { clockwise = rules:sub(i, i) == "r", rgba = color } end end local function initScreen() local width, height = love.graphics.getDimensions() WIDTH, HEIGHT = round2even(width), round2even(height) CANVAS = love.graphics.newCanvas(WIDTH, HEIGHT) CANVAS:renderTo(function() local color = COLORS[1].rgba color[4] = 0.9 love.graphics.setColor(color) love.graphics.rectangle("fill", 0, 0, WIDTH, HEIGHT) end) 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 spawnAnt(x, y) table.insert(ANTS, { x = x, y = y, direction = "u" }) end local function spawnAntCentered() spawnAnt( (WIDTH / 2) - ((WIDTH / 2) % UNITS), (HEIGHT / 2) - ((HEIGHT / 2) % UNITS) ) end local function initAnts() ANTS = {} spawnAntCentered() 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 function love.load(args) local rules = args[1] or "RL" UNITS = args[2] or 4 STEPS_PER_FRAME = args[3] or 5 initColors(rules) initScreen() initFont() initAnts() initGrid() end local function antColor(ant) return GRID[ant.x][ant.y] end local function setColor(ant, color) GRID[ant.x][ant.y] = color end local function updateColor(ant) local val = antColor(ant) if val == #COLORS then val = 1 else val = val + 1 end setColor(ant, val) end local function nextColor(ant) local c = COLORS[antColor(ant)] updateColor(ant) return c end function love.mousepressed(x, y) spawnAnt(x, y) end function love.update() require("lurker").update() for _ = 1, STEPS_PER_FRAME do for i, ant in pairs(ANTS) do local c = nextColor(ant) ant.direction = rotate(ant.direction, c.clockwise) CANVAS:renderTo(function() love.graphics.setBlendMode("alpha") love.graphics.setColor(c.rgba) love.graphics.rectangle("fill", ant.x, ant.y, UNITS, UNITS) end) if ant.direction == "u" then ant.y = ant.y - UNITS elseif ant.direction == "r" then ant.x = ant.x + UNITS elseif ant.direction == "d" then ant.y = ant.y + UNITS else ant.x = ant.x - UNITS end if ant.x >= WIDTH then ant.x = 0 elseif ant.x < 0 then ant.x = (WIDTH - 1) - ((WIDTH - 1) % UNITS) end if ant.y >= HEIGHT then ant.y = 0 elseif ant.y < 0 then ant.y = (HEIGHT - 1) - ((HEIGHT - 1) % UNITS) end ANTS[i] = ant end end end local function paintFPS() love.graphics.setBlendMode("alpha") local fps = tostring(love.timer.getFPS()) .. " FPS" love.graphics.setColor(COLORS[1].rgba) love.graphics.rectangle("fill", WIDTH - FPS_WIDTH - 10, HEIGHT - FPS_HEIGHT - 20, FPS_WIDTH + 30, FPS_HEIGHT + 10, 5, 5) love.graphics.setColor(COLORS[#COLORS].rgba) love.graphics.print(fps, WIDTH - FPS_WIDTH - 5, HEIGHT - FPS_HEIGHT - 15) end function love.draw() love.graphics.setBlendMode("alpha", "premultiplied") love.graphics.setColor(COLORS[1].rgba) love.graphics.draw(CANVAS, 0, 0) paintFPS() end