Search code examples
ocaml

Fatal error: exception Invalid_argument("String.sub / Bytes.sub")


I am learning OCaml and working my way through the advent of code 2022.

But it seems that reading the input.txt file is causing some issue.

A X
B Y
C Z

I am getting this strange error, that comes from the func score. Particularly the expression call scorer hd. Though, when I manually set the lines variable to a list string, everything works.

The error occurs here inside the func scorer:

    | hd :: tail -> score_helper tail scorer (scorer hd + acc)
let read_lines filename =
  let contents = In_channel.with_open_bin filename In_channel.input_all in
  String.split_on_char '\n' contents

let lines = read_lines "input.txt"

let score input scorer =
  let rec score_helper input scorer acc =
    match input with
    | [] -> acc
    | hd :: tail -> score_helper tail scorer (scorer hd + acc)
  in
  score_helper input scorer 0

(* Gets called on every row, returns the score value *)
let scorer s =
  let theirs =
    match String.sub s 0 1 with
    | "A" -> "X"
    | "B" -> "Y"
    | "C" -> "Z"
    | _ -> assert false
  in
  let ours = String.sub s 2 1 in
  let played =
    match ours with "X" -> 1 | "Y" -> 2 | "Z" -> 3 | _ -> assert false
  in
  let result =
    match (theirs, ours) with
    | "X", "Y" | "Y", "Z" | "Z", "X" -> 6
    | theirs, ours when theirs = ours -> 3
    | _ -> 0
  in
  played + result

let () = Format.sprintf "Part 1: %d" (score lines scorer) |> print_endline


Solution

  • The problem is revealed by inspecting lines:

    # lines;;
    - : string list = ["A X"; "B Y"; "C Z"; ""]
    #
    

    Note the last element: ""! You most likely want to ignore this empty line.

    A simple way to handle this case is to ignore this blank lines in the score function:

    let score input scorer =
      let rec score_helper input scorer acc =
        match input with
        | [] -> acc
        | "" :: tail -> score_helper tail scorer acc
        | hd :: tail -> score_helper tail scorer (scorer hd + acc)
      in
      score_helper input scorer 0