(** Type containing commands available in input *) type cmd = | Do (** Enable processing *) | Donot (** Disable processing *) | Mul of int * int (** Multiply two integers. *) (** [find_nums s] returns the list of instructions given in [s]. *) let cmds_of_string s = let r = Str.regexp {|do()\|don't()\|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 action = match Str.matched_group 0 s with | "do()" -> Do | "don't()" -> Donot | _ -> Mul ( int_of_string (Str.matched_group 1 s), int_of_string (Str.matched_group 2 s) ) in impl (action :: acc) (Str.match_end ()) with Not_found -> acc in List.rev (impl [] 0) let cmds_of_file fname = Aoc.strings_of_file fname |> List.map cmds_of_string |> List.concat (** [mac acc a b] returns [acc + a * b]. *) let mac acc = function Mul (a, b) -> acc + (a * b) | _ -> acc let day2403a = List.fold_left mac 0 let day2403b lst = let rec impl acc enabled = function | [] -> acc | Do :: t -> impl acc true t | Donot :: t -> impl acc false t | Mul (a, b) :: t -> if enabled then impl (acc + (a * b)) true t else impl acc false t in impl 0 true lst let _ = Aoc.main cmds_of_file [ (string_of_int, day2403a); (string_of_int, day2403b) ]