diff --git a/AdventOfCode2024/bin/main.ml b/AdventOfCode2024/bin/main.ml index 82d5a45..b73f87a 100644 --- a/AdventOfCode2024/bin/main.ml +++ b/AdventOfCode2024/bin/main.ml @@ -13,7 +13,7 @@ let read_lines name = let () = print_endline "\nAdvent of Code 2024"; let part1, part2 = - read_lines "./inputs/05.txt" |> AdventOfCode2024.Day_05.solve + read_lines "./inputs/06.txt" |> AdventOfCode2024.Day_06.solve in Printf.printf "Part 1: %s\nPart 2: %s\n" (string_of_int part1) (string_of_int part2) diff --git a/AdventOfCode2024/lib/day_06.ml b/AdventOfCode2024/lib/day_06.ml new file mode 100644 index 0000000..943999a --- /dev/null +++ b/AdventOfCode2024/lib/day_06.ml @@ -0,0 +1,133 @@ +module IntTuple = struct + type t = int * int * int * int + + let compare (x0, y0, z0, w0) (x1, y1, z1, w1) = + if x0 == x1 && y0 == y1 && z0 == z1 && w0 == w1 then 0 else 1 +end + +module IntTupleSet = Set.Make (IntTuple) + +let find_position lines = + let rec loop list_index lines = + match lines with + | [] -> raise (Invalid_argument "not found") + | head :: tail -> ( + match String.index_from_opt head 0 '^' with + | None -> loop (list_index + 1) tail + | Some i -> (list_index, i)) + in + loop 0 lines + +let remove_list_duplicates l = + let rec loop acc l = + match l with + | [] -> acc + | (y1, x1) :: tail -> + if List.exists (fun (y2, x2) -> x1 == x2 && y1 == y2) acc then + loop acc tail + else loop ([ (y1, x1) ] @ acc) tail + in + loop [] l + +let get_direction_change direction = + match direction with + | -1, 0 -> (0, 1) + | 1, 0 -> (0, -1) + | 0, 1 -> (1, 0) + | 0, -1 -> (-1, 0) + | _ -> raise (Invalid_argument "not valid direction") + +let is_out_of_bounds l (y, x) = + y < 0 || y >= List.length l || x < 0 || x >= String.length (List.nth l 0) + +let is_in_loop visited (y, x) (dy, dx) = + List.exists + (fun (y1, x1, dy1, dx1) -> y1 == y && x1 == x && dy1 == dy && dx1 == dx) + visited + +let positions_visited lines (y, x) = + let rec loop positions (y, x) (dy, dx) = + if is_out_of_bounds lines (y, x) then positions + else + let loop_with_pos = loop ([ (y, x) ] @ positions) in + let next_pos = (y + dy, x + dx) in + + if is_out_of_bounds lines next_pos then loop_with_pos next_pos (dy, dx) + else + let next_tile = String.get (List.nth lines (y + dy)) (x + dx) in + if next_tile == '#' then + let new_dy, new_dx = get_direction_change (dy, dx) in + loop_with_pos (y, x) (new_dy, new_dx) + else loop_with_pos (y + dy, x + dx) (dy, dx) + in + loop [] (y, x) (-1, 0) + +let check_loop lines (y, x) = + let rec loop positions (y, x) (dy, dx) = + if is_out_of_bounds lines (y, x) then false + else if IntTupleSet.mem (y, x, dy, dx) positions then true + else + let incremented_set = IntTupleSet.add (y, x, dy, dx) positions in + let loop_with_pos = loop incremented_set in + let next_pos = (y + dy, x + dx) in + + if is_out_of_bounds lines next_pos then loop_with_pos next_pos (dy, dx) + else + let next_tile = String.get (List.nth lines (y + dy)) (x + dx) in + if next_tile == '#' then + let new_dy, new_dx = get_direction_change (dy, dx) in + loop_with_pos (y, x) (new_dy, new_dx) + else loop_with_pos (y + dy, x + dx) (dy, dx) + in + loop IntTupleSet.empty (y, x) (-1, 0) + +let add_obstacle lines (y, x) = + List.mapi + (fun i -> + fun _ -> + if i == y then + let row = List.nth lines y in + let mapped_str = + String.mapi + (fun j -> fun _ -> if j == x then '#' else String.get row j) + row + in + mapped_str + else List.nth lines i) + lines + +let solve lines = + let initial_position = find_position lines in + let visited = + positions_visited lines initial_position |> remove_list_duplicates + in + let part1 = List.length visited in + + let x_list = List.init (List.nth lines 0 |> String.length) (fun i -> i) in + let y_list = List.init (List.length lines) (fun i -> i) in + + (* + # + .# + *) + let part2 = + List.fold_left + (fun acc y -> + acc + + List.fold_left + (fun acc x -> + let initial_y, initial_x = initial_position in + if + List.exists (fun (y1, x1) -> y1 == y && x1 == x) visited + || (y == initial_y && x == initial_x) + then ( + let new_lines = add_obstacle lines (y, x) in + print_endline (List.nth new_lines 0); + Printf.printf "%d,%d\n" (y + 1) (x + 1); + if check_loop new_lines initial_position then acc + 1 else acc) + else acc) + 0 x_list) + 0 y_list + in + + (part1, part2)