Coding Challenge #5: Rotating 90-degrees

Coding Challenge #5

Welcome back, to another coding challenge! Let’s do this as usual.

As usual, same requirements:

  • Has to be written in Lua 5.1 (the version roblox uses)
  • The program has to be compatible with Roblox Studio, meaning you can’t use features vanilla Lua has but rbxlua disabled
  • You can’t use httpservice to cheat the challenge

Given a 2D table, write a function Rotate(t) which will rotate the table 90 degrees.

Let’s see what I mean. This is a 2D table, which some other people would like to call a matrix.

{{1,2,3},
 {4,5,6},
 {7,8,9}}

You need to rotate it 90 degrees, which in linear algebra is a matrix operation known as transposing (although transposing is actually rotating 90 degrees clockwise and not anti-clockwise) what emily said.
codingchallenge1-5

{{7,4,1},
 {8,5,2},
 {9,6,3}}

If you want to check if your code is working by printing the output, here is a function which will print the 2D table for you.

local function Print(t)
  for i, v in pairs(t) do
    print(unpack(v))
    print("")
  end
end

Goodluck! You can find a list of all the challenges here or a github version here.
Capture

Answer!

Here is my solution! I have a great feeling everybody gonna have the same setup.

local function Rotate(t)
  local output = {{}, {}, {}}

  for i, row in pairs(t) do
    for j = 1,3 do
      output[j][4-i] = row[j]
    end
  end

  return output
end
14 Likes

So cool and simple! Thank you for the quick challenge.

1 Like

That was pretty simple, matrices rotation isn’t the hardest thing in the world to do. just some simple math

Now time to extend my code to work with any square because that’s looks possible

My solution if anyone wants to know :3

function rotate90(tab)
	local out = {{},{},{}}
	
	for yIndex, x in pairs(tab) do
		for y = 1, 3 do
			out[y][4-yIndex] = x[y]
		end
	end
	
	return out
end
4 Likes

I did two approaches, since this was another relatively simple problem. Here’s the lazy approach:

code
function Rotate(t)
	local rotatedT = {}
	
	for i = 1, 3 do
		rotatedT[i] = {t[3][i], t[2][i], t[1][i]}
	end
	
	return rotatedT
end

And I’ll edit in a more flexible one that lets you input a number of degrees, soon.

Edit: It’s a bit messy, but here it is. Blame @starmaq for recommending I use ternary instead of a more readable if-else chain.

code
function Rotate(t, deg)
	deg = deg or 90 -- default of 90 so it fits specs of challenge
	
	if type(t) ~= "table" or type(deg) ~= "number" then
		error("Typing must be `Rotate(table, number)`")
	end
	
	assert(deg % 90 == 0, "argument #2 must be divisible by 90")
	
	local rotatedT = {{}, {}, {}}
	deg = deg and (math.sign(deg) > 0 and deg or deg + 360) -- allow negative degrees
	
	-- the actual function part:
	local d = (deg / 90) % 4
	
	for x = 1, 3 do
		for y = 1, 3 do
			rotatedT[x][y] = t[(d % 3 > 0 and 4 or 2 * (d % 2 == 1 and y or x)) - (d % 2 == 1 and y or x)][(d > 1 and 4 or 2 * (d % 2 == 1 and x or y)) - (d % 2 == 1 and x or y)]
		end
	end
	
	return rotatedT
end
3 Likes

Here’s my take at it

function Rotate(t)
  local t2 = { {},{},{}}

   for i,v in pairs(t) do 
     for k = 1,3,1 do 
           table.insert(t2[i],4-k,t[k][i])
      end
  end

  return t2
end
1 Like

I’ve never done matrix math before but this was my take on it, I couldn’t figure out how to rotate it clockwise :sob: so if anybody can make adjustments to my code so I can see how it should be done that’d be much appreciated

local function rotateMatrix90(arr)
    local matrix_tbl
    -- if we haven't provided a matrix then use the example from the tutorial
    if arr then
        matrix_tbl = arr
    else
        matrix_tbl = {
            {1,2,3}, 
            {4,5,6}, 
            {7,8,9}
        }   
    end
    
   -- creates a new matrix
    local new_matrix = {}
  -- for every column in the matrix provided we create a new column in our new matrix
    for i = 1, #matrix_tbl do
        new_matrix[i] = {}
   -- iterate through the provided matrix and find the elements that correspond to the current
   -- column we're in
        for index, arr in pairs(matrix_tbl) do
  -- insert these elements in the column of our new matrix
            table.insert(new_matrix[i], #new_matrix[i] + 1, arr[i])
        end
    end
    
    --For displaying the ordered matrix in console
    for all, som in pairs(new_matrix) do
        local rows = "{"
        for _, column in pairs(som) do
            rows = rows..","..column
        end
        rows = rows.."}".."\n"
        print(rows)
    end
end

rotateMatrix90()
2 Likes

I know that this isn’t inherent with the challenge, but after completing it I felt like it wasn’t enough, and I’ve decided to make a 180 degrees rotation function, and here is the result (put a spoiler just in case you want to figure it out by yourself):


local function rotate180(t)
	local output = {{},{},{}}

    for i, Table in pairs(t) do
	    for i = 1,3 do
	       for i2 = 3,1,-1 do
	          output[i][i2] = M[4-i][4-i2]
	       end
	    end
	end
		
   return output
end

1 Like
The redundant and messy way
   local function Rotate(t)


   local temp = {

   {};
   {};
   {};

   };

    
   assert(typeof(t) == "table","tables only please!")
 

   temp[1][1] = t[3][1]
   temp[1][2] = t[2][1]
   temp[1][3] = t[1][1]
   
   temp[2][1] = t[3][2]
   temp[2][2] = t[2][2]
   temp[2][3] = t[1][2]

   temp[3][1] = t[3][3]
   temp[3][2] = t[2][3]
   temp[3][3] = t[1][3]


 
    
   return temp

   end

 
      for _, v in ipairs(Rotate(
      {{1,2,3}, {4,5,6}, {7,8,9}})) do
     print(unpack(v)) 
 end

What I was originally going to do was taken by Posatta in his first one.

Works only as a solution to the current problem.

1 Like

Hay so I did the n-degrees rotation bonus challenge as well! I basically used the fact that rotating 180 matrix is the same as rotating 90 degrees,then rotating 90 degrees again, and called the function recursively. To omit deepcopying I just made the rotating part a function on its own.

local function Rotate(t, r)
  assert(r%90==0, "rotation must be multiple of 90")
  
  local function rotate(t,r)
    local t = t
    if r ~= 90 then 
      t = rotate(t, r-90)
    end
    local output = {{}, {}, {}}
    for x, v1 in pairs(t) do
      for y, v2 in pairs(v1) do
        output[y][4-x] = v2
      end
    end
    return output
  end 
  

  return rotate(t, r)
end
2 Likes

Matrix transposition is not a 90-degree rotation of the matrix in either direction, except by coincidence for matrices with specific symmetry. The transpose of:

{{1, 2, 3},
 {4, 5, 6},
 {7, 8, 9}}

is

{{1, 4, 7},
  2, 5, 8},
  3, 6, 9}}

