From 1d3f5509881e2450f357ddadf56166263ca3c95a Mon Sep 17 00:00:00 2001 From: Acvaxoort Date: Thu, 12 Dec 2024 17:55:21 +0100 Subject: [PATCH] part 12 --- 12/main.ml | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 12/main.ml diff --git a/12/main.ml b/12/main.ml new file mode 100644 index 0000000..2b2b67d --- /dev/null +++ b/12/main.ml @@ -0,0 +1,96 @@ +open Printf;; + +let rec list_of_lines in_file = + try + let line = input_line in_file in + line :: list_of_lines(in_file) + with End_of_file -> + close_in in_file; + [] + +let file_to_2d_array in_file = + let lines = list_of_lines in_file in + let size_x = String.length @@ List.hd lines in + let size_y = List.length lines in + let arr = Array.make_matrix size_x size_y '?' in + List.iteri (fun j line -> String.iteri (fun i c -> arr.(j).(i) <- c) line) lines; + arr + +let get_neighbours_bitmask list8 = + list8 + |> List.mapi (fun i x -> (i, x)) + |> List.fold_left (fun acc (i, x) -> Int.logor acc (Int.shift_left (if x then 1 else 0) i)) 0 + +let rotate_8bit_left_twice mask = + let x = Int.shift_left mask 2 in + Int.logor (Int.logand x 0xff) (Int.shift_right x 8) + +let count_corners_no_rotation bitmask = + let corner_bitmask = Int.logand bitmask 0x07 in + if corner_bitmask = 0x00 || corner_bitmask = 0x5 || corner_bitmask = 0x2 then 1 else 0 + +let count_corners bitmask = + let rot1 = rotate_8bit_left_twice bitmask in + let rot2 = rotate_8bit_left_twice rot1 in + let rot3 = rotate_8bit_left_twice rot2 in + count_corners_no_rotation bitmask + + count_corners_no_rotation rot1 + + count_corners_no_rotation rot2 + + count_corners_no_rotation rot3 + +let is_same_value value arr (x, y) = + try + arr.(y).(x) = value + with Invalid_argument _ -> false + +let add_int_triplet (a1, a2, a3) (b1, b2, b3) = + (a1 + b1, a2 + b2, a3 + b3) + +let get_even_index_elements lst = + lst + |> List.mapi (fun i x -> (i, x)) + |> List.filter_map (fun (i, x) -> if i mod 2 = 0 then Some x else None) + +let rec grow_and_get_region_parameters arr visited (x, y) = + if visited.(y).(x) then + (0, 0, 0) + else begin + visited.(y).(x) <- true; + let value = arr.(y).(x) in + let neighbours8_coords = [(x, y - 1); (x + 1, y - 1); (x + 1, y); (x + 1, y + 1); (x, y + 1); (x - 1, y + 1); (x - 1, y); (x - 1, y - 1)] in + let neighbours8_same = List.map (is_same_value value arr) neighbours8_coords in + let corners = count_corners @@ get_neighbours_bitmask neighbours8_same in + let neighbours4_coords = get_even_index_elements neighbours8_coords in + let neighbours4_same = get_even_index_elements neighbours8_same in + let sides = List.fold_left (fun acc x -> acc - if x then 1 else 0) 4 neighbours4_same in + Seq.zip (List.to_seq neighbours4_same) (List.to_seq neighbours4_coords) + |> Seq.filter_map (fun (same, coords) -> if same then Some coords else None) + |> Seq.map (grow_and_get_region_parameters arr visited) + |> Seq.fold_left add_int_triplet (1, sides, corners) + end + +let find_all_regions_cost arr = + let size_x = Array.length arr.(0) in + let size_y = Array.length arr in + let visited = Array.make_matrix size_x size_y false in + let regions = ref [] in + for j = 0 to (size_y - 1) do + for i = 0 to (size_x - 1) do + if not visited.(j).(i) then + let parameters = grow_and_get_region_parameters arr visited (i, j) in + regions := parameters :: !regions + done + done; + let price1 = !regions + |> List.map (fun (area, sides, _) -> area * sides) + |> List.fold_left Int.add 0 in + let price2 = !regions + |> List.map (fun (area, _, corners) -> (*printf "%d %d\n" area corners;*) area * corners) + |> List.fold_left Int.add 0 in + (price1, price2) + +let () = + let f = open_in "input.txt" in + let arr = file_to_2d_array f in + let result, result2 = find_all_regions_cost arr in + printf "%d %d\n" result result2