summaryrefslogtreecommitdiff
path: root/ocaml/lib/year2025/day03/part02
diff options
context:
space:
mode:
Diffstat (limited to 'ocaml/lib/year2025/day03/part02')
-rw-r--r--ocaml/lib/year2025/day03/part02/battery.ml25
-rw-r--r--ocaml/lib/year2025/day03/part02/battery.mli13
-rw-r--r--ocaml/lib/year2025/day03/part02/battery_bank.ml77
-rw-r--r--ocaml/lib/year2025/day03/part02/battery_bank.mli18
-rw-r--r--ocaml/lib/year2025/day03/part02/solver.ml23
-rw-r--r--ocaml/lib/year2025/day03/part02/solver.mli4
6 files changed, 160 insertions, 0 deletions
diff --git a/ocaml/lib/year2025/day03/part02/battery.ml b/ocaml/lib/year2025/day03/part02/battery.ml
new file mode 100644
index 0000000..e8f0443
--- /dev/null
+++ b/ocaml/lib/year2025/day03/part02/battery.ml
@@ -0,0 +1,25 @@
+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
diff --git a/ocaml/lib/year2025/day03/part02/battery.mli b/ocaml/lib/year2025/day03/part02/battery.mli
new file mode 100644
index 0000000..e00940b
--- /dev/null
+++ b/ocaml/lib/year2025/day03/part02/battery.mli
@@ -0,0 +1,13 @@
+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
diff --git a/ocaml/lib/year2025/day03/part02/battery_bank.ml b/ocaml/lib/year2025/day03/part02/battery_bank.ml
new file mode 100644
index 0000000..d7dc213
--- /dev/null
+++ b/ocaml/lib/year2025/day03/part02/battery_bank.ml
@@ -0,0 +1,77 @@
+open Battery
+
+module BatteryBank = 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/ocaml/lib/year2025/day03/part02/battery_bank.mli b/ocaml/lib/year2025/day03/part02/battery_bank.mli
new file mode 100644
index 0000000..bffc4cb
--- /dev/null
+++ b/ocaml/lib/year2025/day03/part02/battery_bank.mli
@@ -0,0 +1,18 @@
+open Battery
+
+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
diff --git a/ocaml/lib/year2025/day03/part02/solver.ml b/ocaml/lib/year2025/day03/part02/solver.ml
new file mode 100644
index 0000000..4a06e83
--- /dev/null
+++ b/ocaml/lib/year2025/day03/part02/solver.ml
@@ -0,0 +1,23 @@
+open Battery_bank
+
+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/ocaml/lib/year2025/day03/part02/solver.mli b/ocaml/lib/year2025/day03/part02/solver.mli
new file mode 100644
index 0000000..93d3b98
--- /dev/null
+++ b/ocaml/lib/year2025/day03/part02/solver.mli
@@ -0,0 +1,4 @@
+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. *)