(* * SPDX-FileCopyrightText: Copyright 2025 Alexandre Jesus * * SPDX-License-Identifier: GPL-3.0-or-later *) let part1 ch = let ops, nums = In_channel.input_all ch |> String.trim |> String.split_on_char '\n' |> List.map (String.split_on_char ' ') |> List.map (List.filter (( <> ) "")) |> List.rev |> fun l -> (List.hd l, List.map (List.map int_of_string) (List.tl l)) in List.fold_left (fun acc l -> List.map2 (fun (r, op) v -> (op r v, op)) acc l) (List.map (fun o -> if o = "*" then (1, ( * )) else (0, ( + ))) ops) nums |> List.map fst |> List.fold_left ( + ) 0 |> Printf.printf "%d\n" let part2 ch = (* another option would be to tranpose the numbers, but I wanted to avoid it *) let parse_nums lines = let czero = Char.code '0' in let parse_digit c = if c = ' ' then None else Some (Char.code c - czero) in let rec fn nums line = match (nums, Seq.uncons line) with | [], None -> [] | nums, None -> nums | [], Some (v, tv) -> parse_digit v :: fn [] tv | n :: tn, Some (v, tv) -> ( match (n, parse_digit v) with | Some n, Some v -> Some ((n * 10) + v) :: fn tn tv | Some n, None -> Some n :: fn tn tv | None, Some v -> Some v :: fn tn tv | None, None -> None :: fn tn tv) in List.fold_left (fun acc line -> fn acc (String.to_seq line)) [] lines |> List.fold_left (fun acc n -> match n with | None -> [] :: acc | Some n -> (n :: List.hd acc) :: List.tl acc) [ [] ] |> List.filter (( <> ) []) |> List.rev in let parse_ops line = String.split_on_char ' ' line |> List.filter (( <> ) "") in let data = In_channel.input_all ch in let lines = data |> String.split_on_char '\n' |> List.filter (( <> ) "") in let rlines = List.rev lines in let ops = parse_ops (List.hd rlines) in let nums = parse_nums (List.rev (List.tl rlines)) in List.map2 (fun op nums -> if op = "*" then List.fold_left ( * ) 1 nums else List.fold_left ( + ) 0 nums) ops nums |> List.fold_left ( + ) 0 |> Printf.printf "%d\n"