Skip to content

Instantly share code, notes, and snippets.

@liammclennan
Created April 13, 2015 22:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save liammclennan/160dc400a2a9629a2f5a to your computer and use it in GitHub Desktop.
Save liammclennan/160dc400a2a9629a2f5a to your computer and use it in GitHub Desktop.
Mars Rover problem in F#
type Direction = N | E | S | W
type Rover = {x:int;y:int;direction:Direction}
type Action = L | R | M
type Instruction = {rover:Rover; actions:Action list}
type Initialization = { upperRightX: int; upperRightY: int; instructions: Instruction list}
let testInput = "5 5
1 2 N
LMLMLMLMM
3 3 E
MMRMMRMRRM"
let extectedOutput = "2 3 N
5 1 E"
let parseDirection = function
| "N" -> N
| "E" -> E
| "S" -> S
| "W" -> W
| d -> failwith ("Unknown direction " + d)
let parseRover (line:string) =
let lineParts = line.Split(' ')
{x = lineParts.[0] |> int; y = lineParts.[1] |> int; direction = parseDirection lineParts.[2]}
let parseActions (line:string) =
[
for c in line do
yield match c with
| 'L' -> L
| 'R' -> R
| 'M' -> M
| other -> failwith ("Unknown action " + (string other))
]
let parseInstructions lines : Instruction list =
[
for i in [0..(Array.length lines)/2 - 1] do
let roverLine = lines.[2*i]
let actionLine = lines.[2*i+1]
yield {rover= parseRover roverLine; actions = parseActions actionLine}
]
let parseInitialization (input:string) =
let lines = input.Split('\n')
let topRightLine = lines.[0]
{
upperRightX = lines.[0].Split(' ').[0] |> int; upperRightY = lines.[0].Split(' ').[1] |> int;
instructions = parseInstructions lines.[1..]
}
let play (init:Initialization) =
let playInstruction (instruction:Instruction) =
let turn direction action =
if action = M then failwith "M is not a turn action"
match (direction,action) with
| (N,L) -> W
| (N,R) -> E
| (E,L) -> N
| (E,R) -> S
| (S,L) -> E
| (S,R) -> W
| (W,L) -> S
| (W,R) -> N
let turnAlt direction action =
let directionAngles = [(N,0);(E,90);(S,180);(W,270)]
let angle = (List.find (fun (d,a) -> d = direction) directionAngles) |> snd
let angleToDirection angle =
List.find (fun (d,a) -> a = angle) directionAngles |> fst
let turnedAngle =
match action with
| L -> angle - 90
| R -> angle + 90
| M -> failwith "M is not a turn action"
angleToDirection (if turnedAngle < 0 then
turnedAngle + 360
elif turnedAngle = 360 then
0
else
turnedAngle)
let applyAction (rover:Rover) (action:Action) =
if action = L || action = R then
{rover with direction = turnAlt rover.direction action}
else
let moved = match rover.direction with
| N -> {rover with y = rover.y+1}
| E -> {rover with x = rover.x+1}
| S -> {rover with y = rover.y-1}
| W -> {rover with x = rover.x-1}
if moved.x < 1 || moved.y < 1 || moved.x > init.upperRightX || moved.y > init.upperRightY then
rover
else
moved
List.fold applyAction instruction.rover instruction.actions
List.map playInstruction init.instructions
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment