let rec read_line in_chan =
  try
    let line = input_line in_chan in
    line :: read_line in_chan
  with End_of_file ->
    close_in in_chan;
    []

let char_list str = List.init (String.length str) (String.get str)

let read_file path = open_in path |> read_line |> List.map char_list

let is_closing ch = List.mem ch [')'; ']'; '}'; '>']

let is_pair o c =
  match (o, c) with
  | ('(', ')') -> true
  | ('[', ']') -> true
  | ('{', '}') -> true
  | ('<', '>') -> true
  | (_, _)     -> false

let rec rem_score stack points =
  let score ch =
    match ch with
    | '(' -> 1
    | '[' -> 2
    | '{' -> 3
    | '<' -> 4
    | _   -> 0
  in

  match stack with
  | [] -> points
  | x :: xs -> rem_score xs (points * 5 + (score x))

let err_score ch =
  match ch with
  | ')' -> 3
  | ']' -> 57
  | '}' -> 1197
  | '>' -> 25137
  | _   -> 0


let rec scores line stack error_score =
  match (line, stack) with
  | ([], _) -> (error_score, rem_score stack 0)
  | (x :: xs, y :: ys) when is_closing x ->
    if is_pair y x
    then scores xs ys error_score
    else scores xs ys (error_score + err_score x)
  | (x :: xs, _) ->
    scores xs (x :: stack) error_score