l-system/main.lua

local lfs = require "lfs"

local name
local iter

love.graphics.setDefaultFilter "nearest"

local leaves = love.graphics.newImage "leaves.png"
local flower = love.graphics.newImage "flower.png"

local plant
local rules = {
	{"X", ".>^[>^X]<X", chance = 0.10},
	{"X", ".<^[<^X]>X", chance = 0.10},
	{"X", "^^^.[<X][>X]", chance = 0.10},
	{"X", "F", chance = 0.05},
	{"^%^", "^@", chance = 0.01},
}
local rendered

local function apply(system, rules)
	for _, rule in ipairs(rules) do
		system = system:gsub(rule[1], function(s)
			if love.math.random() <= rule.chance then
				return rule[2]
			else
				return s
			end
		end)
	end
	return system
end

local function draw(system)
	love.graphics.translate(0, 1080)
	love.graphics.rotate(-90)
	love.graphics.scale(0.5)
	for i = 1, #system do
		local c = system:sub(i, i)
		if c == "[" then
			love.graphics.push()
		elseif c == "]" then
			love.graphics.pop()
		elseif c == "." then
			love.graphics.scale(0.95)
		elseif c == "@" then
			love.graphics.scale(1.10)
		elseif c == "^" then
			love.graphics.setColor(0.4, 0.8, 0.4)
			love.graphics.line(0, 0, 0, 80)
			love.graphics.translate(0, 80)
		elseif c == "<" then
			love.graphics.rotate(math.rad(25))
		elseif c == ">" then
			love.graphics.rotate(-math.rad(25))
		elseif c == "X" then
			love.graphics.push()
			love.graphics.setColor(1, 1, 1)
			love.graphics.scale(2)
			love.graphics.translate(25, 25)
			love.graphics.rotate(math.rad(180))
			love.graphics.draw(leaves)
			love.graphics.pop()
		elseif c == "F" then
			love.graphics.push()
			love.graphics.setColor(1, 1, 1)
			love.graphics.scale(2)
			love.graphics.translate(-25, -25)
			love.graphics.draw(flower)
			love.graphics.pop()
		end
	end
	love.graphics.setColor(1, 1, 1)
end

function love.load()
	lfs.mkdir("rendered/")
	name = "rendered/" .. tostring(math.random(100000))
	lfs.mkdir(name)
	iter = 0
	love.graphics.setLineWidth(5)
	plant = "^>^.X"
end

function love.keypressed()
	love.load()
end

local function update_plant()
	local changed
	if #plant < 4000 then
		plant = apply(plant, rules)
		changed = true
	end

	rendered = love.graphics.newCanvas(1000, 1080)
	love.graphics.setCanvas(rendered)
	draw(plant)
	love.graphics.setCanvas()

	if changed then
		local idata = rendered:newImageData()
		local f = io.open(name.."/"..tostring(iter)..".png", "w")
		f:write(idata:encode("png"):getString())
		f:close()
		iter = iter + 1
	end
end

local rate = 0.05
local accum = rate
function love.update(dt)
	accum = accum + dt
	if accum >= rate then
		update_plant()
		accum = accum - rate
	end
end

function love.draw()
	love.graphics.setColor(1, 1, 1)
	love.graphics.rectangle("fill", 0, 0, love.graphics.getDimensions())
	if rendered then
		love.graphics.draw(rendered)
	end
end