changeset 50:fd8411815fff

Non-AOC: Leaky Roof problem (Google interviews)
author Lewin Bormann <lbo@spheniscida.de>
date Wed, 13 Dec 2023 09:34:10 +0100
parents 31edc574a4bc
children fd579cbd3a93
files 2023/dune 2023/leakyroof.ml
diffstat 2 files changed, 97 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/2023/dune	Thu Dec 07 22:33:48 2023 +0100
+++ b/2023/dune	Wed Dec 13 09:34:10 2023 +0100
@@ -46,3 +46,14 @@
  (libraries base core angstrom)
  (preprocess
   (pps ppx_let ppx_sexp_conv)))
+
+(executable
+ (name leakyroof)
+ (modules leakyroof)
+ (libraries base core angstrom)
+ (preprocess
+  (pps ppx_let ppx_sexp_conv)))
+
+(env
+  (dev
+    (flags (:standard -w -32-33))))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/2023/leakyroof.ml	Wed Dec 13 09:34:10 2023 +0100
@@ -0,0 +1,86 @@
+open Base
+open Core
+
+module Roof = struct
+  type t = { a : bool array; m : int; n : int }
+
+  let random_bool ?(chance = 30) () = Random.int 100 < chance
+
+  let create m n =
+    { a = Array.init (n * m) ~f:(fun _i -> random_bool ()); m; n }
+
+  let string_of_t arr =
+    let char_of_bool = function true -> " X " | false -> " O " in
+    let f ix a e =
+      if Int.((ix + 1) % arr.n = 1) then
+        Printf.sprintf "\n%s" (char_of_bool e) :: a
+      else char_of_bool e :: a
+    in
+    let parts = List.rev @@ ("\n" :: Array.foldi ~init:[] ~f arr.a) in
+    let parts = Printf.sprintf "%d x %d roof\n" arr.m arr.n :: parts in
+    String.concat parts
+
+  type cover = { rows : bool array; cols : bool array } [@@deriving sexp]
+
+  let cover_for_roof roof =
+    {
+      rows = Array.create ~len:roof.m false;
+      cols = Array.create ~len:roof.n false;
+    }
+
+  let with_row_covered m cover f =
+    let old = cover.rows.(m) in
+    cover.rows.(m) <- true;
+    let r = f cover in
+    cover.rows.(m) <- old;
+    r
+
+  let with_col_covered m cover f =
+    let old = cover.cols.(m) in
+    cover.cols.(m) <- true;
+    let r = f cover in
+    cover.cols.(m) <- old;
+    r
+
+  let is_covered cover x y = cover.rows.(x) || cover.cols.(y)
+
+  let covers cover =
+    let f a e = if e then a + 1 else a in
+    let rr = Array.fold ~init:0 ~f cover.rows in
+    let rc = Array.fold ~init:0 ~f cover.cols in
+    rr + rc
+
+  let coords_from_ix roof ix =
+    let x = ix / roof.m in
+    let y = ix % roof.m in
+    (x, y)
+
+  let first_open_leak roof cover =
+    let f ix e =
+      let x, y = coords_from_ix roof ix in
+      match (e, is_covered cover x y) with
+      | true, false -> Some (x, y)
+      | _ -> None
+    in
+    Array.find_mapi roof.a ~f
+end
+
+let rec solve roof cover =
+  match Roof.first_open_leak roof cover with
+  | None -> Roof.covers cover
+  | Some (lx, ly) ->
+      let row_covered = Roof.with_row_covered lx cover (solve roof) in
+      let col_covered = Roof.with_col_covered ly cover (solve roof) in
+      Int.min row_covered col_covered
+
+let solve0 roof =
+  let cover = Roof.cover_for_roof roof in
+  solve roof cover
+
+let () =
+  let roof = Roof.create 5 5 in
+  let min = solve0 roof in
+  let open Out_channel in
+  printf "min: %d\n" min;
+  output_string stdout "\n";
+  output_string stdout (Roof.string_of_t roof)