love-cellular-automata/ants/main.lua

186 lines
4.0 KiB
Lua

-- 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 c = COLORS[1].rgba
love.graphics.setColor({ c[1], c[2], c[3], 0.9 })
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()
pcall(function()
require("lurker").update()
end)
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