Created
May 17, 2016 20:21
-
-
Save isaacabraham/984d1769d80812247c11a5389c07b47b to your computer and use it in GitHub Desktop.
Sample solution to Thoughtworks Rover challenge
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
// A few patterns to make it a bit easier to reason about the raw text. A more typesafe implementation might use full discriminated unions. | |
let (|North|South|East|West|) = function | "N" -> North | "S" -> South | "E" -> East | "W" -> West | _ -> failwith "Unknown direction" | |
let (|Rotate|MoveForward|) = function | 'L' | 'R' -> Rotate | 'M' -> MoveForward | _ -> failwith "Unknown command" | |
let (|Left|Right|) = function | 'L' -> Left | 'R' -> Right | _ -> failwith "Unknown command" | |
/// A DTO to represent the Rover | |
type Rover = { X : int; Y : int; Direction : string } | |
/// Moves the rover forward one unit. | |
let driveForward rover = | |
match rover.Direction with | |
| North -> { rover with Y = rover.Y + 1 } | |
| South -> { rover with Y = rover.Y - 1 } | |
| East -> { rover with X = rover.X + 1 } | |
| West -> { rover with X = rover.X - 1 } | |
/// Rotates the rover left or right by 90 degrees. | |
let rotate rotation rover = | |
{ rover with | |
Direction = | |
let directions = [ "N"; "E"; "S"; "W" ] | |
let index = | |
let currentPositionIndex = directions |> List.findIndex ((=) rover.Direction) | |
match rotation with | |
| Left -> currentPositionIndex - 1 | |
| Right -> currentPositionIndex + 1 | |
match index with | |
| -1 -> "W" | |
| 4 -> "N" | |
| index -> directions.[index] } | |
/// Carries out a single command on a the rover | |
let act rover command = | |
match command with | |
| MoveForward -> rover |> driveForward | |
| Rotate -> rover |> rotate command | |
/// Parses a single raw input command into a Rover and associated set of commands. | |
let parse [ rover:string; commands ] = | |
let [| x; y; direction |] = rover.Split ' ' | |
{ X = int x; Y = int y; Direction = direction }, | |
commands |> Seq.toArray | |
/// Everything above is the behaviour; below we feed the data into it. | |
/// Parse our sample dataset | |
let instructions = | |
[ "5 5" | |
"1 2 N" | |
"LMLMLMLMM" | |
"3 3 E" | |
"MMRMMRMRRM" ] | |
|> List.skip 1 | |
|> List.chunkBySize 2 | |
|> List.map parse | |
/// Carry out the commands | |
instructions | |
|> List.map(fun (rover, commands) ->(rover, commands) ||> Array.fold act) | |
|> List.iter(fun rover -> printfn "%d %d %s" rover.X rover.Y rover.Direction) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment