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 Data.List
    import Data.Char
    import qualified Data.ByteString.Char8 as BS -- BS.getContents
    import qualified Data.Vector as V
    import qualified Data.Map as Map
    import qualified Data.HashMap.Strict as HM
    import Control.Applicative
    import Text.Printf                           -- printf "%0.6f" (1.0)
    import Data.Tuple
    import Data.Maybe
    -- }}}

    type Index = (Int, Int)
    type MatrixIndex = Map.Map Index Index

    main :: IO ()
    main = BS.getContents >>= putStrLn. validate. map getIntArray. BS.lines

    showMatrix :: (Show a) => [[a]] -> String
    showMatrix = unlines. map(unwords. map show)

    validate ([n, m, r]:matrix)
      | n < 2 || n > 300  = error $ printf "n = %d" n
      | m < 2 || m > 300  = error $ printf "m = %d" m
      | odd (min n m)     = error $ printf "min is not even: n = %d, m = %d" n m
      | r < 1 || r > 10^9 = error $ printf "r = %d" r
      | any (any (\x -> x < 1 || x > 10^8)) matrix = error "element of matrix is out of bound"
      | otherwise = showMatrix ans
        where
          vMatrix = V.fromList (map V.fromList matrix)
          (layers, revLayers) = getIndices (n, m)
          layers' = map (rotate r) layers
          layersMap = Map.fromList. concat $ layers'
          revLayersMap = Map.fromList. concat $ revLayers
          indexMatrix = getMatrix (n, m) layersMap revLayersMap
          ans = [ [ vMatrix V.! r V.! c| (r, c) <- rows] | rows <- indexMatrix]

    getMatrix :: Index -> MatrixIndex -> MatrixIndex -> [[(Int, Int)]]
    getMatrix    (n, m)   matIdx revMatIdx = [ [ getValue r c |c <- [0..m-1]]| r <- [0..n-1]]
      where
        getValue r c =
          let
            idx = fromJust. Map.lookup (r, c) $ revMatIdx
          in
            fromJust. Map.lookup idx $ matIdx


    getIndices :: Index -> ([[(Index, Index)]], [[(Index, Index)]])
    getIndices (n, m) = (layers,  layersRev)
      where
        mn = min (n+1) (m+1)
        layers = map (\(r, c) -> getLayer r (n-2*r, m-2*c)) $ indicesAdd
        layersRev = map (map swap) layers
        indicesAdd = take (mn`div`2)(zip [0..] [0..])

    rotate :: Int -> [(Index, Index)] -> [(Index, Index)]
    rotate k idx = zip lt (b++a)
      where
        lt = map fst idx
        rt = map snd idx
        (a, b) = splitAt (k `rem` (length idx)) rt

    getLayer :: Int -> Index -> [(Index, Index)]
    getLayer layerIdx rc@(r, c)
      | r == 0 || c == 0 =
        let
          dr = signum r
          dc = signum c
          arr = zipWith (\d (x, y) -> (x+d*dr, y+d*dc)) [0..] (replicate (max r c) (layerIdx, layerIdx))
        in
          zip (zip (repeat layerIdx) [0..]) arr
      | otherwise = getLayer' 0 (layerIdx, layerIdx) (0, 1)
        where
          getLayer' :: Int -> Index ->        Index ->         [(Index, Index)]
          getLayer'    idx    curPos@(r', c') add1@(rAdd, cAdd)
            | idx == 2*(r-1+c-1) = []
            | otherwise = ((layerIdx, idx), curPos): ans'
              where
                ans' = getLayer' (idx+1) (r'+rAdd', c'+cAdd') add2
                add2@(rAdd', cAdd') = if idx == c-1
                                        then (1, 0)
                                        else if idx == r-1+c-1
                                          then (0, -1)
                                          else if idx == c-1+r-1+c-1
                                            then (-1, 0)
                                            else add1


    ---------------User Defined Functions----------------- {{{
    getIntArray = readIntArray
    readIntArray input_pqr =
        case x_yzpqr of
            Just (a_yzpqr, xs_pqr) -> a_yzpqr : readIntArray (BS.drop 1 xs_pqr)
            Nothing -> []
        where
            x_yzpqr = BS.readInt input_pqr

    ------------------------------------------------------ }}}