open StdLabels

type t = int

let column_of_char = function
  | 'A' .. 'Z' as c -> Char.code c - (Char.code 'A' - 1)
  | 'a' .. 'z' as c -> Char.code c - (Char.code 'a' - 1)
  | c -> raise (Invalid_argument ("column: " ^ Char.escaped c))

let column_of_string : string -> int =
 fun s ->
  String.fold_left s ~init:0 ~f:(fun value c -> (value * 26) + column_of_char c)

(** Accumulate the remaining for the successives divisions in a list. *)
let rec _to_char ~b i =
  if i > 0 then
    let res = i mod 26 in
    let res = if res = 0 then 26 else res in

    let c = char_of_int @@ (res + 64) in
    (* The modulo is accumulated in the list head, which is the expected
       sequence *)
    let b = c :: b in

    _to_char ~b @@ ((i - res) / 26)
  else b

let column_to_string i =
  let res = _to_char ~b:[] i in
  List.to_seq res |> String.of_seq