let parse_machine line_a line_b prize_pos = let re_ab = Str.regexp {|Button [AB]: X\+\([0-9]+\), Y\+\([0-9]+\)|} in let re_pos = Str.regexp {|Prize: X=\([0-9]+\), Y=\([0-9]+\)|} in let _ = Str.search_forward re_ab line_a 0 in let a = ( int_of_string (Str.matched_group 1 line_a), int_of_string (Str.matched_group 2 line_a) ) in let _ = Str.search_forward re_ab line_b 0 in let b = ( int_of_string (Str.matched_group 1 line_b), int_of_string (Str.matched_group 2 line_b) ) in let _ = Str.search_forward re_pos prize_pos 0 in let prize = ( int_of_string (Str.matched_group 1 prize_pos), int_of_string (Str.matched_group 2 prize_pos) ) in (a, b, prize) let parse_machines = let rec impl acc = function | "" :: t -> impl acc t | a :: b :: p :: t -> impl (parse_machine a b p :: acc) t | [] -> acc | _ -> failwith "parse_machines.impl" in impl [] let machines_of_file fname = Aoc.strings_of_file fname |> parse_machines (* We want to solve A * a.x + B * b.x = X and A * a.y + B * b.y = Y which is A * a.x / b.x + B = X / b.x A * a.y / b.y + B = Y / b.y A * (a.x / b.x - a.y / b.y) = X / b.x - Y / b.y A * (a.x * b.y - a.y * b.x) / b.x / b.y = X / b.x - Y / b.y A * (a.x * b.y - a.y * b.x) = X * b.y - Y * b.x A = (X * b.y - Y * b.x) / (a.x * by.y - a.y * b.x) (7870 * 37 - 6450 * 84) / (17 * 37 - 86 * 84) 80 - (8400 * 67 - 5400 * 22) / (94 * 67 - 34 * 22) a = (94, 34) b = (22, 67) p = (8400, 5400) [ a.x b.x ] [ A ] = [ X ] [ a.y b.y ] [ B ] [ Y ] *) let calc_tokens ((ax, ay), (bx, by), (x, y)) = let a_n = (x * by) - (y * bx) in let a_d = (ax * by) - (ay * bx) in Printf.printf "a = (%d, %d) b = (%d, %d) p = (%d, %d), a_n / a_d = %d / %d, mod = %d\n" ax ay bx by x y a_n a_d (a_n mod a_d); if a_n mod a_d <> 0 then None else if a_n / a_d <= 0 then None else let a = a_n / a_d in let b = (x - (ax * a)) / bx in Printf.printf " a = %d b = %d\n" a b; Some ((3 * a) + b) let part machines = List.map calc_tokens machines |> List.filter_map Fun.id |> List.fold_left ( + ) 0 let _ = Aoc.main machines_of_file [ (string_of_int, part) ]