Created
April 13, 2015 22:41
-
-
Save liammclennan/160dc400a2a9629a2f5a to your computer and use it in GitHub Desktop.
Mars Rover problem in F#
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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