You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

91 lines
2.3 KiB
OCaml

(* Common util. Should probably put this in a module or something.. *)
let get_one_line file =
try Some (input_line file) with
End_of_file -> None
let get_lines file =
let rec input lines =
match get_one_line file with
Some line -> input (line :: lines)
| None -> List.rev lines
in input []
let read_file file =
let channel = open_in(file) in
get_lines channel
let explode s = (* convert a string to a list of chars *)
let rec exp i l =
if i < 0 then l else exp (i - 1) (s.[i] :: l) in
exp (String.length s - 1) []
let (<<) f g x = f(g(x))
let (>>) f g x = g(f(x))
let rec take n l = (* take the first n elements *)
match n with
| 0 -> []
| n ->
match l with
| [] -> []
| x :: xs -> x :: (take (n-1) xs)
let rec drop n l = (* drop the first n elemnts *)
match n with
| 0 -> l
| n -> drop (n-1) @@ List.tl l
let c2i = String.make 1 >> int_of_string
(* --- *)
type exp = Add of exp * exp | Mul of exp * exp | Num of int
let rec string_of_exp = function
| Num x -> string_of_int x
| Mul (a, b) -> Printf.sprintf "(%s * %s)" (string_of_exp a) (string_of_exp b)
| Add (a, b) -> Printf.sprintf "(%s + %s)" (string_of_exp a) (string_of_exp b)
let print_exp = print_string << string_of_exp
let print_exps = List.iter print_exp
let rec find_matching_paren count (x::xs) =
match x with
| '(' -> if count = 0 then 0 else 1 + find_matching_paren (count-1) xs
| ')' -> 1 + find_matching_paren (count+1) xs
| n -> 1 + find_matching_paren count xs
let read_exp line =
let line' = line
|> explode
|> List.filter (fun x -> x != ' ')
|> List.rev
in
let rec go stack = function
| [] -> List.hd stack
| '+' :: xs -> Add (List.hd stack, (go (List.tl stack) xs))
| '*' :: xs -> Mul (List.hd stack, (go (List.tl stack) xs))
| ')' :: xs ->
let matching = 1 + find_matching_paren 0 xs in
let sub = take matching xs in
let rest = drop matching xs in
go ((go [] sub)::stack) rest
| '(' :: xs -> List.hd stack
| num :: xs -> go ((Num (c2i num)) :: stack) xs
in
go [] line'
let rec eval = function
| Num a -> a
| Add (a, b) -> (eval a) + (eval b)
| Mul (a, b) -> (eval a) * (eval b)
let () =
let exps = read_file "day18.txt" |> List.map read_exp in
let values = List.map eval exps in
let sum = List.fold_left (+) 0 values in
print_int sum;