let year = 2023 let day = 1 module Part_1 = struct let run (input : string) : (string, string) result = let string_to_digits s = String.to_seq s |> Seq.map Char.escaped |> Seq.map int_of_string_opt |> Seq.flat_map Option.to_seq |> Seq.map Int.to_string |> List.of_seq in let rec concat_digits = function | [] -> 0 | [ x ] -> int_of_string (x ^ x) | [ first; last ] -> int_of_string (first ^ last) | first :: _ :: xs -> concat_digits (first :: xs) in let result = String.split_on_char '\n' input |> List.map string_to_digits |> List.map concat_digits |> List.fold_left ( + ) 0 |> Int.to_string in Ok result end module Part_2 = struct let run (input : string) : (string, string) result = let word_to_digit_list = [ ("one", "1"); ("two", "2"); ("three", "3"); ("four", "4"); ("five", "5"); ("six", "6"); ("seven", "7"); ("eight", "8"); ("nine", "9"); ("1", "1"); ("2", "2"); ("3", "3"); ("4", "4"); ("5", "5"); ("6", "6"); ("7", "7"); ("8", "8"); ("9", "9"); ] in let rec find_first_digit string = match List.find_opt (fun (word, _) -> String.starts_with ~prefix:word string) word_to_digit_list with | Some (_, digit) -> digit | None -> find_first_digit (String.sub string 1 (String.length string - 1)) in let rec find_last_digit string = match List.find_opt (fun (word, _) -> String.ends_with ~suffix:word string) word_to_digit_list with | Some (_, digit) -> digit | None -> find_last_digit (String.sub string 0 (String.length string - 1)) in let concat_digits s = let first = find_first_digit s in let last = find_last_digit s in int_of_string (first ^ last) in let result = input |> String.split_on_char '\n' |> List.filter (fun s -> String.length s > 0) |> List.map concat_digits |> List.fold_left ( + ) 0 |> Int.to_string in Ok result end