From 6d8fb621d1e93b83786890d6d9cb6f0d8defa8ae Mon Sep 17 00:00:00 2001 From: DJ O'Leary Date: Fri, 26 Jun 2026 18:04:09 +0200 Subject: refactor!: invert repo directory structure now is language first --- 2025/ocaml/lib/application/d01p01.ml | 53 --------- 2025/ocaml/lib/application/d01p01.mli | 4 - 2025/ocaml/lib/application/d01p02.ml | 55 --------- 2025/ocaml/lib/application/d01p02.mli | 4 - 2025/ocaml/lib/application/d02p01.ml | 54 --------- 2025/ocaml/lib/application/d02p01.mli | 4 - 2025/ocaml/lib/application/d02p02.ml | 86 --------------- 2025/ocaml/lib/application/d02p02.mli | 4 - 2025/ocaml/lib/application/d03p01.ml | 23 ---- 2025/ocaml/lib/application/d03p01.mli | 4 - 2025/ocaml/lib/application/d03p02.ml | 23 ---- 2025/ocaml/lib/application/d03p02.mli | 4 - 2025/ocaml/lib/application/d04p01.ml | 48 -------- 2025/ocaml/lib/application/d04p01.mli | 4 - 2025/ocaml/lib/application/d04p02.ml | 64 ----------- 2025/ocaml/lib/application/d04p02.mli | 4 - 2025/ocaml/lib/application/d05p01.ml | 3 - 2025/ocaml/lib/application/d05p01.mli | 4 - 2025/ocaml/lib/application/d06p01.ml | 50 --------- 2025/ocaml/lib/application/d06p01.mli | 4 - 2025/ocaml/lib/application/d06p02.ml | 50 --------- 2025/ocaml/lib/application/d06p02.mli | 4 - 2025/ocaml/lib/application/dune | 14 --- 2025/ocaml/lib/application/parser.ml | 36 ------ 2025/ocaml/lib/domain/d01p01.ml | 76 ------------- 2025/ocaml/lib/domain/d01p02.ml | 95 ---------------- 2025/ocaml/lib/domain/d02p01.ml | 33 ------ 2025/ocaml/lib/domain/d02p01.mli | 36 ------ 2025/ocaml/lib/domain/d02p02.ml | 29 ----- 2025/ocaml/lib/domain/d02p02.mli | 30 ----- 2025/ocaml/lib/domain/d03p01.ml | 114 ------------------- 2025/ocaml/lib/domain/d03p02.ml | 116 ------------------- 2025/ocaml/lib/domain/dune | 13 --- 2025/ocaml/lib/domain/matrix.ml | 196 --------------------------------- 2025/ocaml/lib/domain/range.ml | 67 ----------- 2025/ocaml/lib/infrastructure/dune | 15 --- 2025/ocaml/lib/infrastructure/file.ml | 4 - 2025/ocaml/lib/infrastructure/file.mli | 3 - 2025/ocaml/lib/presentation/cli.ml | 62 ----------- 2025/ocaml/lib/presentation/dune | 16 --- 40 files changed, 1508 deletions(-) delete mode 100644 2025/ocaml/lib/application/d01p01.ml delete mode 100644 2025/ocaml/lib/application/d01p01.mli delete mode 100644 2025/ocaml/lib/application/d01p02.ml delete mode 100644 2025/ocaml/lib/application/d01p02.mli delete mode 100644 2025/ocaml/lib/application/d02p01.ml delete mode 100644 2025/ocaml/lib/application/d02p01.mli delete mode 100644 2025/ocaml/lib/application/d02p02.ml delete mode 100644 2025/ocaml/lib/application/d02p02.mli delete mode 100644 2025/ocaml/lib/application/d03p01.ml delete mode 100644 2025/ocaml/lib/application/d03p01.mli delete mode 100644 2025/ocaml/lib/application/d03p02.ml delete mode 100644 2025/ocaml/lib/application/d03p02.mli delete mode 100644 2025/ocaml/lib/application/d04p01.ml delete mode 100644 2025/ocaml/lib/application/d04p01.mli delete mode 100644 2025/ocaml/lib/application/d04p02.ml delete mode 100644 2025/ocaml/lib/application/d04p02.mli delete mode 100644 2025/ocaml/lib/application/d05p01.ml delete mode 100644 2025/ocaml/lib/application/d05p01.mli delete mode 100644 2025/ocaml/lib/application/d06p01.ml delete mode 100644 2025/ocaml/lib/application/d06p01.mli delete mode 100644 2025/ocaml/lib/application/d06p02.ml delete mode 100644 2025/ocaml/lib/application/d06p02.mli delete mode 100644 2025/ocaml/lib/application/dune delete mode 100644 2025/ocaml/lib/application/parser.ml delete mode 100644 2025/ocaml/lib/domain/d01p01.ml delete mode 100644 2025/ocaml/lib/domain/d01p02.ml delete mode 100644 2025/ocaml/lib/domain/d02p01.ml delete mode 100644 2025/ocaml/lib/domain/d02p01.mli delete mode 100644 2025/ocaml/lib/domain/d02p02.ml delete mode 100644 2025/ocaml/lib/domain/d02p02.mli delete mode 100644 2025/ocaml/lib/domain/d03p01.ml delete mode 100644 2025/ocaml/lib/domain/d03p02.ml delete mode 100644 2025/ocaml/lib/domain/dune delete mode 100644 2025/ocaml/lib/domain/matrix.ml delete mode 100644 2025/ocaml/lib/domain/range.ml delete mode 100644 2025/ocaml/lib/infrastructure/dune delete mode 100644 2025/ocaml/lib/infrastructure/file.ml delete mode 100644 2025/ocaml/lib/infrastructure/file.mli delete mode 100644 2025/ocaml/lib/presentation/cli.ml delete mode 100644 2025/ocaml/lib/presentation/dune (limited to '2025/ocaml/lib') 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))) -- cgit v1.2.3