This commit is contained in:
2024-12-12 17:55:21 +01:00
parent 2ca07cc93c
commit 1d3f550988

96
12/main.ml Normal file
View File

@@ -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