# Mars Rover Kata in Haskell

Riccardo Odone Updated on ・3 min read

You can keep reading here or jump to my blog to get the full experience, including the wonderful pink, blue and white palette.

Today we will TDD the Mars Rover Kata with the T in TDD meaning Type!

## Red

The first step is to define all the types we need for our program to do it's job:

type Coord =
(Int, Int)

type CoordDir =
(Coord, Dir)

data Turn
= L
| R

data Dir
= N
| E
| S
| W

data Cmd
= Turn Turn
| Move

parsePlateauMax :: Text -> Maybe Coord

parseStartingCoordDir :: Text -> Maybe CoordDir

parseCommands :: Text -> Maybe [Cmd]

runCommands :: [Cmd] -> Coord -> CoordDir -> CoordDir

run :: Text -> Maybe CoordDir


Ideally we would use the functions above as follows:

main :: IO ()
main = do
print $parsePlateauMax "5 5" -- Just (5,5) print$ parseStartingCoordDir "1 2 N"
-- Just ((1,2),N)

print $parseCommands "LMLMLMLMM" -- Just [Turn L,Move,Turn L,Move,Turn L,Move,Turn L,Move,Move] let commands = "5 5\n1 2 N\nLMLMLMLMM" maybe (print "ERR!") print$ run commands
-- ((1,3),N)


## Green

With the types in place it's enough to make it compile :D

{-# LANGUAGE OverloadedStrings #-}

module Main where

import Data.Text (Text)
import qualified Data.Text as T (lines, words, unpack)

type Coord =
(Int, Int)

type CoordDir =
(Coord, Dir)

data Turn
= L
| R

data Dir
= N
| E
| S
| W

data Cmd
= Turn Turn
| Move
deriving (Show)

parsePlateauMax :: Text -> Maybe Coord
parsePlateauMax txt =
case T.words txt of
[x, y] -> (,) <$> readMaybeT x <*> readMaybeT y _ -> Nothing parseStartingCoordDir :: Text -> Maybe CoordDir parseStartingCoordDir txt = do (x, y, d) <- case T.words txt of [x, y, d] -> (,,) <$> readMaybeT x <*> readMaybeT y <*> readMaybeT d
_      -> Nothing
Just ((x, y), d)

parseCommands :: Text -> Maybe [Cmd]
parseCommands txt = toCmd traverse T.unpack txt
where
toCmd :: Char -> Maybe Cmd
toCmd 'L' = Just (Turn L)
toCmd 'R' = Just (Turn R)
toCmd 'M' = Just Move
toCmd _   = Nothing

runCommands :: [Cmd] -> Coord -> CoordDir -> CoordDir
runCommands []       _   coordDir             = coordDir
runCommands (c:cmds) max coordDir = runCommands cmds max $newCoordDir c where newCoordDir (Turn L) = turnL coordDir newCoordDir (Turn R) = turnR coordDir newCoordDir Move = move coordDir turnL (c, N) = (c, W) turnL (c, E) = (c, N) turnL (c, S) = (c, E) turnL (c, W) = (c, S) turnR (c, N) = (c, E) turnR (c, E) = (c, S) turnR (c, S) = (c, W) turnR (c, W) = (c, N) move ((x, y), N) = (wrap max (x, y+1), N) move ((x, y), E) = (wrap max (x+1, y), E) move ((x, y), S) = (wrap max (x, y-1), S) move ((x, y), W) = (wrap max (x-1, y), W) wrap (maxX, maxY) (x, y) = (wrap' maxX x, wrap' maxY y) wrap' max x | x < 0 = max + 1 + x wrap' max x | x > max = x rem max wrap' max x | otherwise = x run :: Text -> Maybe CoordDir run txt = do (max, coordDir, cmds) <- go$ T.lines txt
Just $runCommands cmds max coordDir where go [f, s, t] = (,,) <$> parsePlateauMax f <*> parseStartingCoordDir s <*> parseCommands t
go _         = Nothing

main :: IO ()
main = do
let commands = "5 5\n1 2 N\nLMLMLMLMM"
print $parsePlateauMax "5 5" print$ parseStartingCoordDir "1 2 N"
print $parseCommands "LMLMLMLMM" maybe (print "ERR!") print$ run commands


## Refactor

I don't have any more time for today. We will be refactoring in a future post!

Get the latest content via email from me personally. Reply with your thoughts. Let's learn from each other. Subscribe to my PinkLetter!

Posted on by:

### Riccardo Odone

🏳️‍🌈 Pronoun.is/he 💣 Maverick & Leader @Lunar_Logic 🧑‍💻 Functional Programming Rambler 🔥 Sometimes failing 🚀 Sometimes succeeding 💡Always learning

### Discussion

CodinGame have 3-parts series of interactive Mars lander puzzle.

You might want to checkout.