local function set(self, r, c, v) if r < self.top or r > self.bottom or c < self.left or c > self.right then error(string.format("index (%d %d) out of bounds (%d..%d %d..%d)", r, c, self.top, self.bottom, self.left, self.right)) end self.grid[r * self.width + c] = v end local function get(self, r, c) if r < self.top or r > self.bottom or c < self.left or c > self.right then if self.default then return self.default else error(string.format("index (%d %d) out of bounds (%d..%d %d..%d)", r, c, self.top, self.bottom, self.left, self.right)) end end local item = self.grid[r * self.width + c] if item == nil and self.default then return self.default else return item end end local function iter(self, r, c, h, w) if r == nil then r = self.top end if c == nil then c = self.left end if h == nil then h = self.height end if w == nil then w = self.width end local r0, c0 = r, c return function() if r0 > r + h - 1 then return nil end local rb, cb = r0, c0 c0 = c0 + 1 if c0 > c + w - 1 then c0 = c r0 = r0 + 1 end return self:get(rb, cb), rb, cb end end local function neigh9(self, r, c, exclude) local iter = self:iter(r - 1, c - 1, 3, 3) return function() local i, ri, ci = iter() if exclude and ri == r and ci == c then local i, ri, ci = iter() end return i, ri, ci end end local function write(self, format) if not format then format = function(i) return string.format("%3s", i) end end for r = self.top, self.bottom do for c = self.left, self.right do io.write(format(self:get(r, c))) end io.write("\n") end end local function grow(self) self.height = self.height + 1 self.bottom = self.bottom + 1 end function grid(top, left, width, height, default) return { top = top, left = left, height = height, width = width, bottom = top + height - 1, right = left + width - 1, default = default, grid = {}, get = get, set = set, iter = iter, neigh9 = neigh9, write = write, grow = grow, } end