(* Common util. Should probably put this in a module or something.. *) let get_one_line file = try Some (input_line file) with End_of_file -> None let get_lines file = let rec input lines = match get_one_line file with Some line -> input (line :: lines) | None -> List.rev lines in input [] let read_file file = let channel = open_in(file) in get_lines channel let explode s = (* convert a string to a list of chars *) let rec exp i l = if i < 0 then l else exp (i - 1) (s.[i] :: l) in exp (String.length s - 1) [];; let implode l = String.of_seq (List.to_seq l) let (<<) f g x = f(g(x)) let (>>) f g x = g(f(x)) let rec find_idx x = function (* find index of x *) | [] -> raise (Failure "Not Found") | h :: t -> if x = h then 0 else 1 + find_idx x t let abs x = if x < 0 then -x else x (* --- *) type instruction = { action: char; value: int } let dirs = [('N', (0, 1)); ('E', (1, 0)); ('S', (0, -1)); ('W', (-1, 0))] let dir_list = ['N'; 'E'; 'S'; 'W'] let parse_line = (* from string to instruction *) explode >> function | action :: value -> { action; value = int_of_string @@ implode value } let rec turn direction (wx, wy) = function (* returns new waypoint location *) | 0 -> (wx, wy) (* doing this 90 degrees at a time *) | degrees -> let new_position = match direction with | 'L' -> (-1 * wy, wx) | 'R' -> (wy, -1 * wx) in turn direction new_position (degrees - 90) let move { action; value } (x, y) (wx, wy) = (* returns (new ship location, new waypoint location) *) Printf.printf "@ (%i, %i). moving %c %i\n" x y action value; match action with | 'L' -> ((x, y), turn 'L' (wx, wy) value) | 'R' -> ((x, y), turn 'R' (wx, wy) value) | 'F' -> ((x + (wx * value), y + (wy * value)), (wx, wy)) | dir -> (* Either N, E, S, or W. Find the (dx, dy) and apply it *) let (dx, dy) = List.assoc dir dirs in ((x, y), (wx + (dx * value), wy + (dy * value))) let rec travel (x, y) (wx, wy) map = match map with | [] -> (x, y) | line :: rest -> let (new_position, waypoint_position) = move line (x, y) (wx, wy) in travel new_position waypoint_position rest let manhattan (x, y) = (abs x) + abs y let () = let map = read_file "day12.txt" |> List.map parse_line in let (x, y) = map |> travel (0, 0) (10, 1) in Printf.printf "ending location (%i, %i). manhattan distance: %i\n" x y (manhattan (x, y));