summaryrefslogtreecommitdiff
path: root/2025/ocaml/lib
diff options
context:
space:
mode:
Diffstat (limited to '2025/ocaml/lib')
-rw-r--r--2025/ocaml/lib/application/d01p01.ml53
-rw-r--r--2025/ocaml/lib/application/d01p01.mli4
-rw-r--r--2025/ocaml/lib/application/d01p02.ml55
-rw-r--r--2025/ocaml/lib/application/d01p02.mli4
-rw-r--r--2025/ocaml/lib/application/d02p01.ml54
-rw-r--r--2025/ocaml/lib/application/d02p01.mli4
-rw-r--r--2025/ocaml/lib/application/d02p02.ml86
-rw-r--r--2025/ocaml/lib/application/d02p02.mli4
-rw-r--r--2025/ocaml/lib/application/d03p01.ml23
-rw-r--r--2025/ocaml/lib/application/d03p01.mli4
-rw-r--r--2025/ocaml/lib/application/d03p02.ml23
-rw-r--r--2025/ocaml/lib/application/d03p02.mli4
-rw-r--r--2025/ocaml/lib/application/d04p01.ml48
-rw-r--r--2025/ocaml/lib/application/d04p01.mli4
-rw-r--r--2025/ocaml/lib/application/d04p02.ml64
-rw-r--r--2025/ocaml/lib/application/d04p02.mli4
-rw-r--r--2025/ocaml/lib/application/d05p01.ml3
-rw-r--r--2025/ocaml/lib/application/d05p01.mli4
-rw-r--r--2025/ocaml/lib/application/d06p01.ml50
-rw-r--r--2025/ocaml/lib/application/d06p01.mli4
-rw-r--r--2025/ocaml/lib/application/d06p02.ml50
-rw-r--r--2025/ocaml/lib/application/d06p02.mli4
-rw-r--r--2025/ocaml/lib/application/dune14
-rw-r--r--2025/ocaml/lib/application/parser.ml36
-rw-r--r--2025/ocaml/lib/domain/d01p01.ml76
-rw-r--r--2025/ocaml/lib/domain/d01p02.ml95
-rw-r--r--2025/ocaml/lib/domain/d02p01.ml33
-rw-r--r--2025/ocaml/lib/domain/d02p01.mli36
-rw-r--r--2025/ocaml/lib/domain/d02p02.ml29
-rw-r--r--2025/ocaml/lib/domain/d02p02.mli30
-rw-r--r--2025/ocaml/lib/domain/d03p01.ml114
-rw-r--r--2025/ocaml/lib/domain/d03p02.ml116
-rw-r--r--2025/ocaml/lib/domain/dune13
-rw-r--r--2025/ocaml/lib/domain/matrix.ml196
-rw-r--r--2025/ocaml/lib/domain/range.ml67
-rw-r--r--2025/ocaml/lib/infrastructure/dune15
-rw-r--r--2025/ocaml/lib/infrastructure/file.ml4
-rw-r--r--2025/ocaml/lib/infrastructure/file.mli3
-rw-r--r--2025/ocaml/lib/presentation/cli.ml62
-rw-r--r--2025/ocaml/lib/presentation/dune16
40 files changed, 0 insertions, 1508 deletions
diff --git a/2025/ocaml/lib/application/d01p01.ml b/2025/ocaml/lib/application/d01p01.ml
deleted file mode 100644
index 206e757..0000000
--- a/2025/ocaml/lib/application/d01p01.ml
+++ /dev/null
@@ -1,53 +0,0 @@
-open Domain.D01p01
-
-let err_empty_input = "input is empty"
-
-let rec input_to_lines input =
- let lines =
- String.split_on_char '\n' input |> List.filter (fun l -> l <> "")
- in
- pp_lines lines ; lines
-
-and pp_lines = function
- | [] ->
- ()
- | h :: t ->
- Logs.debug (fun m -> m "Line=%s" h) ;
- pp_lines t
-
-let parse_line line =
- Scanf.sscanf line "%c%d" (fun d n ->
- match d with
- | 'L' ->
- Dial.Left n
- | 'R' ->
- Dial.Right n
- | _ ->
- failwith "invalid direction" )
-
-let lines_to_turns =
- List.map (fun (l : string) ->
- Logs.debug (fun m -> m "parsing %s into turn" l) ;
- let turn = parse_line l in
- Logs.debug (fun m -> m "%s" (Dial.pp_direction turn)) ;
- turn )
-
-let rec turn_aux count current = function
- | [] ->
- count
- | h :: t ->
- let current' = Dial.turn current h in
- Logs.debug (fun m -> m "dial at %d" (Dial.to_int current')) ;
- if Dial.to_int current' = 0 then turn_aux (count + 1) current' t
- else turn_aux count current' t
-
-let turn current = turn_aux 0 current
-
-let solve input () =
- if input = "" then Error err_empty_input
- else
- let lines = input_to_lines input in
- let turns = lines_to_turns lines in
- let start = Dial.start in
- let answer = turn start turns in
- Ok answer
diff --git a/2025/ocaml/lib/application/d01p01.mli b/2025/ocaml/lib/application/d01p01.mli
deleted file mode 100644
index 2eecf19..0000000
--- a/2025/ocaml/lib/application/d01p01.mli
+++ /dev/null
@@ -1,4 +0,0 @@
-val solve : string -> unit -> (int, string) result
-(** [solve input ()] is the solution for the first part of the first day of advent of code 2025 for [input].
- The solution for an empty input is [None].
- Requires: [input] to be a multiline string using `\n` as it's line separator. *)
diff --git a/2025/ocaml/lib/application/d01p02.ml b/2025/ocaml/lib/application/d01p02.ml
deleted file mode 100644
index 7910486..0000000
--- a/2025/ocaml/lib/application/d01p02.ml
+++ /dev/null
@@ -1,55 +0,0 @@
-open Domain.D01p02
-
-let err_empty_input = "input is empty"
-
-let rec input_to_lines input =
- let lines =
- String.split_on_char '\n' input |> List.filter (fun l -> l <> "")
- in
- pp_lines lines ; lines
-
-and pp_lines = function
- | [] ->
- ()
- | h :: t ->
- Logs.debug (fun m -> m "Line=%s" h) ;
- pp_lines t
-
-let parse_line line =
- Scanf.sscanf line "%c%d" (fun d n ->
- match d with
- | 'L' ->
- Dial.Left n
- | 'R' ->
- Dial.Right n
- | _ ->
- failwith "invalid direction" )
-
-let lines_to_turns =
- List.map (fun (l : string) ->
- Logs.debug (fun m -> m "parsing %s into turn" l) ;
- let turn = parse_line l in
- Logs.debug (fun m -> m "%s" (Dial.pp_direction turn)) ;
- turn )
-
-let rec turn_aux count dial = function
- | [] ->
- count
- | h :: t -> (
- let dial_and_count = Turner.turn dial count h in
- match dial_and_count with
- | dial', count' ->
- Logs.debug (fun m ->
- m "(dial=%d, count=%d)" (Dial.to_int dial') count' ) ;
- turn_aux count' dial' t )
-
-let turn current = turn_aux 0 current
-
-let solve input () =
- if input = "" then Error err_empty_input
- else
- let lines = input_to_lines input in
- let turns = lines_to_turns lines in
- let start = Dial.start in
- let answer = turn start turns in
- Ok answer
diff --git a/2025/ocaml/lib/application/d01p02.mli b/2025/ocaml/lib/application/d01p02.mli
deleted file mode 100644
index 9e9a2f2..0000000
--- a/2025/ocaml/lib/application/d01p02.mli
+++ /dev/null
@@ -1,4 +0,0 @@
-val solve : string -> unit -> (int, string) result
-(** [solve input ()] is the solution for the second part of the first day of advent of code 2025 for [input].
- The solution for an empty input is [Error msg].
- Requires: [input] to be a multiline string using `\n` as it's line separator. *)
diff --git a/2025/ocaml/lib/application/d02p01.ml b/2025/ocaml/lib/application/d02p01.ml
deleted file mode 100644
index f313149..0000000
--- a/2025/ocaml/lib/application/d02p01.ml
+++ /dev/null
@@ -1,54 +0,0 @@
-open Domain.D02p01
-
-let err_empty_input = "input is empty"
-
-(** [input_to_lines input] is a list of strings that have been split on ','.
- Example: [input_to_lines "12-34,56-78,90-100"] becomes the list \[ "12-34"; "56-78"; "90-100" \].
- Requires: [input] to be a string in the format "12-34,56-78,90-100". *)
-let input_to_lines input = input |> String.trim |> String.split_on_char ','
-
-let pp_lines = Seq.iter (fun l -> Logs.debug (fun m -> m "line=%s" l))
-
-(** [lines_to_ranges line] is a list of [Range]s found on [line]. *)
-let lines_to_ranges =
- Seq.map (fun line ->
- Scanf.sscanf line "%d-%d" (fun id1 id2 -> Range.create (id1, id2)) )
-
-let pp_ranges = Seq.iter (fun r -> Logs.debug (fun m -> m "%s" (Range.pp r)))
-
-(** [collect_all ranges] is an unsorted list of [ID]s within the [ranges] (inclusive). *)
-let collect_all =
- Seq.concat_map (fun range -> List.to_seq (Range.collect range))
-
-let pp_collection = Seq.iter (fun c -> Logs.debug (fun m -> m "%s" (ID.pp c)))
-
-(** [rules] is a list of rules that [ID]s must pass to be considered invalid. *)
-let rules =
- [ (fun id -> String.length (ID.to_string id) mod 2 = 0)
- ; (fun id ->
- let id' = ID.to_string id in
- let id_len = String.length id' in
- let left = String.sub id' 0 (id_len / 2) in
- let right = String.sub id' (id_len / 2) (id_len / 2) in
- String.equal left right ) ]
-
-(** [is_invalid id] is [true] for an [id] that passes all of the rules and is considered invalid. *)
-let is_invalid = ID.validate rules
-
-(** [passthrough_with_logs logger lst] is [lst] with the side-effects caused by calling [logger] on [lst]. *)
-let passthrough_with_logs logger lst = logger lst ; lst
-
-let solve input () =
- if input = "" then Error err_empty_input
- else
- let answer =
- input |> input_to_lines |> List.to_seq
- |> passthrough_with_logs pp_lines
- |> lines_to_ranges
- |> passthrough_with_logs pp_ranges
- |> collect_all
- |> passthrough_with_logs pp_collection
- |> Seq.filter is_invalid
- |> Seq.fold_left (fun acc id -> acc + ID.to_int id) 0
- in
- Ok answer
diff --git a/2025/ocaml/lib/application/d02p01.mli b/2025/ocaml/lib/application/d02p01.mli
deleted file mode 100644
index 8a8eb32..0000000
--- a/2025/ocaml/lib/application/d02p01.mli
+++ /dev/null
@@ -1,4 +0,0 @@
-val solve : string -> unit -> (int, string) result
-(** [solve input ()] is the solution for the first part of the second day of advent of code 2025 for [input].
- The solution for an empty input is [Error msg].
- Requires: [input] to be a string. *)
diff --git a/2025/ocaml/lib/application/d02p02.ml b/2025/ocaml/lib/application/d02p02.ml
deleted file mode 100644
index d062f7b..0000000
--- a/2025/ocaml/lib/application/d02p02.ml
+++ /dev/null
@@ -1,86 +0,0 @@
-open Domain.D02p02
-
-(* Errors *)
-
-let err_empty_input = "input is empty"
-
-(* Logging *)
-
-(** [passthrough_with_logs logger lst] is [lst] with the side-effects caused by calling [logger] on [lst]. *)
-let passthrough_with_logs logger lst = logger lst ; lst
-
-(** [input_to_lines input] is a list of strings that have been split on ','.
- Example: [input_to_lines "12-34,56-78,90-100"] becomes the list \[ "12-34"; "56-78"; "90-100" \].
- Requires: [input] to be a string in the format "12-34,56-78,90-100". *)
-let input_to_lines input = input |> String.trim |> String.split_on_char ','
-
-let pp_lines = Seq.iter (fun l -> Logs.debug (fun m -> m "line=%s" l))
-
-let pp_ranges = Seq.iter (fun r -> Logs.debug (fun m -> m "%s" (Range.pp r)))
-
-let pp_collection = Seq.iter (fun c -> Logs.debug (fun m -> m "%s" (ID.pp c)))
-
-(* Core Logic *)
-
-(** [lines_to_ranges line] is a list of [Range]s found on [line]. *)
-let lines_to_ranges =
- Seq.map (fun line ->
- Scanf.sscanf line "%d-%d" (fun id1 id2 -> Range.create (id1, id2)) )
-
-(** [collect_all ranges] is an unsorted list of [ID]s within the [ranges] (inclusive). *)
-let collect_all =
- Seq.concat_map (fun range -> List.to_seq (Range.collect range))
-
-(** [string_to_segments count string] is a list containing [count] string segments with of equal length.
- Requires: length of [string] to be divisible by [count]
- and [count] to be greater than or equal to zero *)
-let rec string_to_segments s =
- let segment_lengths = possible_segment_lengths s in
- List.map (fun c -> string_to_segments_aux [] c s |> List.rev) segment_lengths
-
-(** [possible_segment_lengths s] is a list of segment sizes that fit within [s]
- that must be checked to rule out a repeating pattern. *)
-and possible_segment_lengths s =
- List.init (String.length s) (fun x -> x + 1)
- |> List.filter (fun x -> x != 1 && String.length s mod x = 0)
-
-and string_to_segments_aux segments count string =
- match List.length segments = count with
- | true ->
- segments
- | false ->
- let segment_start = String.length string / count * List.length segments in
- let segment_len = String.length string / count in
- string_to_segments_aux
- (String.sub string segment_start segment_len :: segments)
- count string
-
-(** [cmp_segments segments] is true is all segments are equal *)
-let cmp_segments segments =
- List.length (List.sort_uniq String.compare segments) = 1
-
-(** [is_invalid id] is [true] for an [id] that is considered invalid. *)
-let is_invalid id =
- Logs.debug (fun m -> m "CHECKING ID=%s" id) ;
- let repeating_patterns =
- id |> string_to_segments |> List.filter cmp_segments
- in
- List.iter
- (fun l -> Logs.debug (fun m -> m "HAS SUBPATTERN=%s" (List.hd l)))
- repeating_patterns ;
- List.length repeating_patterns > 0
-
-let solve input () =
- if input = "" then Error err_empty_input
- else
- let answer =
- input |> input_to_lines |> List.to_seq
- |> passthrough_with_logs pp_lines
- |> lines_to_ranges
- |> passthrough_with_logs pp_ranges
- |> collect_all
- |> passthrough_with_logs pp_collection
- |> Seq.map ID.to_string |> Seq.filter is_invalid
- |> Seq.fold_left (fun acc id -> acc + int_of_string id) 0
- in
- Ok answer
diff --git a/2025/ocaml/lib/application/d02p02.mli b/2025/ocaml/lib/application/d02p02.mli
deleted file mode 100644
index 8a8eb32..0000000
--- a/2025/ocaml/lib/application/d02p02.mli
+++ /dev/null
@@ -1,4 +0,0 @@
-val solve : string -> unit -> (int, string) result
-(** [solve input ()] is the solution for the first part of the second day of advent of code 2025 for [input].
- The solution for an empty input is [Error msg].
- Requires: [input] to be a string. *)
diff --git a/2025/ocaml/lib/application/d03p01.ml b/2025/ocaml/lib/application/d03p01.ml
deleted file mode 100644
index 522f5d0..0000000
--- a/2025/ocaml/lib/application/d03p01.ml
+++ /dev/null
@@ -1,23 +0,0 @@
-open Domain.D03p01
-
-let err_empty_input = "input is empty"
-
-let to_lines s =
- s |> String.split_on_char '\n' |> List.map String.trim
- |> List.filter (fun l -> l <> "")
-
-let solve input () =
- if input = "" then Error err_empty_input
- else
- let answer =
- input |> to_lines |> List.to_seq
- |> Seq.map BatteryBank.of_string
- |> Seq.mapi (fun idx bb ->
- let joltage = BatteryBank.highest_joltage bb in
- Logs.debug (fun m ->
- m "%d line=%s highest_joltage=%d" (idx + 1) (BatteryBank.pp bb)
- joltage ) ;
- joltage )
- |> Seq.fold_left ( + ) 0
- in
- Ok answer
diff --git a/2025/ocaml/lib/application/d03p01.mli b/2025/ocaml/lib/application/d03p01.mli
deleted file mode 100644
index 31dd0cd..0000000
--- a/2025/ocaml/lib/application/d03p01.mli
+++ /dev/null
@@ -1,4 +0,0 @@
-val solve : string -> unit -> (int, string) result
-(** [solve input ()] is the solution for the first part of the third day of advent of code 2025 for [input].
- The solution for an empty input is [Error msg].
- Requires: [input] to be a string. *)
diff --git a/2025/ocaml/lib/application/d03p02.ml b/2025/ocaml/lib/application/d03p02.ml
deleted file mode 100644
index 743c658..0000000
--- a/2025/ocaml/lib/application/d03p02.ml
+++ /dev/null
@@ -1,23 +0,0 @@
-open Domain.D03p02
-
-let err_empty_input = "input is empty"
-
-let to_lines s =
- s |> String.split_on_char '\n' |> List.map String.trim
- |> List.filter (fun l -> l <> "")
-
-let solve input () =
- if input = "" then Error err_empty_input
- else
- let answer =
- input |> to_lines |> List.to_seq
- |> Seq.map BatteryBank.of_string
- |> Seq.mapi (fun idx bb ->
- let joltage = BatteryBank.highest_joltage bb in
- Logs.debug (fun m ->
- m "%d line=%s highest_joltage=%d" (idx + 1) (BatteryBank.pp bb)
- joltage ) ;
- joltage )
- |> Seq.fold_left ( + ) 0
- in
- Ok answer
diff --git a/2025/ocaml/lib/application/d03p02.mli b/2025/ocaml/lib/application/d03p02.mli
deleted file mode 100644
index 93d3b98..0000000
--- a/2025/ocaml/lib/application/d03p02.mli
+++ /dev/null
@@ -1,4 +0,0 @@
-val solve : string -> unit -> (int, string) result
-(** [solve input ()] is the solution for the second part of the third day of advent of code 2025 for [input].
- The solution for an empty input is [Error msg].
- Requires: [input] to be a string. *)
diff --git a/2025/ocaml/lib/application/d04p01.ml b/2025/ocaml/lib/application/d04p01.ml
deleted file mode 100644
index 7c69de4..0000000
--- a/2025/ocaml/lib/application/d04p01.ml
+++ /dev/null
@@ -1,48 +0,0 @@
-open Domain
-
-let err_empty_input = "input is empty"
-
-let rec solve input () =
- if input = "" then Error err_empty_input
- else
- let matrix = Matrix.M.of_string input in
- let count_paper lst = List.length @@ List.filter (fun c -> c <> ".") lst in
- let accessible_rolls_of_paper = ref 0 in
- for y = 0 to Array.length matrix - 1 do
- for x = 0 to Array.length matrix.(y) - 1 do
- if matrix.(y).(x) = "." then ()
- else
- let neighbour_coords = Matrix.M.get_valid_neighbours matrix x y in
- let neighbours =
- List.map
- (fun (x', y') -> Matrix.M.get matrix x' y')
- neighbour_coords
- in
- let paper_count = count_paper neighbours in
- let is_accessible = paper_count < 4 in
- if is_accessible then
- accessible_rolls_of_paper := !accessible_rolls_of_paper + 1 ;
- print_iteration_debug_msg x y neighbour_coords neighbours paper_count
- is_accessible
- done
- done ;
- Ok !accessible_rolls_of_paper
-
-and print_iteration_debug_msg x y neighbour_coords neighbours paper_count
- is_accessible =
- Logs.debug (fun m ->
- m
- "coords=(%d,%d) neighbour_coords=[%s] neighbours=[%s] paper=%d \
- is_accessible=%B"
- x y
- (List.fold_left
- (fun acc (x, y) ->
- if acc = "" then
- " (" ^ string_of_int x ^ "," ^ string_of_int y ^ "); "
- else acc ^ "(" ^ string_of_int x ^ "," ^ string_of_int y ^ "); " )
- "" neighbour_coords )
- (List.fold_left
- (fun acc neighbour ->
- if acc = "" then " " ^ neighbour ^ "; " else acc ^ neighbour ^ "; " )
- "" neighbours )
- paper_count is_accessible )
diff --git a/2025/ocaml/lib/application/d04p01.mli b/2025/ocaml/lib/application/d04p01.mli
deleted file mode 100644
index 873acff..0000000
--- a/2025/ocaml/lib/application/d04p01.mli
+++ /dev/null
@@ -1,4 +0,0 @@
-val solve : string -> unit -> (int, string) result
-(** [solve input ()] is the solution for the first part of the fourth day of advent of code 2025 for [input].
- The solution for an empty input is [Error msg].
- Requires: [input] to be a string. *)
diff --git a/2025/ocaml/lib/application/d04p02.ml b/2025/ocaml/lib/application/d04p02.ml
deleted file mode 100644
index 75b1236..0000000
--- a/2025/ocaml/lib/application/d04p02.ml
+++ /dev/null
@@ -1,64 +0,0 @@
-open Domain
-
-let err_empty_input = "input is empty"
-
-let rec count_accessible_rolls matrix =
- let count_paper lst = List.length @@ List.filter (fun c -> c = "@") lst in
- let accessible_rolls_of_paper = ref [] in
- let no_change = ref false in
- while not !no_change do
- let accessible_rolls_of_paper' = !accessible_rolls_of_paper in
- count_accessible_rolls_aux matrix count_paper accessible_rolls_of_paper ;
- if
- List.length accessible_rolls_of_paper'
- = List.length !accessible_rolls_of_paper
- then no_change := true
- done ;
- List.length !accessible_rolls_of_paper
-
-and count_accessible_rolls_aux matrix count_paper accessible_rolls_of_paper =
- for y = 0 to Array.length matrix - 1 do
- for x = 0 to Array.length matrix.(y) - 1 do
- if matrix.(y).(x) = "." then ()
- else
- let neighbour_coords = Matrix.M.get_valid_neighbours matrix x y in
- let neighbours =
- List.map (fun (nx, ny) -> Matrix.M.get matrix nx ny) neighbour_coords
- in
- let paper_count = count_paper neighbours in
- let is_accessible = paper_count < 4 in
- if is_accessible then
- accessible_rolls_of_paper := (x, y) :: !accessible_rolls_of_paper ;
- print_iteration_debug_msg x y neighbour_coords neighbours paper_count
- is_accessible
- done
- done ;
- List.iter
- (fun (x', y') -> Matrix.M.set matrix x' y' ".")
- !accessible_rolls_of_paper
-
-and print_iteration_debug_msg x y neighbour_coords neighbours paper_count
- is_accessible =
- Logs.debug (fun m ->
- m
- "coords=(%d,%d) neighbour_coords=[%s] neighbours=[%s] paper=%d \
- is_accessible=%B"
- x y
- (List.fold_left
- (fun acc (x, y) ->
- if acc = "" then
- " (" ^ string_of_int x ^ "," ^ string_of_int y ^ "); "
- else acc ^ "(" ^ string_of_int x ^ "," ^ string_of_int y ^ "); " )
- "" neighbour_coords )
- (List.fold_left
- (fun acc neighbour ->
- if acc = "" then " " ^ neighbour ^ "; " else acc ^ neighbour ^ "; " )
- "" neighbours )
- paper_count is_accessible )
-
-let solve input () =
- if input = "" then Error err_empty_input
- else
- let matrix = Matrix.M.of_string input in
- let accessible_rolls_of_paper = count_accessible_rolls matrix in
- Ok accessible_rolls_of_paper
diff --git a/2025/ocaml/lib/application/d04p02.mli b/2025/ocaml/lib/application/d04p02.mli
deleted file mode 100644
index 388ec56..0000000
--- a/2025/ocaml/lib/application/d04p02.mli
+++ /dev/null
@@ -1,4 +0,0 @@
-val solve : string -> unit -> (int, string) result
-(** [solve input ()] is the solution for the second part of the fourth day of advent of code 2025 for [input].
- The solution for an empty input is [Error msg].
- Requires: [input] to be a string. *)
diff --git a/2025/ocaml/lib/application/d05p01.ml b/2025/ocaml/lib/application/d05p01.ml
deleted file mode 100644
index 4bf79ab..0000000
--- a/2025/ocaml/lib/application/d05p01.ml
+++ /dev/null
@@ -1,3 +0,0 @@
-let err_empty_input = "input is empty"
-
-let solve input () = if input = "" then Error err_empty_input else Ok 0
diff --git a/2025/ocaml/lib/application/d05p01.mli b/2025/ocaml/lib/application/d05p01.mli
deleted file mode 100644
index 85c3dd5..0000000
--- a/2025/ocaml/lib/application/d05p01.mli
+++ /dev/null
@@ -1,4 +0,0 @@
-val solve : string -> unit -> (int, string) result
-(** [solve input ()] is the solution for the first part of the five day of advent of code 2025 for [input].
- The solution for an empty input is [Error msg].
- Requires: [input] to be a string. *)
diff --git a/2025/ocaml/lib/application/d06p01.ml b/2025/ocaml/lib/application/d06p01.ml
deleted file mode 100644
index 9425810..0000000
--- a/2025/ocaml/lib/application/d06p01.ml
+++ /dev/null
@@ -1,50 +0,0 @@
-let err_empty_input = "input is empty"
-
-let log_matrix matrix =
- let open Domain.Matrix in
- Logs.debug (fun m -> m "%s" (M.of_list matrix |> M.pp (fun elt -> elt)))
-
-let log_list lst =
- Logs.debug (fun m ->
- m "[%s]" (List.fold_left (fun acc i -> acc ^ i ^ "; ") " " lst) )
-
-type operation = Mult | Add
-
-let solve input () =
- if input = "" then Error err_empty_input
- else
- let input' = Parser.columns_of_string input in
- assert (input' <> []) ;
- log_matrix input' ;
- let nums =
- List.map (List.filter (fun i -> i <> "*" && i <> "+")) input'
- |> List.map
- @@ List.map (fun n ->
- Logs.debug (fun m -> m "peeking: %s" n) ;
- int_of_string n )
- and ops =
- List.map (List.filter (fun i -> i = "*" || i = "+")) input'
- |> List.concat
- |> List.map (fun op ->
- match op with
- | "*" ->
- Mult
- | "+" ->
- Add
- | _ ->
- failwith "case not covered" )
- in
- let answer =
- List.map2
- (fun op num_lst ->
- match op with
- | Add ->
- List.fold_left (fun acc i -> acc + i) 0 num_lst
- | Mult ->
- List.fold_left (fun acc i -> acc * i) 1 num_lst )
- ops nums
- |> fun lst ->
- log_list @@ List.map string_of_int lst ;
- lst |> List.fold_left ( + ) 0
- in
- Ok answer
diff --git a/2025/ocaml/lib/application/d06p01.mli b/2025/ocaml/lib/application/d06p01.mli
deleted file mode 100644
index b3abc1e..0000000
--- a/2025/ocaml/lib/application/d06p01.mli
+++ /dev/null
@@ -1,4 +0,0 @@
-val solve : string -> unit -> (int, string) result
-(** [solve input ()] is the solution for the first part of the sixth day of advent of code 2025 for [input].
- The solution for an empty input is [Error msg].
- Requires: [input] to be a string. *)
diff --git a/2025/ocaml/lib/application/d06p02.ml b/2025/ocaml/lib/application/d06p02.ml
deleted file mode 100644
index 9425810..0000000
--- a/2025/ocaml/lib/application/d06p02.ml
+++ /dev/null
@@ -1,50 +0,0 @@
-let err_empty_input = "input is empty"
-
-let log_matrix matrix =
- let open Domain.Matrix in
- Logs.debug (fun m -> m "%s" (M.of_list matrix |> M.pp (fun elt -> elt)))
-
-let log_list lst =
- Logs.debug (fun m ->
- m "[%s]" (List.fold_left (fun acc i -> acc ^ i ^ "; ") " " lst) )
-
-type operation = Mult | Add
-
-let solve input () =
- if input = "" then Error err_empty_input
- else
- let input' = Parser.columns_of_string input in
- assert (input' <> []) ;
- log_matrix input' ;
- let nums =
- List.map (List.filter (fun i -> i <> "*" && i <> "+")) input'
- |> List.map
- @@ List.map (fun n ->
- Logs.debug (fun m -> m "peeking: %s" n) ;
- int_of_string n )
- and ops =
- List.map (List.filter (fun i -> i = "*" || i = "+")) input'
- |> List.concat
- |> List.map (fun op ->
- match op with
- | "*" ->
- Mult
- | "+" ->
- Add
- | _ ->
- failwith "case not covered" )
- in
- let answer =
- List.map2
- (fun op num_lst ->
- match op with
- | Add ->
- List.fold_left (fun acc i -> acc + i) 0 num_lst
- | Mult ->
- List.fold_left (fun acc i -> acc * i) 1 num_lst )
- ops nums
- |> fun lst ->
- log_list @@ List.map string_of_int lst ;
- lst |> List.fold_left ( + ) 0
- in
- Ok answer
diff --git a/2025/ocaml/lib/application/d06p02.mli b/2025/ocaml/lib/application/d06p02.mli
deleted file mode 100644
index 49444de..0000000
--- a/2025/ocaml/lib/application/d06p02.mli
+++ /dev/null
@@ -1,4 +0,0 @@
-val solve : string -> unit -> (int, string) result
-(** [solve input ()] is the solution for the second part of the sixth day of advent of code 2025 for [input].
- The solution for an empty input is [Error msg].
- Requires: [input] to be a string. *)
diff --git a/2025/ocaml/lib/application/dune b/2025/ocaml/lib/application/dune
deleted file mode 100644
index b78613a..0000000
--- a/2025/ocaml/lib/application/dune
+++ /dev/null
@@ -1,14 +0,0 @@
-(library
- (name application)
- (libraries
- domain
- fmt
- logs)
- (inline_tests)
- (preprocess
- (pps
- ppx_deriving.show
- ppx_deriving.eq
- ppx_deriving.ord
- ppx_inline_test
- ppx_expect)))
diff --git a/2025/ocaml/lib/application/parser.ml b/2025/ocaml/lib/application/parser.ml
deleted file mode 100644
index 099900b..0000000
--- a/2025/ocaml/lib/application/parser.ml
+++ /dev/null
@@ -1,36 +0,0 @@
-(** [rows_of_string s] is a list of strings where each element is a row of [s]. *)
-let rows_of_string s =
- s |> String.split_on_char '\n'
- |> List.filter_map (fun l ->
- let trimmed = String.trim l in
- if trimmed <> "" then Some trimmed else None )
-
-(** [columns_of_string ?sep s] is a list of strings where each element is
- a column of [s] where each column is separated by [sep]. *)
-let rec columns_of_string ?(sep = ' ') s =
- rows_of_string s
- |> List.map (fun l ->
- l |> String.split_on_char sep |> List.filter (fun l -> l <> "") )
- |> transpose
-
-(** [group_columns lst] is a list where the first element of each
- sublist of [lst] is grouped in [acc] and so on for the rest of the elements.
- Example: [group_columns [] \[\["abc"; "def"\]; \["ghi"; "jkl"\]\]] is the list [\[\["abc";"ghi"\];\["def";"jkl"\]\]]. *)
-and transpose lst =
- assert (lst <> []) ;
- if List.mem [] lst then []
- else List.map List.hd lst :: transpose (List.map List.tl lst)
-
-let%expect_test "rows correctly parsed" =
- let have = {| abc def
- ghi jkl |} in
- let rows = rows_of_string have in
- List.iter (fun c -> print_string (c ^ " ")) rows ;
- [%expect {| abc def ghi jkl |}]
-
-let%expect_test "columns correctly parsed" =
- let have = {| abc def
- ghi jkl |} in
- let cols = columns_of_string have in
- List.iter (fun row -> List.iter (fun c -> print_string (c ^ " ")) row) cols ;
- [%expect {| abc ghi def jkl |}]
diff --git a/2025/ocaml/lib/domain/d01p01.ml b/2025/ocaml/lib/domain/d01p01.ml
deleted file mode 100644
index 6b531f4..0000000
--- a/2025/ocaml/lib/domain/d01p01.ml
+++ /dev/null
@@ -1,76 +0,0 @@
-module Dial : sig
- (** [t] is a dial between 0 and 99 inclusive *)
- type t
-
- (** [direction] is a direction the dial can be turned *)
- type direction = Left of int | Right of int
-
- val start : t
- (** [start] is the initial state of the dial *)
-
- val dial_out_of_range : string
- (** [dial_out_of_range] is the error message when the dial is out of range *)
-
- val turn : t -> direction -> t
- (** [turn current direction] is the new state of the dial after turning [direction] from [current] *)
-
- val to_string : t -> string
- (** [to_string t] is the string representation of [t] *)
-
- val to_int : t -> int
- (** [to_int t] is the integer representation of [t] *)
-
- val pp_direction : direction -> string
-end = struct
- (** [t] is an int between 0 and 99 inclusive *)
- type t = int
-
- type direction = Left of int | Right of int
-
- let start = 50
-
- let dial_out_of_range = "dial out of range"
-
- (** [next n] is the new state of the dial after turning [Right].
- Raises: [dial_out_of_range] if [n] is greater than 99. *)
- let next = function
- | n when n < 99 ->
- n + 1
- | 99 ->
- 0
- | _ ->
- failwith dial_out_of_range
-
- (** [prev n] is the new state of the dial after turning [Left].
- Raises: [dial_out_of_range] if [n] is less than 0. *)
- let prev = function
- | n when n > 0 ->
- n - 1
- | 0 ->
- 99
- | _ ->
- failwith dial_out_of_range
-
- (** [turn current direction] is the new state of the dial after turning [direction] from [current].
- Raises: [dial_out_of_range] if the dial is moved to an invalid state. *)
- let rec turn current direction =
- match direction with
- | Left 0 ->
- current
- | Left n ->
- turn (prev current) (Left (n - 1))
- | Right 0 ->
- current
- | Right n ->
- turn (next current) (Right (n - 1))
-
- let to_string = string_of_int
-
- let to_int t = t
-
- let pp_direction = function
- | Left n ->
- "Left " ^ string_of_int n
- | Right n ->
- "Right " ^ string_of_int n
-end
diff --git a/2025/ocaml/lib/domain/d01p02.ml b/2025/ocaml/lib/domain/d01p02.ml
deleted file mode 100644
index f71e965..0000000
--- a/2025/ocaml/lib/domain/d01p02.ml
+++ /dev/null
@@ -1,95 +0,0 @@
-module Dial : sig
- (** [t] is a dial between 0 and 99 inclusive *)
- type t
-
- (** [direction] is a direction the dial can be turned *)
- type direction = Left of int | Right of int
-
- val start : t
- (** [start] is the initial state of the dial *)
-
- val dial_out_of_range : string
- (** [dial_out_of_range] is the error message when the dial is out of range *)
-
- val prev : t -> t
-
- val next : t -> t
-
- val is_zero : t -> bool
-
- val to_string : t -> string
- (** [to_string t] is the string representation of [t] *)
-
- val to_int : t -> int
- (** [to_int t] is the integer representation of [t] *)
-
- val pp_direction : direction -> string
-end = struct
- (** [t] is an int between 0 and 99 inclusive *)
- type t = int
-
- type direction = Left of int | Right of int
-
- let start = 50
-
- let dial_out_of_range = "dial out of range"
-
- (** [next n] is the new state of the dial after turning [Right].
- Raises: [dial_out_of_range] if [n] is greater than 99. *)
- let next = function
- | n when n < 99 ->
- n + 1
- | 99 ->
- 0
- | _ ->
- failwith dial_out_of_range
-
- (** [prev n] is the new state of the dial after turning [Left].
- Raises: [dial_out_of_range] if [n] is less than 0. *)
- let prev = function
- | n when n > 0 ->
- n - 1
- | 0 ->
- 99
- | _ ->
- failwith dial_out_of_range
-
- let is_zero = function 0 -> true | _ -> false
-
- let to_string = string_of_int
-
- let to_int t = t
-
- let pp_direction = function
- | Left n ->
- "Left " ^ string_of_int n
- | Right n ->
- "Right " ^ string_of_int n
-end
-
-module Turner : sig
- val turn : Dial.t -> int -> Dial.direction -> Dial.t * int
- (** [turn dial direction] is the new state of the dial after turning [direction] on [dial] *)
-end = struct
- (** [turn dial direction] is the new state of the dial after turning [direction] on [dial].
- Raises: [dial_out_of_range] if the dial is moved to an invalid state. *)
- let rec turn dial zero_count direction =
- let open Dial in
- match direction with
- | Left 0 ->
- (dial, zero_count)
- | Left n ->
- let dial' = prev dial in
- let zero_count' =
- if Dial.is_zero dial' then zero_count + 1 else zero_count
- in
- turn dial' zero_count' (Left (n - 1))
- | Right 0 ->
- (dial, zero_count)
- | Right n ->
- let dial' = next dial in
- let zero_count' =
- if Dial.is_zero dial' then zero_count + 1 else zero_count
- in
- turn dial' zero_count' (Right (n - 1))
-end
diff --git a/2025/ocaml/lib/domain/d02p01.ml b/2025/ocaml/lib/domain/d02p01.ml
deleted file mode 100644
index 725d4b1..0000000
--- a/2025/ocaml/lib/domain/d02p01.ml
+++ /dev/null
@@ -1,33 +0,0 @@
-module ID = struct
- (** *)
- type t = int
-
- let create num = num
-
- let validate rules id = List.fold_left (fun acc r -> acc && r id) true rules
-
- let incr = ( + ) 1
-
- let to_int id = id
-
- let to_string = string_of_int
-
- let pp id = "ID=" ^ string_of_int id
-end
-
-module Range = struct
- type t = ID.t * ID.t
-
- let create (id1, id2) = (ID.create id1, ID.create id2)
-
- let rec collect range = collect_range_aux [] range
-
- and collect_range_aux lst (id1, id2) =
- match id1 <= id2 with
- | false ->
- lst
- | true ->
- collect_range_aux (id1 :: lst) (ID.incr id1, id2)
-
- let pp (id1, id2) = "(L" ^ ID.pp id1 ^ ", R" ^ ID.pp id2 ^ ")"
-end
diff --git a/2025/ocaml/lib/domain/d02p01.mli b/2025/ocaml/lib/domain/d02p01.mli
deleted file mode 100644
index 55665fe..0000000
--- a/2025/ocaml/lib/domain/d02p01.mli
+++ /dev/null
@@ -1,36 +0,0 @@
-module ID : sig
- (** [t] is a ID within a range *)
- type t
-
- val create : int -> t
- (** [create num] is an ID [t] *)
-
- val validate : (t -> bool) list -> t -> bool
- (** [validate rules id] is [true] if the [id] passes all rule checks *)
-
- val incr : t -> t
- (** [incr id] is the next [id] in the sequence *)
-
- val to_int : t -> int
- (** [to_int id] is an integer representation of [id] *)
-
- val to_string : t -> string
- (** [to_string id] is an string representation of [id] *)
-
- val pp : t -> string
- (** [pp id] is a pretty string representing [id] *)
-end
-
-module Range : sig
- (** [t] is a range of values *)
- type t
-
- val create : int * int -> t
- (** [create (s, e)] is a range starting at [s] and ending at [e]. *)
-
- val collect : t -> ID.t list
- (** [collect r] is a list containing all elements within the range (inclusive). *)
-
- val pp : t -> string
- (** [pp r] is a pretty string representing [r] *)
-end
diff --git a/2025/ocaml/lib/domain/d02p02.ml b/2025/ocaml/lib/domain/d02p02.ml
deleted file mode 100644
index b2b55f1..0000000
--- a/2025/ocaml/lib/domain/d02p02.ml
+++ /dev/null
@@ -1,29 +0,0 @@
-module ID = struct
- (** *)
- type t = int
-
- let create num = num
-
- let incr = ( + ) 1
-
- let to_string = string_of_int
-
- let pp id = "ID=" ^ string_of_int id
-end
-
-module Range = struct
- type t = ID.t * ID.t
-
- let create (id1, id2) = (ID.create id1, ID.create id2)
-
- let rec collect range = collect_range_aux [] range
-
- and collect_range_aux lst (id1, id2) =
- match id1 <= id2 with
- | false ->
- lst
- | true ->
- collect_range_aux (id1 :: lst) (ID.incr id1, id2)
-
- let pp (id1, id2) = "(L" ^ ID.pp id1 ^ ", R" ^ ID.pp id2 ^ ")"
-end
diff --git a/2025/ocaml/lib/domain/d02p02.mli b/2025/ocaml/lib/domain/d02p02.mli
deleted file mode 100644
index f918ae1..0000000
--- a/2025/ocaml/lib/domain/d02p02.mli
+++ /dev/null
@@ -1,30 +0,0 @@
-module ID : sig
- (** [t] is a ID within a range *)
- type t
-
- val create : int -> t
- (** [create num] is an ID [t] *)
-
- val incr : t -> t
- (** [incr id] is the next [id] in the sequence *)
-
- val to_string : t -> string
- (** [to_string id] is an string representation of [id] *)
-
- val pp : t -> string
- (** [pp id] is a pretty string representing [id] *)
-end
-
-module Range : sig
- (** [t] is a range of values *)
- type t
-
- val create : int * int -> t
- (** [create (s, e)] is a range starting at [s] and ending at [e]. *)
-
- val collect : t -> ID.t list
- (** [collect r] is a list containing all elements within the range (inclusive). *)
-
- val pp : t -> string
- (** [pp r] is a pretty string representing [r] *)
-end
diff --git a/2025/ocaml/lib/domain/d03p01.ml b/2025/ocaml/lib/domain/d03p01.ml
deleted file mode 100644
index 1367712..0000000
--- a/2025/ocaml/lib/domain/d03p01.ml
+++ /dev/null
@@ -1,114 +0,0 @@
-module Battery : sig
- type t
-
- val of_int : int -> t
-
- val to_int : t -> int
-
- val to_string : t -> string
-
- val compare : t -> t -> int
-
- val pp : t -> string
-end = struct
- type t = int
-
- let of_int i = i
-
- let to_int b = b
-
- let to_string = string_of_int
-
- let compare = Int.compare
-
- let pp = string_of_int
-end
-
-module BatteryBank : sig
- type t
-
- val highest_joltage : t -> int
- (** [highest_joltage bb] is an integer created from the two highest
- digits in [bb].
- Raises: [Assert_failure] if [bb] is empty. *)
-
- val of_string : string -> t
-
- val of_list : Battery.t list -> t
-
- val to_list : t -> Battery.t list
-
- val pp : t -> string
-end = struct
- type t = Battery.t list
-
- let rec highest_joltage bb =
- assert (List.length bb > 0) ;
- match highest_joltage_aux (None, None) bb with
- | None, None ->
- 0
- | Some x, Some y ->
- int_of_string (Battery.to_string x ^ Battery.to_string y)
- | _ ->
- failwith "highest_joltage must be two digits"
-
- and highest_joltage_aux acc = function
- | [] ->
- acc
- | [elt] -> (
- match acc with
- | None, None ->
- (Some (Battery.of_int 0), Some elt)
- | Some first, None ->
- (Some first, Some elt)
- | None, Some second ->
- (Some second, Some elt)
- | Some first, Some second ->
- if elt > second then (Some first, Some elt)
- else (Some first, Some second) )
- | h :: t ->
- highest_joltage_aux
- ( match acc with
- | None, None ->
- (Some h, None)
- | Some first, None ->
- let second = Battery.of_int 0 in
- swap_if_higher first second h
- | Some first, Some second ->
- swap_if_higher first second h
- | _ ->
- failwith "this branch should be impossible" )
- t
-
- and swap_if_higher first second considering =
- assert (first >= second) ;
- let c_gt_f = Battery.compare considering first = 1 in
- let c_gt_s = Battery.compare considering second = 1 in
- match (c_gt_f, c_gt_s) with
- | true, true ->
- (Some considering, None)
- | false, true ->
- (Some first, Some considering)
- | true, false ->
- failwith "[second] should never be greater than [first]"
- | false, false ->
- (Some first, Some second)
-
- let of_string s =
- s |> String.to_seq
- |> Seq.map (fun c -> Char.escaped c |> int_of_string |> Battery.of_int)
- |> List.of_seq
-
- let of_list lst = lst
-
- let to_list bb = bb
-
- let pp bb =
- "[ "
- ^ ( bb |> List.map Battery.pp
- |> List.fold_left
- (fun acc b ->
- if acc = "" then b ^ ";" else Printf.sprintf "%s %s;" acc b )
- "" )
- ^ " ]"
-end
diff --git a/2025/ocaml/lib/domain/d03p02.ml b/2025/ocaml/lib/domain/d03p02.ml
deleted file mode 100644
index 88257d0..0000000
--- a/2025/ocaml/lib/domain/d03p02.ml
+++ /dev/null
@@ -1,116 +0,0 @@
-module Battery : sig
- type t
-
- val of_int : int -> t
-
- val to_int : t -> int
-
- val to_string : t -> string
-
- val compare : t -> t -> int
-
- val pp : t -> string
-end = struct
- type t = int
-
- let of_int i = i
-
- let to_int b = b
-
- let to_string = string_of_int
-
- let compare = Int.compare
-
- let pp = string_of_int
-end
-
-module BatteryBank : sig
- type t
-
- val highest_joltage : t -> int
- (** [highest_joltage bb] is an integer created from the two highest
- digits in [bb].
- Raises: [Assert_failure] if [bb] is empty. *)
-
- val of_string : string -> t
-
- val of_list : Battery.t list -> t
-
- val to_list : t -> Battery.t list
-
- val pp : t -> string
-end = struct
- type t = Battery.t list
-
- type highest = {one: Battery.t option; two: Battery.t option}
-
- let rec highest_joltage bb =
- assert (List.length bb > 0) ;
- match highest_joltage_aux {one= None; two= None} bb with
- | {one= None; two= None} ->
- 0
- | {one= Some x; two= Some y} ->
- int_of_string (Battery.to_string x ^ Battery.to_string y)
- | _ ->
- failwith "highest_joltage must be two digits"
-
- and highest_joltage_aux acc = function
- | [] ->
- acc
- | [elt] -> (
- match acc with
- | {one= None; two= None} ->
- {one= Some (Battery.of_int 0); two= Some elt}
- | {one= Some first; two= None} ->
- {one= Some first; two= Some elt}
- | {one= None; two= Some second} ->
- {one= Some second; two= Some elt}
- | {one= Some first; two= Some second} ->
- if elt > second then {one= Some first; two= Some elt}
- else {one= Some first; two= Some second} )
- | h :: t ->
- highest_joltage_aux
- ( match acc with
- | {one= None; two= None} ->
- {one= Some h; two= None}
- | {one= Some first; two= None} ->
- let second = Battery.of_int 0 in
- swap_if_higher first second h
- | {one= Some first; two= Some second} ->
- swap_if_higher first second h
- | _ ->
- failwith "this branch should be impossible" )
- t
-
- and swap_if_higher first second considering =
- assert (first >= second) ;
- let c_gt_f = Battery.compare considering first = 1 in
- let c_gt_s = Battery.compare considering second = 1 in
- match (c_gt_f, c_gt_s) with
- | true, true ->
- {one= Some considering; two= None}
- | false, true ->
- {one= Some first; two= Some considering}
- | true, false ->
- failwith "[second] should never be greater than [first]"
- | false, false ->
- {one= Some first; two= Some second}
-
- let of_string s =
- s |> String.to_seq
- |> Seq.map (fun c -> Char.escaped c |> int_of_string |> Battery.of_int)
- |> List.of_seq
-
- let of_list lst = lst
-
- let to_list bb = bb
-
- let pp bb =
- "[ "
- ^ ( bb |> List.map Battery.pp
- |> List.fold_left
- (fun acc b ->
- if acc = "" then b ^ ";" else Printf.sprintf "%s %s;" acc b )
- "" )
- ^ " ]"
-end
diff --git a/2025/ocaml/lib/domain/dune b/2025/ocaml/lib/domain/dune
deleted file mode 100644
index 5b13d31..0000000
--- a/2025/ocaml/lib/domain/dune
+++ /dev/null
@@ -1,13 +0,0 @@
-(library
- (name domain)
- (inline_tests)
- (libraries
- fmt
- logs)
- (preprocess
- (pps
- ppx_deriving.show
- ppx_deriving.eq
- ppx_deriving.ord
- ppx_inline_test
- ppx_expect)))
diff --git a/2025/ocaml/lib/domain/matrix.ml b/2025/ocaml/lib/domain/matrix.ml
deleted file mode 100644
index fdf476f..0000000
--- a/2025/ocaml/lib/domain/matrix.ml
+++ /dev/null
@@ -1,196 +0,0 @@
-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
- (** [of_list lst] is a 2D array where every element in the array is an
- element corresponds to an element of the [lst]. *)
-
- val to_list : 'a t -> 'a list list
- (** [to_list matrix] is a 2D list where every element in the list is an
- element corresponds to an element of the [matrix]. *)
-
- 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)].
- Requires: [x] and [y] are positive integers or 0. *)
-
- val set : 'a t -> int -> int -> 'a -> unit
- (** [set matrix x y v] is an alias for [matrix.(y).(x) <- v].
- Requires: [x] and [y] are positive integers or 0. *)
-
- val get_valid_neighbours : 'a t -> int -> int -> (int * int) list
- (** [get_valid_neighbours matrix x y] is a list of pairs in the format
- (x * y) that represent the valid surrounding positions of [matrix.(y).(x)].
- Requires: [x] and [y] are positive integers or 0. *)
-
- 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 to_list matrix = Array.to_list @@ Array.map Array.to_list matrix
-
- 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 set matrix x y v = matrix.(y).(x) <- v
-
- let get_valid_neighbours matrix x y =
- let potential_neighbours =
- [ (x - 1, y - 1)
- ; (x, y - 1)
- ; (x + 1, y - 1)
- ; (x - 1, y)
- ; (x + 1, y)
- ; (x - 1, y + 1)
- ; (x, y + 1)
- ; (x + 1, y + 1) ]
- in
- let min_x = 0 in
- let max_x = Array.length matrix.(y) - 1 in
- let min_y = 0 in
- let max_y = Array.length matrix - 1 in
- List.filter
- (fun (x, y) -> min_x <= x && x <= max_x && min_y <= y && y <= max_y)
- potential_neighbours
-
- 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
- col_acc ^ " " ^ row ^ "\n" )
- "\n" 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 "."]
diff --git a/2025/ocaml/lib/domain/range.ml b/2025/ocaml/lib/domain/range.ml
deleted file mode 100644
index a1bdc00..0000000
--- a/2025/ocaml/lib/domain/range.ml
+++ /dev/null
@@ -1,67 +0,0 @@
-module M : sig
- type t
-
- val of_string : string -> t option
- (** [of_string s] is a range of integers if [s] is a string in the form ["%d-%d"]
- or [None] otherwise. *)
-
- val collect : t -> int list
- (** [collect range] is a fully realised range as a list.
- Example: ["1-5" |> of_string |> collect] is the list [\[1;2;3;4;5\]].
- Example: ["5-1" |> of_string |> collect] is the list [\[5;4;3;2;1\]].*)
-
- val pp : t -> string
- (** [pp range] is a pretty-printed version of the range. *)
-end = struct
- type t = int * int
-
- let of_string s =
- Scanf.sscanf_opt s "%d-%d" (fun start finish -> (start, finish))
-
- let rec collect (start, finish) =
- let collected =
- match Int.compare start finish with
- | -1 ->
- collect_range_aux Int.succ ( > ) [] (start, finish)
- | 0 ->
- [start]
- | 1 ->
- collect_range_aux Int.pred ( < ) [] (start, finish)
- | _ ->
- assert false
- in
- List.rev collected
-
- and collect_range_aux fn cmp lst (start, finish) =
- if cmp start finish then lst
- else collect_range_aux fn cmp (start :: lst) (fn start, finish)
-
- let pp (start, finish) = string_of_int start ^ "-" ^ string_of_int finish
-end
-
-let%expect_test "incrementing range" =
- match M.of_string "1-5" with
- | None ->
- [%expect.unreachable]
- | Some range ->
- let collected = M.collect range in
- List.iter print_int collected ;
- [%expect "12345"]
-
-let%expect_test "decrementing range" =
- match M.of_string "5-1" with
- | None ->
- [%expect.unreachable]
- | Some range ->
- let collected = M.collect range in
- List.iter print_int collected ;
- [%expect "54321"]
-
-let%expect_test "one element range" =
- match M.of_string "1-1" with
- | None ->
- [%expect.unreachable]
- | Some range ->
- let collected = M.collect range in
- List.iter print_int collected ;
- [%expect "1"]
diff --git a/2025/ocaml/lib/infrastructure/dune b/2025/ocaml/lib/infrastructure/dune
deleted file mode 100644
index b9d250f..0000000
--- a/2025/ocaml/lib/infrastructure/dune
+++ /dev/null
@@ -1,15 +0,0 @@
-(library
- (name infrastructure)
- (libraries
- application
- domain
- fmt
- logs)
- (inline_tests)
- (preprocess
- (pps
- ppx_deriving.show
- ppx_deriving.eq
- ppx_deriving.ord
- ppx_inline_test
- ppx_expect)))
diff --git a/2025/ocaml/lib/infrastructure/file.ml b/2025/ocaml/lib/infrastructure/file.ml
deleted file mode 100644
index 3b49c01..0000000
--- a/2025/ocaml/lib/infrastructure/file.ml
+++ /dev/null
@@ -1,4 +0,0 @@
-let read filename =
- let chan = In_channel.open_text filename in
- let content = In_channel.input_all chan in
- In_channel.close chan ; content
diff --git a/2025/ocaml/lib/infrastructure/file.mli b/2025/ocaml/lib/infrastructure/file.mli
deleted file mode 100644
index 17d4495..0000000
--- a/2025/ocaml/lib/infrastructure/file.mli
+++ /dev/null
@@ -1,3 +0,0 @@
-val read : string -> string
-(** [read filename] is the contents of [filename] as a string.
- The empty string is returned if [filename] does not exist. *)
diff --git a/2025/ocaml/lib/presentation/cli.ml b/2025/ocaml/lib/presentation/cli.ml
deleted file mode 100644
index 7864e7f..0000000
--- a/2025/ocaml/lib/presentation/cli.ml
+++ /dev/null
@@ -1,62 +0,0 @@
-(* Business logic behind CLI *)
-
-let run_solver name solver filepath =
- let content = Infrastructure.File.read filepath in
- match solver content () with
- | Error msg ->
- Logs.app (fun m -> m "[%s] Err=%s" name msg)
- | Ok answer ->
- Logs.app (fun m -> m "[%s] ANSWER=%d" name answer)
-
-let run_day _ = function
- | 1 ->
- let filepath = "../_input/day_01.txt" in
- run_solver "D01P01" Application.D01p01.solve filepath ;
- run_solver "D01P02" Application.D01p02.solve filepath ;
- 0
- | 2 ->
- let filepath = "../_input/day_02.txt" in
- run_solver "D02P01" Application.D02p01.solve filepath ;
- run_solver "D02P02" Application.D02p02.solve filepath ;
- 0
- | 3 ->
- let filepath = "../_input/day_03.txt" in
- run_solver "D03P01" Application.D03p01.solve filepath ;
- run_solver "D03P02" Application.D03p02.solve filepath ;
- 0
- | 4 ->
- let filepath = "../_input/day_04.txt" in
- run_solver "D04P01" Application.D04p01.solve filepath ;
- run_solver "D04P02" Application.D04p02.solve filepath ;
- 0
- | 5 ->
- let filepath = "../_input/day_05.txt" in
- run_solver "D05P01" Application.D05p01.solve filepath ;
- 0
- | 6 ->
- let filepath = "../_input/day_06.txt" in
- run_solver "D06P01" Application.D06p01.solve filepath ;
- run_solver "D06P02" Application.D06p02.solve filepath ;
- 0
- | _ ->
- failwith "day not implemented"
-
-(* Command line interface *)
-
-open Cmdliner
-
-let setup_log style_renderer = Fmt_tty.setup_std_outputs ?style_renderer ()
-
-let setup_log_t = Term.(const setup_log $ Fmt_cli.style_renderer ())
-
-let day_arg =
- let doc = "Day to run. MUST be in range of 1-12." in
- Arg.(value & pos 0 int 1 & info [] ~docv:"DAY" ~doc)
-
-let day_t = Term.(const run_day $ setup_log_t $ day_arg)
-
-let cmd =
- let info = Cmd.info "aoc" ~version:"0.1.0" in
- Cmd.v info day_t
-
-let run () = Cmd.eval' cmd
diff --git a/2025/ocaml/lib/presentation/dune b/2025/ocaml/lib/presentation/dune
deleted file mode 100644
index ae1fcb1..0000000
--- a/2025/ocaml/lib/presentation/dune
+++ /dev/null
@@ -1,16 +0,0 @@
-(library
- (name presentation)
- (libraries
- application
- domain
- infrastructure
- cmdliner
- fmt.cli
- fmt.tty)
- (inline_tests)
- (preprocess
- (pps
- ppx_deriving.show
- ppx_deriving.eq
- ppx_deriving.ord
- ppx_expect)))