P.S. I think Syharaa’s is the only solution that actually solves the general question asked, rather than being hard-coded to only work for a 3-row or 3-column matrix. I think if he just changed one pairs to ipairs it would be guaranteed to preserve order in any compliant Lua VM too. IIRC using pairs technically allows for an interpreter to iterate the array part of the table in any order while still being compliant to the Lua standard, right? In practice, I think most–if not all–will still iterate in index order.

2 Likes

Most of the solutions here only solve for the case you have given and not an n×n matrix.

Anyway, here is my solution:

local function col(t)
	local i, h = 0, #t
	return function ()
		i = i + 1
		local column = {}
		for j = 1, h do
			local val = t[j][i]
			if not val then return end
			column[j] = val
		end
		return i, column
	end
end

local function rev(t)
	local n = #t
	for i = 1, math.floor(n / 2) do
		local j = n - i + 1
		t[i], t[j] = t[j], t[i]
	end
	return t
end

local function rotateCW(t)
	local t2 = {}
	for i, column in col(t) do
		t2[i] = rev(column)
	end
	return t2
end

local function rotateCCW(t)
	local t2 = {}
	for i, column in col(t) do
		t2[i] = column
	end
	return rev(t2)
end

There are certainly simpler solutions, I just thought it might be fun to use iterators for this. col returns a function which allows the table to be iterated as columns rather than rows. rev is used to reverse a table.

3 Likes

Thank you for the feedback! I was wondering what you exactly meant by pairs iterating over the array part with any order, but still respect lua’s standards. Does that mean it can iterate through indices in the logical numerical order but still obey lua’s rules?

From the Lua FAQ:

pairs(t) gives a general iterator over all the keys and values in a table, numerical or not, in no particular order; ipairs(t) goes over the array part, in order.

What this means is that if you want to write code for this challenge that will work in any Lua runtime with a standards-compliant implementation, you need to use the ipairs() iterator to rotate a matrix that is stored in the array parts of Lua tables, otherwise the columns of your supposed-to-be-rotated matrix could end up shuffled arbitrarily.

ipairs() must iterate over the array part of the Lua table in numerical order of the indices. pairs() need only iterate over all of the keys (array indices and dictionary keys), but it’s free to do so in any order the implementor pleases.

In practice, most (if not all) Lua interpreters probably implement pairs() to iterate over the array part using [almost] the same code as ipairs(), because why would you want to intentionally write that code twice or intentionally iterate over an ordered array randomly? It’s just not technically guaranteed by the standard.

1 Like

I did it!!!

local gg = {{1,2,3},
{4,5,6},
{7,8,9}}

local t = {{},
{},
{}}

function rotate(t)
for a,b in pairs(gg) do
local e , f , g = unpack(b)

local v1 = table.insert(t[1], e)
local v2 = table.insert(t[2], f)
local v3 = table.insert(t[3], g)
	for i , v in pairs(t) do
		table.sort(v, function(lol,ez)
			return (lol > ez)
		end)
	end
end
    end

rotate(t)

for i, v in pairs(t) do
print(unpack(v))
print(“”)
end

1 Like

I thank you a lot for your contribution! Although the code sadly doesn’t seem to work, and I can’t find the issue. The result isn’t what’s intended. This video should help, please watch it!

I wrote code that I think works with all matrixes also some replies are quite messy(not saying it isn’t well coded, just saying it is over-complicated imo), I made something simple. Correct me if I made any mistakes.

local matrix = 
	{{1,2,3},
	{4,5,6},
	{7,8,9}}

function rotate(m)
	local res = {}
	local n = 0
	for i,v in pairs(matrix) do
		local tableSize = #v
		table.insert(res,{})
		n+=1
		for x = tableSize,1,-1 do
			table.insert(res[n],m[x][i])
		end
	end
	return res
end

print(matrix)

print(rotate(matrix))
1 Like