import Data.Maybe
import Data.List
import System.Environment

-- main = do
--   let Movements _ movements = executeProgramTrackMoves (interpolate 9 "Fa") (-1) (Movements (defaultPos) [])
--       filteredMovements = fmap (\l -> abs ((trd3 (l !! 0)) - ((trd3 (l !! 1))))) $ nub $ filter (\l -> (length l) > 1) $ fmap (\(x1, y1, _) -> filter (\(x2, y2, _) -> (x1, y1) == (x2, y2)) movements) movements
--       in print filteredMovements

-- main = do 
--   args <- getArgs
--   let interpolateCount = read (args !! 0)
--       moveCount = (-1)
--       in print $ executeProgramTrackMoveDirection (interpolate interpolateCount "Fa") moveCount 0 defaultPos
         
-- main = do
--   print $ executeProgramWithInitialDirection "Fa" (-1) North 
--   print $ executeProgram (interpolate 0 "Fa") (-1)
--   putStrLn "--"
--   print $ executeProgramWithInitialDirection "Rb FR" (-1) North
--   print $ executeProgram (interpolate 1 "Fa") (-1)
--   putStrLn "--"
--   print $ executeProgramWithInitialDirection "RLF aLb FR" (-1) South
--   print $ executeProgram (interpolate 2 "Fa") (-1)
--   putStrLn "--"
--   print $ executeProgramWithInitialDirection "RLF aRb FRLLF aLb FR" (-1) South
--   print $ executeProgram (interpolate 3 "Fa") (-1)
--   putStrLn "--"
--   print $ executeProgramWithInitialDirection "RLF aRb FRRLF aLb FRLLF aRb FRLLF aLb FR" (-1) South
--   print $ executeProgram (interpolate 4 "Fa") (-1)
--   putStrLn "--"
--   print $ executeProgramWithInitialDirection "RLF aRb FRRLF aLb FRRLF aRb FRLLF aLb FRLLF aRb FRRLF aLb FRLLF aRb FRLLF aLb FR" (-1) South
--   print $ executeProgram (interpolate 5 "Fa") (-1)

-- main = do
--   print $ executeProgram (interpolate 0 i) (-1)
--   print $ executeProgram (interpolate 1 i) (-1)
--   print $ executeProgram (interpolate 2 i) (-1)
--   print $ executeProgram (interpolate 3 i) (-1)
--   print $ executeProgram (interpolate 4 i) (-1)
--   print $ executeProgram (interpolate 5 i) (-1)
--   print $ executeProgram (interpolate 6 i) (-1)
--   print $ executeProgram (interpolate 7 i) (-1)
--   print $ executeProgram (interpolate 8 i) (-1)
--   print $ executeProgram (interpolate 9 i) (-1)
--   print $ executeProgram (interpolate 10 i) (-1)
--   print $ executeProgram (interpolate 11 i) (-1)

i = "Fa"        

printNTimes n = printN 0 n where
  printN index n = do
    print $ executeProgram (interpolate index i) (-1)
    if index < n then printN (index + 1) n else return ()

main = do
  args <- getArgs
  printNTimes $ read (args !! 0)
                                                
data Position = Position Int Int Direction deriving (Show)
data Direction = North | South | East | West deriving (Show)
data Movements = Movements Position [(Int, Int, Int)] deriving (Show)

defaultPos :: Position
defaultPos = Position 0 0 North

getX :: Position -> Int
getX (Position x _ _) = x

getY :: Position -> Int
getY (Position _ y _) = y

direction :: Position -> Direction
direction (Position _ _ d) = d

getMovements :: Movements -> [(Int, Int, Int)]
getMovements (Movements _ m) = m

moveX :: Position -> Int -> Position
moveX p m = Position ((getX p) + m) (getY p) (direction p)

moveY :: Position -> Int -> Position
moveY p m = Position (getX p) ((getY p) + m) (direction p)

updateDir :: Position -> Direction -> Position
updateDir p d = Position (getX p) (getY p) d

advance :: Position -> Position
advance p = case (direction p) of
  North -> moveY p 1
  South -> moveY p (-1)
  East  -> moveX p 1
  West  -> moveX p (-1)

rotL :: Position -> Position
rotL p = updateDir p $ case (direction p) of
  North -> West
  South -> East
  East  -> North
  West  -> South

rotR :: Position -> Position
rotR p = updateDir p $ case (direction p) of
  North -> East
  South -> West
  East  -> South
  West  -> North

fst3 :: (a, a, a) -> a
fst3 (f, _, _) = f

snd3 :: (a, a, a) -> a
snd3 (_, s, _) = s

trd3 :: (a, a, a) -> a
trd3 (_, _, t) = t

executeProgramTrackMoves :: String -> Int -> Movements -> Movements
executeProgramTrackMoves prog stepLimit movements = execute prog stepLimit 0 movements where
  execute prog stepLimit stepCount (Movements pos locations) = do
    if (length prog) > 0 && (stepLimit < 0 || stepLimit > stepCount) then case (head prog) of
      'F' -> let newPos = advance pos
               in execute (tail prog) stepLimit (stepCount + 1) (Movements newPos ((getX pos, getY pos, stepCount):locations))
      'L' -> execute (tail prog) stepLimit stepCount (Movements (rotL pos) locations)
      'R' -> execute (tail prog) stepLimit stepCount (Movements (rotR pos) locations)
      _   -> execute (tail prog) stepLimit stepCount (Movements pos locations)
    else Movements pos locations

executeProgram :: String -> Int -> Position
executeProgram prog stepLimit = execute prog stepLimit 0 (defaultPos)

executeProgramTrackMoveDirection :: String -> Int -> Int -> Position -> [Direction]
executeProgramTrackMoveDirection prog stepLimit stepCount pos = do
    if (length prog) > 0 && (stepLimit < 0 || stepLimit > stepCount) then case (head prog) of
      'F' -> (direction pos):(executeProgramTrackMoveDirection (tail prog) stepLimit (stepCount + 1) (advance pos))
      'L' -> executeProgramTrackMoveDirection (tail prog) stepLimit (stepCount + 1) (rotL pos)
      'R' -> executeProgramTrackMoveDirection (tail prog) stepLimit (stepCount + 1) (rotR pos)
      _   -> executeProgramTrackMoveDirection (tail prog) stepLimit (stepCount + 1) pos
    else []
   
execute :: String -> Int -> Int -> Position -> Position
execute prog stepLimit stepCount pos = do
    if (length prog) > 0 && (stepLimit < 0 || stepLimit > stepCount) then case (head prog) of
      'F' -> execute (tail prog) stepLimit (stepCount + 1) (advance pos)
      'L' -> execute (tail prog) stepLimit stepCount (rotL pos)
      'R' -> execute (tail prog) stepLimit stepCount (rotR pos)
      _   -> execute (tail prog) stepLimit stepCount pos
    else pos

executeProgramWithInitialDirection :: String -> Int -> Direction -> Position
executeProgramWithInitialDirection prog stepLimit dir = execute prog stepLimit 0 (Position 0 0 dir)

interpolate :: Int -> [Char] -> String
interpolate count strToInterpolate = do
  if count > 0 then
    interpolate (count - 1) $ concat $ fmap (\c ->  case c of
      'a' -> "aRbFR"
      'b' -> "LFaLb"
      _   -> [c]) strToInterpolate
  else strToInterpolate
