From 1ffa545f6004d806bd4a7fdc251f3ee164123291 Mon Sep 17 00:00:00 2001 From: mat ess Date: Wed, 14 Sep 2022 23:05:05 -0400 Subject: [PATCH] Add wireworld! --- life/main.lua | 8 -- util.lua | 8 ++ wireworld/conf.lua | 5 + wireworld/main.lua | 222 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 235 insertions(+), 8 deletions(-) create mode 100644 wireworld/conf.lua create mode 100644 wireworld/main.lua diff --git a/life/main.lua b/life/main.lua index b71f2fe..b6aaea8 100644 --- a/life/main.lua +++ b/life/main.lua @@ -80,14 +80,6 @@ function love.load(args) 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 diff --git a/util.lua b/util.lua index 7141a30..561063a 100644 --- a/util.lua +++ b/util.lua @@ -21,3 +21,11 @@ end function round2even(num) return 2 * math.floor(num / 2) end + +function wrap(n, high) + n = n % high + if n < 0 then + n = n + high + end + return n +end diff --git a/wireworld/conf.lua b/wireworld/conf.lua new file mode 100644 index 0000000..1084f7d --- /dev/null +++ b/wireworld/conf.lua @@ -0,0 +1,5 @@ +function love.conf(t) + t.window.highdpi = true + t.window.vsync = true + t.window.title = "wireworld" +end diff --git a/wireworld/main.lua b/wireworld/main.lua new file mode 100644 index 0000000..8f74ed3 --- /dev/null +++ b/wireworld/main.lua @@ -0,0 +1,222 @@ +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