diff --git a/bin/day2412.ml b/bin/day2412.ml index 3ab88a8..0d50fc0 100644 --- a/bin/day2412.ml +++ b/bin/day2412.ml @@ -1,9 +1,40 @@ -let find_regions grid = +let get_by_pos_opt grid pos = + if Aoc.Grid.pos_is_valid grid pos then Some (Aoc.Grid.get_by_pos grid pos) + else None + +let perimeter grid (x, y) = + let region = Aoc.Grid.get_by_pos grid (x, y) in + 0 + + (if get_by_pos_opt grid (x - 1, y) = Some region then 1 else 0) + + (if get_by_pos_opt grid (x + 1, y) = Some region then 1 else 0) + + (if get_by_pos_opt grid (x, y + 1) = Some region then 1 else 0) + + if get_by_pos_opt grid (x, y - 1) = Some region then 1 else 0 + +let is_corner grid (x, y) (dx, dy) = + let region = Aoc.Grid.get_by_pos grid (x, y) in + if + get_by_pos_opt grid (x + dx, y) <> Some region + && get_by_pos_opt grid (x, y + dy) <> Some region + then true + else if + get_by_pos_opt grid (x + dx, y) = Some region + && get_by_pos_opt grid (x, y + dy) = Some region + && get_by_pos_opt grid (x + dx, y + dy) <> Some region + then true + else false + +let corners grid pos = + (if is_corner grid pos (-1, -1) then 1 else 0) + + (if is_corner grid pos (-1, 1) then 1 else 0) + + (if is_corner grid pos (1, 1) then 1 else 0) + + if is_corner grid pos (1, -1) then 1 else 0 + +let find_regions calc grid = let working = Array.make (Aoc.Grid.length grid) ~-1 in - let add_pos region pos perimeter lst = - if Aoc.Grid.pos_is_valid grid pos && Aoc.Grid.get_by_pos grid pos = region - then (Aoc.Grid.idx_of_pos grid pos :: lst, perimeter - 1) - else (lst, perimeter) + let add_pos region pos lst = + if get_by_pos_opt grid pos = Some region then + Aoc.Grid.idx_of_pos grid pos :: lst + else lst in let rec scan_pos perimeter area id = function | [] -> (perimeter, area) @@ -12,12 +43,12 @@ let find_regions grid = working.(idx) <- id; let x, y = Aoc.Grid.pos_of_idx grid idx in let area = succ area in - let perimeter = perimeter + 4 in + let perimeter = perimeter + calc grid (x, y) in let region = Aoc.Grid.get_by_idx grid idx in - let t, perimeter = add_pos region (x - 1, y) perimeter t in - let t, perimeter = add_pos region (x + 1, y) perimeter t in - let t, perimeter = add_pos region (x, y - 1) perimeter t in - let t, perimeter = add_pos region (x, y + 1) perimeter t in + let t = add_pos region (x - 1, y) t in + let t = add_pos region (x + 1, y) t in + let t = add_pos region (x, y - 1) t in + let t = add_pos region (x, y + 1) t in scan_pos perimeter area id t in let rec impl acc idx id = @@ -29,7 +60,9 @@ let find_regions grid = in impl [] 0 0 -let part1 grid = - find_regions grid |> List.fold_left (fun acc (p, a) -> acc + (p * a)) 0 +let part calc grid = + find_regions calc grid |> List.fold_left (fun acc (p, a) -> acc + (p * a)) 0 -let _ = Aoc.main Aoc.Grid.of_file [ (string_of_int, part1) ] +let _ = + Aoc.main Aoc.Grid.of_file + [ (string_of_int, part perimeter); (string_of_int, part corners) ]