let matched_group_opt n s = try Some (Str.matched_group n s) with _ -> None let find_nums s = let r = Str.regexp {|mul(\([0-9][0-9]?[0-9]?\),\([0-9][0-9]?[0-9]?\))|} in let rec impl acc pos = try let _ = Str.search_forward r s pos in let p0 = Str.matched_group 0 s in let p1 = matched_group_opt 1 s in let p2 = matched_group_opt 2 s in impl ((p0, Option.map int_of_string p1, Option.map int_of_string p2) :: acc) (Str.match_end ()) with Not_found -> acc in impl [] 0 let nums_from_file fname = Aoc.strings_from_file fname |> List.map find_nums |> List.concat let mac acc a b = acc + (Option.value a ~default:0 * Option.value b ~default:0) let day2403a = List.fold_left (fun acc (_, a, b) -> mac acc a b) 0 let _ = Aoc.main nums_from_file [ (string_of_int, day2403a) ]