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 rec multiple_application_list f arg n = if n <= 0 then [arg] else arg :: multiple_application_list f (f arg) (n - 1) let count_corners bitmask = multiple_application_list rotate_8bit_left_twice bitmask 3 |> List.map count_corners_no_rotation |> List.fold_left Int.add 0 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) -> 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\n%d\n" result result2