Matrix Rotation
Difficulty: Hard

<sup><strong>[Here](https://www.hackerrank.com/challenges/matrix-rotation-algo) is the non-FP version of this challenge, with all languages enabled.</strong></sup>

---
You are given a 2D  matrix, _a_, of dimension *MxN* and a positive integer _R_. You have to rotate the matrix _R_ times and print the resultant matrix. Rotation should be in anti-clockwise direction.  

Rotation of a _4x5_ matrix is represented by the following figure. Note that in one rotation, you have to shift elements by one step only (refer sample tests for more clarity).


![matrix-rotation](https://hr-challenge-images.s3.amazonaws.com/2517/matrix-rotation.png)

It is guaranteed that the minimum of _M_ and _N_ will be even.  

**Input**  
First line contains three space separated integers, *M*, *N* and *R*, where _M_ is the number of rows, _N_ is number of columns in matrix, and _R_ is the number of times the matrix has to be rotated.  
Then *M* lines follow, where each line contains *N* space separated positive integers. These *M* lines  represent the matrix.  

**Output**  
Print the rotated matrix.

**Constraints**  
2 <= *M*, *N* <= 300  
1 <= *R* <= 10<sup>9</sup>  
min(_M, N_) % 2 == 0  
1 <= _a<sub>ij</sub>_ <= 10<sup>8</sup>, where _i_ &isin; _[1..M]_ & _j_ &isin; _[1..N]_  

**Sample Input #00**

    4 4 1
    1 2 3 4
    5 6 7 8
    9 10 11 12
    13 14 15 16

**Sample Output #00**

    2 3 4 8
    1 7 11 12
    5 6 10 16
    9 13 14 15

**Sample Input #01**

    4 4 2
    1 2 3 4
    5 6 7 8
    9 10 11 12
    13 14 15 16

**Sample Output #01**

    3 4 8 12
    2 11 10 16
    1 7 6 15
    5 9 13 14


**Sample Input #02**

    5 4 7
    1 2 3 4
    7 8 9 10
    13 14 15 16
    19 20 21 22
    25 26 27 28

**Sample Output #02**

    28 27 26 25
    22 9 15 19
    16 8 21 13
    10 14 20 7
    4 3 2 1



**Sample Input #03**

    2 2 3
    1 1
    1 1

**Sample Output #03**

    1 1
    1 1


**Explanation**  
*Sample Case #00:* Here is an illustration of what happens when the matrix is rotated once.

     1  2  3  4      2  3  4  8
     5  6  7  8      1  7 11 12
     9 10 11 12  ->  5  6 10 16
    13 14 15 16      9 13 14 15

*Sample Case #01:* Here is what happens when to the matrix after two rotations.

     1  2  3  4      2  3  4  8      3  4  8 12
     5  6  7  8      1  7 11 12      2 11 10 16
     9 10 11 12  ->  5  6 10 16  ->  1  7  6 15
    13 14 15 16      9 13 14 15      5  9 13 14

*Sample Case #02:* Following are the intermediate states.

    1  2  3  4      2  3  4 10    3  4 10 16    4 10 16 22
    7  8  9 10      1  9 15 16    2 15 21 22    3 21 20 28
    13 14 15 16 ->  7  8 21 22 -> 1  9 20 28 -> 2 15 14 27 ->
    19 20 21 22    13 14 20 28    7  8 14 27    1  9  8 26
    25 26 27 28    19 25 26 27    13 19 25 26   7 13 19 25



    10 16 22 28    16 22 28 27    22 28 27 26    28 27 26 25
     4 20 14 27    10 14  8 26    16  8  9 25    22  9 15 19
     3 21  8 26 ->  4 20  9 25 -> 10 14 15 19 -> 16  8 21 13
     2 15  9 25     3 21 15 19     4 20 21 13    10 14 20  7
     1  7 13 19     2  1  7 13     3  2  1  7     4  3  2  1

*Sample Case #03:* As all elements are same, any rotation will reflect the same matrix.

---
**Tested by:** [Tusshar Singh](/tussharsingh13), [Abhiranjan](/abhiranjan)


Input Format:

Output Format:

Sample Input:

Sample Output:

Python 3 starter code:


Reference solution (Python):
    import scala.collection.mutable.HashMap;

    object Solution{

        def main(args:Array[String]) = {
            val in = readLine.split(" ").map(_.toInt);
            var arr = new Array[Array[Int]](in(0));
            for(i <- 1 to in(0)) 
                arr(i-1) = readLine.split(" ").map(_.toInt);
            println(rotate(arr, in(2)));
        }

        def rotate(arr:Array[Array[Int]], r:Int):String = {
            var b = Array.fill(arr.size){ new Array[Int](arr(0).size) };
            var m = arr.size;
            var n = arr(0).size;
            val min = Math.min(m/2, n/2);
            for(i <- 1 to min){
                val map = getMap(m, n);
                val len = map.keys.size;
                for(j <- map.keys){
                    val cur = map(j);
                    val next = map((j+r)%len);
                    b(next._1 + i-1)(next._2 + i-1) = arr(cur._1 + i-1)(cur._2 + i-1);
                }
                m-=2;
                n-=2;
            }
            return b.map(x => x.mkString(" ")).mkString("\n");
        }

        def getMap(m:Int, n:Int):HashMap[Int, Tuple2[Int, Int]] = {
            var map = new HashMap[Int, Tuple2[Int, Int]]();
            val len = 2*(m+n-2)-1;
            for(i <- 0 to len) map += (i -> getLoc(i, m, n));
            return map;
        }

        def getLoc(i:Int, m:Int, n:Int):Tuple2[Int, Int] = {
            if(i < m-1) 
                return (i, 0);
            else if(i < m+n-2) 
                return (m-1, (i - m + 1) % n);
            else if(i < 2*m + n - 3) 
                return (2*m + n-3-i, n-1);
            else 
                return (0, 2*(m+n-2)-i);
        }
    }