let add_t (a, b) (c, d) = (a + c, b + d) let two_to_pov x = int_of_float (2. ** (float_of_int x)) let seat_of_ticket ticket = let len = (String.length ticket) - 1 in let rec aux idx res s = let current = abs (len - idx - 3) in if idx < 0 then res else match s.[idx] with | 'B' -> aux (idx - 1) (add_t res (two_to_pov current, 0)) s | 'R' -> aux (idx - 1) (add_t res (0, two_to_pov (3 - current))) s | _ -> aux (idx - 1) res s in let (row, col) = aux len (0, 0) ticket in (row * 8) + col let try_read f = try Some (input_line f) with End_of_file -> None let part1 filename = let f = open_in filename in let rec loop max = match try_read f with | Some t -> let seat_id = seat_of_ticket t in if seat_id > max then loop seat_id else loop max | None -> close_in f; max in loop 0 let part2 filename = let f = open_in filename in let rec read_file_to_list l = match try_read f with | Some s -> read_file_to_list ((seat_of_ticket s) :: l) | None -> close_in f; l in let find (prev_id, bingo) seat_id = (seat_id, Option.fold ~none:(if seat_id = prev_id + 2 then Some (seat_id - 1) else None) ~some:(fun x -> Some x) bingo) in let (_, ticket_id) = read_file_to_list [] |> List.sort compare |> List.fold_left (find) (-1, None) in Option.get ticket_id let () = print_endline (string_of_int (part1 "day5.input")) let () = print_endline (string_of_int (part2 "day5.input"))