From 373c53ce69b08c0cf2076dd12ba8b586199a5663 Mon Sep 17 00:00:00 2001 From: DJ O'Leary Date: Sun, 7 Dec 2025 21:16:13 +0100 Subject: refactor(matrix): convert matrix into domain module --- 2025/ocaml/lib/application/d04p01.ml | 106 +------------------------ 2025/ocaml/lib/domain/matrix.ml | 150 +++++++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+), 104 deletions(-) create mode 100644 2025/ocaml/lib/domain/matrix.ml diff --git a/2025/ocaml/lib/application/d04p01.ml b/2025/ocaml/lib/application/d04p01.ml index 2cc5f5d..4bf38ad 100644 --- a/2025/ocaml/lib/application/d04p01.ml +++ b/2025/ocaml/lib/application/d04p01.ml @@ -1,106 +1,4 @@ -(** [input_to_matrix input] is a 2D Array where each line of the [input] is - a row and each character in that line is a column. - Requires: all lines in input are of equal length. *) -let input_to_matrix input = - let lines = - input |> String.split_on_char '\n' - |> List.filter_map (fun line -> - let trimmed = String.trim line in - if trimmed <> "" then Some trimmed else None ) - in - let row_count = List.length lines in - let column_count = - match List.nth_opt lines 1 with - | None -> - failwith "first line should not be empty" - | Some line -> - String.length line - in - let matrix = Array.make_matrix column_count row_count "" in - List.iteri - (fun y line -> - String.iteri (fun x char -> matrix.(x).(y) <- Char.escaped char) line ) - lines ; - matrix - -(** [pp_matrix matrix] is the [input] that was used to create the [matrix] - via [input_to_matrix input]. *) -let pp_matrix matrix = - let row_count = Array.length matrix in - let column_count = Array.length matrix.(0) in - let matrix' = Array.make_matrix row_count column_count "" in - Array.iteri - (fun x row -> Array.iteri (fun y c -> matrix'.(y).(x) <- c) row) - matrix ; - matrix' - |> Array.map @@ Array.fold_left (fun acc c -> acc ^ c) "" - |> Array.fold_left - (fun acc line -> if acc = "" then line else acc ^ "\n" ^ line) - "" - let solve input () = - let matrix = input |> input_to_matrix in - Logs.debug (fun m -> m "\n%s" @@ pp_matrix matrix) ; + let matrix = Domain.Matrix.M.of_string input in + Logs.debug (fun m -> m "\n%s" @@ Domain.Matrix.M.pp (fun s -> s) matrix) ; 0 - -let%expect_test "matrix created from input is pretty-printed as the same matrix" - = - let example = - {|..@@.@@@@. -@@@.@.@.@@ -@@@@@.@.@@ -@.@@@@..@. -@@.@@@@.@@ -.@@@@@@@.@ -.@.@.@.@@@ -@.@@@.@@@@ -.@@@@@@@@. -@.@.@@@.@.|} - in - print_string @@ pp_matrix @@ input_to_matrix example ; - [%expect - {|..@@.@@@@. -@@@.@.@.@@ -@@@@@.@.@@ -@.@@@@..@. -@@.@@@@.@@ -.@@@@@@@.@ -.@.@.@.@@@ -@.@@@.@@@@ -.@@@@@@@@. -@.@.@@@.@.|}] - -let%expect_test "direct access of the matrix is in form matrix.(x).(y)" = - let example = - {|..@@.@@@@. -@@@.@.@.@@ -@@@@@.@.@@ -@.@@@@..@. -@@.@@@@.@@ -.@@@@@@@.@ -.@.@.@.@@@ -@.@@@.@@@@ -.@@@@@@@@. -@.@.@@@.@.|} - in - let matrix = input_to_matrix example in - print_string matrix.(0).(0) ; - [%expect "."] ; - print_string matrix.(1).(0) ; - [%expect "."] ; - print_string matrix.(2).(0) ; - [%expect "@"] ; - print_string matrix.(3).(0) ; - [%expect "@"] ; - print_string matrix.(4).(0) ; - [%expect "."] ; - print_string matrix.(5).(0) ; - [%expect "@"] ; - print_string matrix.(6).(0) ; - [%expect "@"] ; - print_string matrix.(7).(0) ; - [%expect "@"] ; - print_string matrix.(8).(0) ; - [%expect "@"] ; - print_string matrix.(9).(0) ; - [%expect "."] diff --git a/2025/ocaml/lib/domain/matrix.ml b/2025/ocaml/lib/domain/matrix.ml new file mode 100644 index 0000000..bb703fc --- /dev/null +++ b/2025/ocaml/lib/domain/matrix.ml @@ -0,0 +1,150 @@ +module M : sig + type 'a t = 'a array array + + val empty : int -> int -> 'a -> 'a t + (** [empty rows columns initial] is an empty 2D array of size [rows] * [columns] + where each element in the array is initialized to [initial]. *) + + val of_list : 'a list list -> 'a t + (** *) + + val of_string : string -> string t + (** [of_string str] is a 2D array where every character is an element. *) + + val get : 'a t -> int -> int -> 'a + (** [get matrix x y] is an alias for [matrix.(y).(x)] *) + + val pp : ('a -> string) -> 'a t -> string + (** [pp matrix string_of_elt] is the string representation of the [matrix] + where [string_of_elt] is called on each element. *) +end = struct + type 'a t = 'a array array + + let empty cols rows initial = Array.make_matrix cols rows initial + + let of_list lst = Array.of_list @@ List.map Array.of_list lst + + let of_string str = + let lines = + str |> String.split_on_char '\n' + |> List.filter_map (fun line -> + let trimmed = String.trim line in + if trimmed <> "" then Some trimmed else None ) + in + let char_lst = + List.map + (fun s -> s |> String.to_seq |> List.of_seq |> List.map Char.escaped) + lines + in + of_list char_lst + + let get matrix x y = matrix.(y).(x) + + let pp string_of_elt matrix = + Array.fold_left + (fun col_acc arr -> + let row = + Array.fold_left + (fun row_acc elt -> row_acc ^ string_of_elt elt) + "" arr + in + if col_acc = "" then row else col_acc ^ "\n" ^ row ) + "" matrix +end + +let%expect_test "matrix created from input is pretty-printed as the same matrix" + = + let example = + {|..@@.@@@@. +@@@.@.@.@@ +@@@@@.@.@@ +@.@@@@..@. +@@.@@@@.@@ +.@@@@@@@.@ +.@.@.@.@@@ +@.@@@.@@@@ +.@@@@@@@@. +@.@.@@@.@.|} + in + print_string @@ M.pp (fun s -> s) @@ M.of_string example ; + [%expect + {|..@@.@@@@. +@@@.@.@.@@ +@@@@@.@.@@ +@.@@@@..@. +@@.@@@@.@@ +.@@@@@@@.@ +.@.@.@.@@@ +@.@@@.@@@@ +.@@@@@@@@. +@.@.@@@.@.|}] + +let%expect_test "direct access of the matrix is in form matrix.(y).(x)" = + let example = + {|..@@.@@@@. +@@@.@.@.@@ +@@@@@.@.@@ +@.@@@@..@. +@@.@@@@.@@ +.@@@@@@@.@ +.@.@.@.@@@ +@.@@@.@@@@ +.@@@@@@@@. +@.@.@@@.@.|} + in + let matrix = M.of_string example in + print_string matrix.(0).(0) ; + [%expect "."] ; + print_string matrix.(0).(1) ; + [%expect "."] ; + print_string matrix.(0).(2) ; + [%expect "@"] ; + print_string matrix.(0).(3) ; + [%expect "@"] ; + print_string matrix.(0).(4) ; + [%expect "."] ; + print_string matrix.(0).(5) ; + [%expect "@"] ; + print_string matrix.(0).(6) ; + [%expect "@"] ; + print_string matrix.(0).(7) ; + [%expect "@"] ; + print_string matrix.(0).(8) ; + [%expect "@"] ; + print_string matrix.(0).(9) ; + [%expect "."] + +let%expect_test "[M.get matrix x y] is an alias for [matrix.(y).(x)]" = + let example = + {|..@@.@@@@. +@@@.@.@.@@ +@@@@@.@.@@ +@.@@@@..@. +@@.@@@@.@@ +.@@@@@@@.@ +.@.@.@.@@@ +@.@@@.@@@@ +.@@@@@@@@. +@.@.@@@.@.|} + in + let matrix = M.of_string example in + print_string @@ M.get matrix 0 0 ; + [%expect "."] ; + print_string @@ M.get matrix 1 0 ; + [%expect "."] ; + print_string @@ M.get matrix 2 0 ; + [%expect "@"] ; + print_string @@ M.get matrix 3 0 ; + [%expect "@"] ; + print_string @@ M.get matrix 4 0 ; + [%expect "."] ; + print_string @@ M.get matrix 5 0 ; + [%expect "@"] ; + print_string @@ M.get matrix 6 0 ; + [%expect "@"] ; + print_string @@ M.get matrix 7 0 ; + [%expect "@"] ; + print_string @@ M.get matrix 8 0 ; + [%expect "@"] ; + print_string @@ M.get matrix 9 0 ; + [%expect "."] -- cgit v1.2.3