Skip to content

Instantly share code, notes, and snippets.

@weswigham
Created July 2, 2013 23:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save weswigham/5914243 to your computer and use it in GitHub Desktop.
Save weswigham/5914243 to your computer and use it in GitHub Desktop.
O(1) Matrix Rotation. I think.
local rawget = rawget
local rawset = rawset
local setmetatable = setmetatable
local tostring = tostring
local error = error
local type = type
local print = print
module("matrix")
local InternalMeta = {}
function InternalMeta:__index(key)
if type(key) ~= "number" then return rawget(self.matrix[self.selection], key) end
local mat = self.matrix
local x,y = self.selection, key
return mat(x, y)
end
function InternalMeta:__newindex(key, val)
if type(key) ~= "number" then rawset(self.matrix[self.selection], key, val) end
local mat = self.matrix
local x,y = self.selection, key
return mat(x, y, val)
end
local Matrix = {}
function Matrix:__index(key)
if type(key) ~= "number" then return (rawget(self, key) or Matrix[key]) end
local metahack = {}
metahack.selection = key
metahack.matrix = self
return setmetatable(metahack, InternalMeta)
end
function Matrix:__call(x, y, ...)
if x<=0 or y<=0 or x>self.size or y>self.size then error("Matrix index out of bounds") end
local val = {...} --Just some trickery to make it so you can put multiple things in the same position in the matrix
if val and #val == 0 then val = nil end
if val and #val == 1 then val = val[1] end
if val then --Set
if self.rotation==0 then --Read normally
self.internal[x][y] = val
elseif self.rotation==1 then --Rotated once to the right
self.internal[self.size-y+1][x] = val
elseif self.rotation==2 then --Rotated 180 degrees from original
self.internal[self.size-x+1][self.size-y+1] = val
elseif self.rotation==3 then --Rotated once to the left
self.internal[y][self.size-x+1] = val
else
error("Matrix has an invalid rotation number")
end
else --Get
if self.rotation==0 then --Read normally
return self.internal[x][y]
elseif self.rotation==1 then --Rotated once to the right
return self.internal[self.size-y+1][x]
elseif self.rotation==2 then --Rotated 180 degrees from original
return self.internal[self.size-x+1][self.size-y+1]
elseif self.rotation==3 then --Rotated once to the left
return self.internal[y][self.size-x+1]
else
error("Matrix has an invalid rotation number")
end
end
end
function Matrix:Zero(size)
if size<1 then error("A Matrix was zeroed to a size of 0 or less.") end
self.rotation = 0
self.size = size or self.size
self.internal = {}
for i=1,size do
local row = {}
for j=1,size do
row[j] = 0
end
self.internal[i] = row
end
end
function Matrix:__tostring()
local ret = ""
for i=1,self.size do
for j=1,self.size do
ret = ret.."["..tostring(self(i, j)).."]"
end
ret = ret.."\n"
end
return ret
end
function Matrix:RotateLeft()
self.rotation = (self.rotation-1)%4
end
function Matrix:RotateRight()
self.rotation = (self.rotation+1)%4
end
return function(size)
local m = {}
m = setmetatable(m, Matrix)
m:Zero(size or 1)
return m
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment