--
-- Lua mutable playfield. Extracted from Beturing sources
-- and converted to a more conventional Lua OO style.
--
-- SPDX-FileCopyrightText: Chris Pressey, the original author of this work, has dedicated it to the public domain.
-- For more information, please refer to <https://unlicense.org/>
-- SPDX-License-Identifier: Unlicense
--
-- to use: ensure LUA_PATH has "thisdir/?.lua", then
--
-- local Playfield = require "playfield.lua"
-- p = Playfield.new()
--
-- to run demo standalone:
--
-- lua -i playfield.lua
-- Playfield_demo()
--
local Playfield = {}
--
-- Private function: pick the appropriate quadrant & translate
--
local pick_quadrant = function(self, x, y)
if x > 0 and y > 0 then return self.se, x, y end
if x > 0 and y <= 0 then return self.ne, x, 1-y end
if x <= 0 and y > 0 then return self.sw, 1-x, y end
if x <= 0 and y <= 0 then return self.nw, 1-x, 1-y end
end
--
-- Read the symbol at a given position in the playfield
--
function Playfield:peek(x, y)
local contents, nx, ny = pick_quadrant(self, x, y)
contents[ny] = contents[ny] or {} -- make sure row exists
local sym = contents[ny][nx] or " "
return sym
end
--
-- Write a symbol at a given position in the playfield
--
function Playfield:poke(x, y, sym)
local contents, nx, ny = pick_quadrant(self, x, y)
contents[ny] = contents[ny] or {} -- make sure row exists
contents[ny][nx] = sym
if not self.min_x or x < self.min_x then self.min_x = x end
if not self.max_x or x > self.max_x then self.max_x = x end
if not self.min_y or y < self.min_y then self.min_y = y end
if not self.max_y or y > self.max_y then self.max_y = y end
end
--
-- Return a string representing the playfield.
--
function Playfield:render(start_x, start_y, end_x, end_y)
start_x = start_x or self.min_x
start_y = start_y or self.min_y
end_x = end_x or self.max_x
end_y = end_y or self.max_y
local y = start_y
local s = ""
while y <= end_y do
local x = start_x
while x <= end_x do
s = s .. self:peek(x, y)
x = x + 1
end
s = s .. "\n"
y = y + 1
end
return s
end
local function Playfield_new()
local self = {
nw = {},
ne = {},
sw = {},
se = {},
min_x = nil,
min_y = nil,
max_x = nil,
max_y = nil
}
setmetatable(self, {__index = Playfield})
return self
end
Playfield_demo = function()
p = Playfield_new()
p:poke(0, 0, "*")
p:poke(1, 0, "/")
p:poke(1, 1, ">")
p:poke(0, 1, "v")
print(p:render())
end
return { new = Playfield_new }