diff --git a/day12.1.ml b/day12.1.ml new file mode 100644 index 0000000..f527ce1 --- /dev/null +++ b/day12.1.ml @@ -0,0 +1,91 @@ +(* 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 dir = North | Eath | South | West +let string_of_dir = function | North -> 'N' | Eeast -> 'E' | South -> 'S' | West -> 'W' + +type action = N | E | S | W | L | R | F +let action_of_char = function | 'N' -> N | 'E' -> E | 'S' -> S | 'W' -> W | 'L' -> L | 'R' -> R | 'F' -> F + +type position = int * int +type bearing = { position: position; heading: char } + +(* nah fuck all that *) +*) + +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 heading = function (* returns new heading, matching on degrees *) + | 0 -> heading (* doing this 90 degrees at a time *) + | d -> (* rotate through our dir_list *) + let old_idx = find_idx heading dir_list in + let idx_dx = match direction with | 'L' -> -1 | 'R' -> 1 in + let new_idx = (old_idx + 4 + idx_dx) mod 4 in (* if we fall off the dir_list in either way, wrap around with mod *) + let new_heading = List.nth dir_list new_idx in + (* Printf.printf "turning! old_idx %i idx_dx %i new_idx %i new_heading %c" old_idx idx_dx new_idx new_heading; *) + turn direction new_heading (d - 90) + +let move { action; value } (x, y) heading = (* returns (new location, new heading) *) + Printf.printf "@ (%i, %i) facing %c. moving %c %i\n" x y heading action value; + match action with + | 'L' -> ((x, y), turn 'L' heading value) + | 'R' -> ((x, y), turn 'R' heading value) + | 'F' -> + let (dx, dy) = List.assoc heading dirs in + ((x + (dx * value), y + (dy * value)), heading) + | dir -> (* Either N, E, S, or W. Find the (dx, dy) and apply it *) + let (dx, dy) = List.assoc dir dirs in + ((x + (dx * value), y + (dy * value)), heading) + +let rec travel (x, y) heading map = + match map with + | [] -> (x, y) + | line :: rest -> + let (new_position, new_heading) = move line (x, y) heading in + travel new_position new_heading 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) 'E' in + Printf.printf "ending location (%i, %i). manhattan distance: %i\n" x y (manhattan (x, y)); diff --git a/day12.2.ml b/day12.2.ml new file mode 100644 index 0000000..3fe27e5 --- /dev/null +++ b/day12.2.ml @@ -0,0 +1,74 @@ +(* 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));