diff --git a/aoc2020.ml b/aoc2020.ml index 5d6d4ab..b2efebe 100644 --- a/aoc2020.ml +++ b/aoc2020.ml @@ -5,4 +5,4 @@ let days = [|Day1.main; Day2.main; Day3.main|] let _ = match Array.to_list Sys.argv with | _exename :: day :: args -> days.(int_of_string day - 1) args - | _ -> Usage.exit " args..." + | _ -> Misc.usage " args..." diff --git a/day1.ml b/day1.ml index 8350af9..a2b8b4b 100644 --- a/day1.ml +++ b/day1.ml @@ -1,13 +1,4 @@ -module IntSet = struct - include Set.Make(Int) - - let exists_opt (type a) (f: int -> a option) (set: t): a option = - let exception Found of a in - let f' x = Option.iter (fun x -> raise (Found x)) (f x) in - match iter f' set with - | exception Found x -> Some x - | _ -> None -end +module IntSet = Set_ext.Make(Int) let read_ints = Bracket.infile_lines ~line:int_of_string ~of_seq:IntSet.of_seq @@ -23,31 +14,18 @@ let rec find ?(target=2020) ~n set = Option.map (List.cons x) (find ~target:(target - x) ~n:(n - 1) set) in IntSet.exists_opt joined set -let print_result xs = - let res = List.fold_left ( * ) 1 xs in - let rec print_prod fmt = function - | [] -> Format.pp_print_text fmt "{}" - | [x] -> Format.fprintf fmt "%d" x - | x::xs -> Format.fprintf fmt "%d * %a" x print_prod xs in - Format.printf "%a = %d\n" print_prod xs res - - let main' n input = match find ~n (read_ints input) with - | Some xs -> print_result xs + | Some xs -> Misc.print_prod xs | None -> raise Not_found -let mains = [|main' 2; main' 3|] - -let main = function - | [part; input] -> mains.(int_of_string part - 1) input - | _ -> Usage.exit_default 1 +let main = Misc.main 1 [|main' 2; main' 3|] let%expect_test "part 1" = - mains.(0) "../../data/day1"; (* is this always the right path??? *) + main' 2 "../../data/day1"; (* is this always the right path??? *) [%expect{| 534 * 1486 = 793524 |}] let%expect_test "part 2" = - mains.(1) "../../data/day1"; + main' 3 "../../data/day1"; [%expect{| 71 * 686 * 1263 = 61515678 |}] diff --git a/day2.ml b/day2.ml index 4c3674c..dfba071 100644 --- a/day2.ml +++ b/day2.ml @@ -26,17 +26,13 @@ let main' ok input = Bracket.infile_iter_lines input ~line:parse_line ~iter:check; Printf.printf "%d out of %d ok\n" !count_ok !count_all -let mains = [|main' ok1; main' ok2|] - -let main = function - | [part; input] -> mains.(int_of_string part - 1) input - | _ -> Usage.exit_default 2 +let main = Misc.main 2 [|main' ok1; main' ok2|] let%expect_test "part 1" = - mains.(0) "../../data/day2"; + main' ok1 "../../data/day2"; [%expect{| 607 out of 1000 ok |}] let%expect_test "part 2" = - mains.(1) "../../data/day2"; + main' ok2 "../../data/day2"; [%expect{| 321 out of 1000 ok |}] diff --git a/day3.ml b/day3.ml index 5530f03..e326a9e 100644 --- a/day3.ml +++ b/day3.ml @@ -36,19 +36,14 @@ let main1 input = let main2 input = let map = read_file input in - let prod = List.fold_left ( * ) 1 + Misc.print_prod [count_trees map; count_trees map ~step_y:3; count_trees map ~step_y:5; count_trees map ~step_y:7; - count_trees map ~step_x:2] in - Format.printf "product: %d\n" prod + count_trees map ~step_x:2] -let mains = [|main1; main2|] - -let main = function - | [part; input] -> mains.(int_of_string part - 1) input - | _ -> Usage.exit_default 3 +let main = Misc.main 3 [|main1; main2|] let%expect_test _ = main1 "../../data/day3"; @@ -56,4 +51,4 @@ let%expect_test _ = let%expect_test _ = main2 "../../data/day3"; - [%expect{| product: 9406609920 |}] + [%expect{| 90 * 244 * 97 * 92 * 48 = 9406609920 |}] diff --git a/dune b/dune index 868d48e..5346368 100644 --- a/dune +++ b/dune @@ -7,4 +7,4 @@ (public_name aoc2020) (inline_tests) (modules (:standard \ aoc2020)) - (preprocess (pps ppx_expect))) + (preprocess (pps ppx_deriving.std ppx_expect))) diff --git a/misc.ml b/misc.ml new file mode 100644 index 0000000..206f5f6 --- /dev/null +++ b/misc.ml @@ -0,0 +1,31 @@ +let usage args = + let err = Format.sprintf "usage: %s %s" Sys.argv.(0) args in + print_endline err; + exit 1 + +let usage_default day = usage (string_of_int day ^ " ") + +let main day mains = function + | [part; input] -> mains.(int_of_string part - 1) input + | _ -> usage_default day + + +type 'a monoid = + {id: 'a; + op: 'a -> 'a -> 'a; + op_name: string; + pp: Format.formatter -> 'a -> unit} + +let mult = {id = 1; op = ( * ); op_name = "*"; pp = Format.pp_print_int} +let add = {id = 0; op = ( + ); op_name = "+"; pp = Format.pp_print_int} + +let print_fold mon xs = + let res = List.fold_left mon.op mon.id xs in + let rec go fmt = function + | [] -> Format.fprintf fmt "%a" mon.pp mon.id + | [x] -> Format.fprintf fmt "%a" mon.pp x + | x::xs -> Format.fprintf fmt "%a * %a" mon.pp x go xs in + Format.printf "%a = %a\n" go xs mon.pp res + +let print_prod = print_fold mult +let print_sum = print_fold add diff --git a/misc.mli b/misc.mli new file mode 100644 index 0000000..f13fa86 --- /dev/null +++ b/misc.mli @@ -0,0 +1,16 @@ +val usage: string -> 'a +val usage_default: int -> 'a + +val main: int -> (string -> unit) array -> string list -> unit + +type 'a monoid = + {id: 'a; + op: 'a -> 'a -> 'a; + op_name: string; + pp: Format.formatter -> 'a -> unit} +val mult: int monoid +val add: int monoid + +val print_fold: 'a monoid -> 'a list -> unit +val print_prod: int list -> unit +val print_sum: int list -> unit diff --git a/set_ext.ml b/set_ext.ml new file mode 100644 index 0000000..2920ad0 --- /dev/null +++ b/set_ext.ml @@ -0,0 +1,15 @@ +module type S = sig + include Set.S + val exists_opt: (elt -> 'a option) -> t -> 'a option +end + +module Make(Elt: Set.OrderedType) = struct + include Set.Make(Elt) + + let exists_opt (type a) (f: elt -> a option) set = + let exception Found of a in + let f' x = Option.iter (fun x -> raise (Found x)) (f x) in + match iter f' set with + | exception Found x -> Some x + | _ -> None +end diff --git a/set_ext.mli b/set_ext.mli new file mode 100644 index 0000000..7702815 --- /dev/null +++ b/set_ext.mli @@ -0,0 +1,8 @@ +module type S = sig + include Set.S + val exists_opt: (elt -> 'a option) -> t -> 'a option +end + +module Make(Elt: Set.OrderedType): S + with type elt = Elt.t + and type t = Set.Make(Elt).t diff --git a/usage.ml b/usage.ml deleted file mode 100644 index f572b7b..0000000 --- a/usage.ml +++ /dev/null @@ -1,6 +0,0 @@ -let exit args = - let err = Format.sprintf "usage: %s %s" Sys.argv.(0) args in - print_endline err; - exit 1 - -let exit_default day = exit (string_of_int day ^ " ")