Skip to content

Commit

Permalink
Add Grid.lua
Browse files Browse the repository at this point in the history
  • Loading branch information
hansonchar committed Jan 13, 2025
1 parent f660d06 commit ea6eebd
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 0 deletions.
42 changes: 42 additions & 0 deletions learning-lua/algo/Grid-tests.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
local grid = require "algo.Grid"

-- Tests west, north, east, south
local g = grid:new(10, 10)
local u = g:node(1, 1)
assert(not g:west(u))
assert(not g:north(u))
assert(g:east(u) == g:node(1, 2))
assert(g:east(u, 9) == g:node(1, 10))
assert(not g:east(u, 10))
assert(g:south(u) == g:node(2, 1))
assert(g:south(u, 9) == g:node(10, 1))
assert(not g:south(u, 10))

local u = g:node(10, 10)
assert(not g:east(u))
assert(not g:south(u))
assert(g:west(u) == g:node(10, 9))
assert(g:west(u, 9) == g:node(10, 1))
assert(not g:west(u, 10))
assert(g:north(u) == g:node(9, 10))
assert(g:north(u, 9) == g:node(1, 10))
assert(not g:north(u, 10))

-- Negative test with dy or dx is non-positive
local u = g:node(5, 5)
for _, f in ipairs {g.west, g.north, g.east, g.south} do
assert(pcall(f, g, u, 2))
assert(not pcall(f, g, u, 0))
assert(not pcall(f, g, u, -1))
end

-- Test Grid:node() and Grid:coord()
for y = 1, g.height do
for x = 1, g.width do
local node = g:node(y, x)
local y1, x1 = g:coord(node)
assert(x == x1 and y == y1)
end
end

os.exit()
43 changes: 43 additions & 0 deletions learning-lua/algo/Grid.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
local Grid = require "algo.GridBase"

function Grid:manhattan_dist(u, v)
local y1, x1 = self:coord(u)
local y2, x2 = self:coord(v)
return self:manhattan_dist_coord(y1, x1, y2, x2)
end

--- Returns a unique node number as a function of the given (y,x) coorindate
--- within the grid; or nil if (y, x) is outside the grid.
---@param y (number)
---@param x (number)
---@return (number) or nil
function Grid:node(y, x)
if y <= self.height and x <= self.width then
return (y << self._intern.wbits) + x
end
end

---Inverse of Grid:node(y, x)
---@param node (number)
---@return (number) y, (number) x
function Grid:coord(node)
return node >> self._intern.wbits, node & self._intern.wmask
end

function Grid:new(width, height)
assert(width > 0 and height > 0)
local g = {
width = width,
height = height
}
local wbits = math.ceil(math.log(width + 1, 2))
g._intern = {
wbits = wbits,
wmask = (1 << wbits) - 1
}
setmetatable(g, self)
self.__index = self
return g
end

return Grid
65 changes: 65 additions & 0 deletions learning-lua/algo/GridBase.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
local Grid = {}

local function move_y(grid, y, x, dy)
local y1 = y + dy
if y1 > 0 and y1 <= grid.height then
return grid:node(y1, x)
end
end

local function move_x(grid, y, x, dx)
local x1 = x + dx
if x1 > 0 and x1 <= grid.width then
return grid:node(y, x1)
end
end

function Grid:up(y, x, dy)
dy = dy or 1
assert(dy > 0)
return move_y(self, y, x, -dy)
end

function Grid:north(node, dy)
local y, x = self:coord(node)
return self:up(y, x, dy)
end

function Grid:down(y, x, dy)
dy = dy or 1
assert(dy > 0)
return move_y(self, y, x, dy)
end

function Grid:south(node, dy)
local y, x = self:coord(node)
return self:down(y, x, dy)
end

function Grid:left(y, x, dx)
dx = dx or 1
assert(dx > 0)
return move_x(self, y, x, -dx)
end

function Grid:west(node, dx)
local y, x = self:coord(node)
return self:left(y, x, dx)
end

function Grid:right(y, x, dx)
dx = dx or 1
assert(dx > 0)
return move_x(self, y, x, dx)
end

function Grid:east(node, dx)
local y, x = self:coord(node)
return self:right(y, x, dx)
end

function Grid:manhattan_dist_coord(y1, x1, y2, x2)
return math.abs(y1 - y2) + math.abs(x1 - x2)
end

return Grid

0 comments on commit ea6eebd

Please sign in to comment.