about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorbrian <brianmchu42@gmail.com>2023-12-03 21:54:01 -0800
committerbrian <brianmchu42@gmail.com>2023-12-03 21:54:01 -0800
commit7000f47b60b3fbdf90e2db12a363bbd1b2236b53 (patch)
tree13d9db09d3530f93d40afe1badf5da35c714a14d
downloadAdventOfCode2023-7000f47b60b3fbdf90e2db12a363bbd1b2236b53.tar.gz
add template for ocaml
-rw-r--r--.gitignore40
-rw-r--r--.ocamlformat6
-rw-r--r--README.md40
-rw-r--r--aoc.opam23
-rw-r--r--bin/dune4
-rw-r--r--bin/main.ml41
-rw-r--r--bin/utils.ml51
-rw-r--r--dune-project11
-rw-r--r--lib/day.ml21
-rw-r--r--lib/day1.ml24
-rw-r--r--lib/day10.ml24
-rw-r--r--lib/day11.ml24
-rw-r--r--lib/day12.ml24
-rw-r--r--lib/day13.ml24
-rw-r--r--lib/day14.ml24
-rw-r--r--lib/day15.ml24
-rw-r--r--lib/day16.ml24
-rw-r--r--lib/day17.ml24
-rw-r--r--lib/day18.ml24
-rw-r--r--lib/day19.ml24
-rw-r--r--lib/day2.ml24
-rw-r--r--lib/day20.ml24
-rw-r--r--lib/day21.ml24
-rw-r--r--lib/day22.ml24
-rw-r--r--lib/day23.ml24
-rw-r--r--lib/day24.ml24
-rw-r--r--lib/day25.ml24
-rw-r--r--lib/day3.ml24
-rw-r--r--lib/day4.ml24
-rw-r--r--lib/day5.ml24
-rw-r--r--lib/day6.ml24
-rw-r--r--lib/day7.ml24
-rw-r--r--lib/day8.ml24
-rw-r--r--lib/day9.ml24
-rw-r--r--lib/day_template.ml24
-rw-r--r--lib/dune6
-rw-r--r--lib/imports.ml10
37 files changed, 877 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..91af45c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,40 @@
+
+# Created by https://www.toptal.com/developers/gitignore/api/ocaml
+# Edit at https://www.toptal.com/developers/gitignore?templates=ocaml
+
+### OCaml ###
+*.annot
+*.cmo
+*.cma
+*.cmi
+*.a
+*.o
+*.cmx
+*.cmxs
+*.cmxa
+
+# ocamlbuild working directory
+_build/
+
+# ocamlbuild targets
+*.byte
+*.native
+
+# oasis generated files
+setup.data
+setup.log
+
+# Merlin configuring file for Vim and Emacs
+.merlin
+
+# Dune generated files
+*.install
+
+# Local OPAM switch
+_opam/
+
+# End of https://www.toptal.com/developers/gitignore/api/ocaml
+
+inputs
+
+.session
diff --git a/.ocamlformat b/.ocamlformat
new file mode 100644
index 0000000..0747dfb
--- /dev/null
+++ b/.ocamlformat
@@ -0,0 +1,6 @@
+profile = ocamlformat
+break-cases = fit
+margin = 77
+parse-docstrings = true
+wrap-comments = true
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..051e2e6
--- /dev/null
+++ b/README.md
@@ -0,0 +1,40 @@
+# Advent of code with OCaml
+
+## Getting started
+
+1. Create a repository using this template
+1. Install dependencies via `opam install . --deps-only`
+1. Put your session cookie into `.session`
+1. (Optional) Put the year into `.year` (e.g. 2022)
+
+## HowTo
+
+For each day, first specify a type `t` for the parsed input, and then
+there are 3 functions to implement:
+
+- `input : string -> t`, a function to parse the input into a user specified
+    type `t`
+- `part1 : t -> unit` and `part2 : t -> unit`, functions to execute both parts
+
+The functor `Day.Make` generates a function `run` to run the pipeline.
+
+```ocaml
+    val run : ?only_part1:bool -> ?only_part2:bool -> string -> unit
+```
+
+The main executable, `aoc`, can be invoked via
+
+```bash
+    dune exec aoc DAY
+```
+
+which will invoke the `run` function for that DAY, with input taken from
+`inputs` directory.
+If no input file is present, then the input file would be downloaded using your
+session cookie.
+
+If you want to test your program with the small example for the day, the
+easiest way is to put it the `example` in the template file.
+The expectation test can be invoked with `dune test`, and updated with `dune
+promote`, see more in [dune documentation on expectation
+tests](https://dune.readthedocs.io/en/stable/tests.html#inline-expectation-tests).
diff --git a/aoc.opam b/aoc.opam
new file mode 100644
index 0000000..ac6f22c
--- /dev/null
+++ b/aoc.opam
@@ -0,0 +1,23 @@
+# This file is generated by dune, edit dune-project instead
+opam-version: "2.0"
+depends: [
+  "dune" {>= "2.7"}
+  "cohttp-lwt-unix"
+  "lwt_ssl"
+  "ppx_expect"
+  "odoc" {with-doc}
+]
+build: [
+  ["dune" "subst"] {dev}
+  [
+    "dune"
+    "build"
+    "-p"
+    name
+    "-j"
+    jobs
+    "@install"
+    "@runtest" {with-test}
+    "@doc" {with-doc}
+  ]
+]
diff --git a/bin/dune b/bin/dune
new file mode 100644
index 0000000..7f1bcd1
--- /dev/null
+++ b/bin/dune
@@ -0,0 +1,4 @@
+(executable
+ (public_name aoc)
+ (name main)
+ (libraries cohttp-lwt-unix lwt_ssl aoc))
diff --git a/bin/main.ml b/bin/main.ml
new file mode 100644
index 0000000..8e36c28
--- /dev/null
+++ b/bin/main.ml
@@ -0,0 +1,41 @@
+open Aoc
+open Utils
+
+let () =
+  let args = Sys.argv in
+  let day = args.(1) in
+  let input_file = Printf.sprintf "inputs/%s.in" day in
+  if not @@ Caml.Sys.file_exists input_file then
+    download_input day input_file ;
+  let file = In_channel.open_text input_file in
+  let inputs = In_channel.input_all file in
+  let (module Day : Day.S) =
+    match day with
+    | "1" -> (module Day1)
+    | "2" -> (module Day2)
+    | "3" -> (module Day3)
+    | "4" -> (module Day4)
+    | "5" -> (module Day5)
+    | "6" -> (module Day6)
+    | "7" -> (module Day7)
+    | "8" -> (module Day8)
+    | "9" -> (module Day9)
+    | "10" -> (module Day10)
+    | "11" -> (module Day11)
+    | "12" -> (module Day12)
+    | "13" -> (module Day13)
+    | "14" -> (module Day14)
+    | "15" -> (module Day15)
+    | "16" -> (module Day16)
+    | "17" -> (module Day17)
+    | "18" -> (module Day18)
+    | "19" -> (module Day19)
+    | "20" -> (module Day20)
+    | "21" -> (module Day21)
+    | "22" -> (module Day22)
+    | "23" -> (module Day23)
+    | "24" -> (module Day24)
+    | "25" -> (module Day25)
+    | _ -> failwith "invalid day"
+  in
+  Day.run inputs ; In_channel.close file
diff --git a/bin/utils.ml b/bin/utils.ml
new file mode 100644
index 0000000..4f488f4
--- /dev/null
+++ b/bin/utils.ml
@@ -0,0 +1,51 @@
+open Unix
+open Lwt
+open Cohttp
+open Cohttp_lwt_unix
+
+let session_file = ".session"
+
+let year_file = ".year"
+
+let get_token () =
+  let file = In_channel.open_text session_file in
+  let token = In_channel.input_all file in
+  In_channel.close file ; String.trim token
+
+let get_year () =
+  if Caml.Sys.file_exists year_file then (
+    let file = In_channel.open_text year_file in
+    let year = In_channel.input_all file in
+    In_channel.close file ;
+    int_of_string (String.trim year) )
+  else
+    let time = time () in
+    let time = gmtime time in
+    time.tm_year + 1900
+
+let download_input day fn =
+  let year = get_year () in
+  let url =
+    Printf.sprintf "https://adventofcode.com/%d/day/%s/input" year day
+  in
+  let token = get_token () in
+  let headers = Header.init () in
+  let headers = Header.add headers "Cookie" ("session=" ^ token) in
+  let headers =
+    Header.add headers "User-Agent"
+      "github.com/fangyi-zhou/advent-of-code-ocaml-starter by \
+       me+aoc@fangyi.io"
+  in
+  let uri = Uri.of_string url in
+  let body =
+    Client.get ~headers uri
+    >>= fun (resp, body) ->
+    let code = resp |> Response.status |> Code.code_of_status in
+    if code = 200 then body |> Cohttp_lwt.Body.to_string
+    else failwith ("Unable to get data, status " ^ Int.to_string code)
+  in
+  let body = Lwt_main.run body in
+  let body = String.trim body in
+  let file = Out_channel.open_text fn in
+  Out_channel.output_string file body ;
+  Out_channel.close file
diff --git a/dune-project b/dune-project
new file mode 100644
index 0000000..b45f2ed
--- /dev/null
+++ b/dune-project
@@ -0,0 +1,11 @@
+(lang dune 2.7)
+(name aoc)
+(generate_opam_files true)
+(package
+  (name aoc)
+  (depends
+    cohttp-lwt-unix
+    lwt_ssl
+    ppx_expect
+  )
+)
diff --git a/lib/day.ml b/lib/day.ml
new file mode 100644
index 0000000..ae5a2bd
--- /dev/null
+++ b/lib/day.ml
@@ -0,0 +1,21 @@
+module type S = sig
+  val run : ?only_part1:bool -> ?only_part2:bool -> string -> unit
+end
+
+module type Impl = sig
+  type t
+
+  val parse : string -> t
+
+  val part1 : t -> unit
+
+  val part2 : t -> unit
+end
+
+module Make (Impl : Impl) : S = struct
+  let run ?(only_part1 = false) ?(only_part2 = false) inputs =
+    let parsed = Impl.parse inputs in
+    let () = if not only_part2 then Impl.part1 parsed in
+    let () = if not only_part1 then Impl.part2 parsed in
+    ()
+end
diff --git a/lib/day1.ml b/lib/day1.ml
new file mode 100644
index 0000000..5f433e2
--- /dev/null
+++ b/lib/day1.ml
@@ -0,0 +1,24 @@
+open! Imports
+
+module M = struct
+  (* Type to parse the input into *)
+  type t = unit
+
+  (* Parse the input to type t, invoked for both parts *)
+  let parse _inputs = ()
+
+  (* Run part 1 with parsed inputs *)
+  let part1 _ = ()
+
+  (* Run part 2 with parsed inputs *)
+  let part2 _ = ()
+end
+
+include M
+include Day.Make (M)
+
+(* Example input *)
+let example = ""
+
+(* Expect test for example input *)
+let%expect_test _ = run example ; [%expect {| |}]
diff --git a/lib/day10.ml b/lib/day10.ml
new file mode 100644
index 0000000..5f433e2
--- /dev/null
+++ b/lib/day10.ml
@@ -0,0 +1,24 @@
+open! Imports
+
+module M = struct
+  (* Type to parse the input into *)
+  type t = unit
+
+  (* Parse the input to type t, invoked for both parts *)
+  let parse _inputs = ()
+
+  (* Run part 1 with parsed inputs *)
+  let part1 _ = ()
+
+  (* Run part 2 with parsed inputs *)
+  let part2 _ = ()
+end
+
+include M
+include Day.Make (M)
+
+(* Example input *)
+let example = ""
+
+(* Expect test for example input *)
+let%expect_test _ = run example ; [%expect {| |}]
diff --git a/lib/day11.ml b/lib/day11.ml
new file mode 100644
index 0000000..5f433e2
--- /dev/null
+++ b/lib/day11.ml
@@ -0,0 +1,24 @@
+open! Imports
+
+module M = struct
+  (* Type to parse the input into *)
+  type t = unit
+
+  (* Parse the input to type t, invoked for both parts *)
+  let parse _inputs = ()
+
+  (* Run part 1 with parsed inputs *)
+  let part1 _ = ()
+
+  (* Run part 2 with parsed inputs *)
+  let part2 _ = ()
+end
+
+include M
+include Day.Make (M)
+
+(* Example input *)
+let example = ""
+
+(* Expect test for example input *)
+let%expect_test _ = run example ; [%expect {| |}]
diff --git a/lib/day12.ml b/lib/day12.ml
new file mode 100644
index 0000000..5f433e2
--- /dev/null
+++ b/lib/day12.ml
@@ -0,0 +1,24 @@
+open! Imports
+
+module M = struct
+  (* Type to parse the input into *)
+  type t = unit
+
+  (* Parse the input to type t, invoked for both parts *)
+  let parse _inputs = ()
+
+  (* Run part 1 with parsed inputs *)
+  let part1 _ = ()
+
+  (* Run part 2 with parsed inputs *)
+  let part2 _ = ()
+end
+
+include M
+include Day.Make (M)
+
+(* Example input *)
+let example = ""
+
+(* Expect test for example input *)
+let%expect_test _ = run example ; [%expect {| |}]
diff --git a/lib/day13.ml b/lib/day13.ml
new file mode 100644
index 0000000..5f433e2
--- /dev/null
+++ b/lib/day13.ml
@@ -0,0 +1,24 @@
+open! Imports
+
+module M = struct
+  (* Type to parse the input into *)
+  type t = unit
+
+  (* Parse the input to type t, invoked for both parts *)
+  let parse _inputs = ()
+
+  (* Run part 1 with parsed inputs *)
+  let part1 _ = ()
+
+  (* Run part 2 with parsed inputs *)
+  let part2 _ = ()
+end
+
+include M
+include Day.Make (M)
+
+(* Example input *)
+let example = ""
+
+(* Expect test for example input *)
+let%expect_test _ = run example ; [%expect {| |}]
diff --git a/lib/day14.ml b/lib/day14.ml
new file mode 100644
index 0000000..5f433e2
--- /dev/null
+++ b/lib/day14.ml
@@ -0,0 +1,24 @@
+open! Imports
+
+module M = struct
+  (* Type to parse the input into *)
+  type t = unit
+
+  (* Parse the input to type t, invoked for both parts *)
+  let parse _inputs = ()
+
+  (* Run part 1 with parsed inputs *)
+  let part1 _ = ()
+
+  (* Run part 2 with parsed inputs *)
+  let part2 _ = ()
+end
+
+include M
+include Day.Make (M)
+
+(* Example input *)
+let example = ""
+
+(* Expect test for example input *)
+let%expect_test _ = run example ; [%expect {| |}]
diff --git a/lib/day15.ml b/lib/day15.ml
new file mode 100644
index 0000000..5f433e2
--- /dev/null
+++ b/lib/day15.ml
@@ -0,0 +1,24 @@
+open! Imports
+
+module M = struct
+  (* Type to parse the input into *)
+  type t = unit
+
+  (* Parse the input to type t, invoked for both parts *)
+  let parse _inputs = ()
+
+  (* Run part 1 with parsed inputs *)
+  let part1 _ = ()
+
+  (* Run part 2 with parsed inputs *)
+  let part2 _ = ()
+end
+
+include M
+include Day.Make (M)
+
+(* Example input *)
+let example = ""
+
+(* Expect test for example input *)
+let%expect_test _ = run example ; [%expect {| |}]
diff --git a/lib/day16.ml b/lib/day16.ml
new file mode 100644
index 0000000..5f433e2
--- /dev/null
+++ b/lib/day16.ml
@@ -0,0 +1,24 @@
+open! Imports
+
+module M = struct
+  (* Type to parse the input into *)
+  type t = unit
+
+  (* Parse the input to type t, invoked for both parts *)
+  let parse _inputs = ()
+
+  (* Run part 1 with parsed inputs *)
+  let part1 _ = ()
+
+  (* Run part 2 with parsed inputs *)
+  let part2 _ = ()
+end
+
+include M
+include Day.Make (M)
+
+(* Example input *)
+let example = ""
+
+(* Expect test for example input *)
+let%expect_test _ = run example ; [%expect {| |}]
diff --git a/lib/day17.ml b/lib/day17.ml
new file mode 100644
index 0000000..5f433e2
--- /dev/null
+++ b/lib/day17.ml
@@ -0,0 +1,24 @@
+open! Imports
+
+module M = struct
+  (* Type to parse the input into *)
+  type t = unit
+
+  (* Parse the input to type t, invoked for both parts *)
+  let parse _inputs = ()
+
+  (* Run part 1 with parsed inputs *)
+  let part1 _ = ()
+
+  (* Run part 2 with parsed inputs *)
+  let part2 _ = ()
+end
+
+include M
+include Day.Make (M)
+
+(* Example input *)
+let example = ""
+
+(* Expect test for example input *)
+let%expect_test _ = run example ; [%expect {| |}]
diff --git a/lib/day18.ml b/lib/day18.ml
new file mode 100644
index 0000000..5f433e2
--- /dev/null
+++ b/lib/day18.ml
@@ -0,0 +1,24 @@
+open! Imports
+
+module M = struct
+  (* Type to parse the input into *)
+  type t = unit
+
+  (* Parse the input to type t, invoked for both parts *)
+  let parse _inputs = ()
+
+  (* Run part 1 with parsed inputs *)
+  let part1 _ = ()
+
+  (* Run part 2 with parsed inputs *)
+  let part2 _ = ()
+end
+
+include M
+include Day.Make (M)
+
+(* Example input *)
+let example = ""
+
+(* Expect test for example input *)
+let%expect_test _ = run example ; [%expect {| |}]
diff --git a/lib/day19.ml b/lib/day19.ml
new file mode 100644
index 0000000..5f433e2
--- /dev/null
+++ b/lib/day19.ml
@@ -0,0 +1,24 @@
+open! Imports
+
+module M = struct
+  (* Type to parse the input into *)
+  type t = unit
+
+  (* Parse the input to type t, invoked for both parts *)
+  let parse _inputs = ()
+
+  (* Run part 1 with parsed inputs *)
+  let part1 _ = ()
+
+  (* Run part 2 with parsed inputs *)
+  let part2 _ = ()
+end
+
+include M
+include Day.Make (M)
+
+(* Example input *)
+let example = ""
+
+(* Expect test for example input *)
+let%expect_test _ = run example ; [%expect {| |}]
diff --git a/lib/day2.ml b/lib/day2.ml
new file mode 100644
index 0000000..5f433e2
--- /dev/null
+++ b/lib/day2.ml
@@ -0,0 +1,24 @@
+open! Imports
+
+module M = struct
+  (* Type to parse the input into *)
+  type t = unit
+
+  (* Parse the input to type t, invoked for both parts *)
+  let parse _inputs = ()
+
+  (* Run part 1 with parsed inputs *)
+  let part1 _ = ()
+
+  (* Run part 2 with parsed inputs *)
+  let part2 _ = ()
+end
+
+include M
+include Day.Make (M)
+
+(* Example input *)
+let example = ""
+
+(* Expect test for example input *)
+let%expect_test _ = run example ; [%expect {| |}]
diff --git a/lib/day20.ml b/lib/day20.ml
new file mode 100644
index 0000000..5f433e2
--- /dev/null
+++ b/lib/day20.ml
@@ -0,0 +1,24 @@
+open! Imports
+
+module M = struct
+  (* Type to parse the input into *)
+  type t = unit
+
+  (* Parse the input to type t, invoked for both parts *)
+  let parse _inputs = ()
+
+  (* Run part 1 with parsed inputs *)
+  let part1 _ = ()
+
+  (* Run part 2 with parsed inputs *)
+  let part2 _ = ()
+end
+
+include M
+include Day.Make (M)
+
+(* Example input *)
+let example = ""
+
+(* Expect test for example input *)
+let%expect_test _ = run example ; [%expect {| |}]
diff --git a/lib/day21.ml b/lib/day21.ml
new file mode 100644
index 0000000..5f433e2
--- /dev/null
+++ b/lib/day21.ml
@@ -0,0 +1,24 @@
+open! Imports
+
+module M = struct
+  (* Type to parse the input into *)
+  type t = unit
+
+  (* Parse the input to type t, invoked for both parts *)
+  let parse _inputs = ()
+
+  (* Run part 1 with parsed inputs *)
+  let part1 _ = ()
+
+  (* Run part 2 with parsed inputs *)
+  let part2 _ = ()
+end
+
+include M
+include Day.Make (M)
+
+(* Example input *)
+let example = ""
+
+(* Expect test for example input *)
+let%expect_test _ = run example ; [%expect {| |}]
diff --git a/lib/day22.ml b/lib/day22.ml
new file mode 100644
index 0000000..5f433e2
--- /dev/null
+++ b/lib/day22.ml
@@ -0,0 +1,24 @@
+open! Imports
+
+module M = struct
+  (* Type to parse the input into *)
+  type t = unit
+
+  (* Parse the input to type t, invoked for both parts *)
+  let parse _inputs = ()
+
+  (* Run part 1 with parsed inputs *)
+  let part1 _ = ()
+
+  (* Run part 2 with parsed inputs *)
+  let part2 _ = ()
+end
+
+include M
+include Day.Make (M)
+
+(* Example input *)
+let example = ""
+
+(* Expect test for example input *)
+let%expect_test _ = run example ; [%expect {| |}]
diff --git a/lib/day23.ml b/lib/day23.ml
new file mode 100644
index 0000000..5f433e2
--- /dev/null
+++ b/lib/day23.ml
@@ -0,0 +1,24 @@
+open! Imports
+
+module M = struct
+  (* Type to parse the input into *)
+  type t = unit
+
+  (* Parse the input to type t, invoked for both parts *)
+  let parse _inputs = ()
+
+  (* Run part 1 with parsed inputs *)
+  let part1 _ = ()
+
+  (* Run part 2 with parsed inputs *)
+  let part2 _ = ()
+end
+
+include M
+include Day.Make (M)
+
+(* Example input *)
+let example = ""
+
+(* Expect test for example input *)
+let%expect_test _ = run example ; [%expect {| |}]
diff --git a/lib/day24.ml b/lib/day24.ml
new file mode 100644
index 0000000..5f433e2
--- /dev/null
+++ b/lib/day24.ml
@@ -0,0 +1,24 @@
+open! Imports
+
+module M = struct
+  (* Type to parse the input into *)
+  type t = unit
+
+  (* Parse the input to type t, invoked for both parts *)
+  let parse _inputs = ()
+
+  (* Run part 1 with parsed inputs *)
+  let part1 _ = ()
+
+  (* Run part 2 with parsed inputs *)
+  let part2 _ = ()
+end
+
+include M
+include Day.Make (M)
+
+(* Example input *)
+let example = ""
+
+(* Expect test for example input *)
+let%expect_test _ = run example ; [%expect {| |}]
diff --git a/lib/day25.ml b/lib/day25.ml
new file mode 100644
index 0000000..5f433e2
--- /dev/null
+++ b/lib/day25.ml
@@ -0,0 +1,24 @@
+open! Imports
+
+module M = struct
+  (* Type to parse the input into *)
+  type t = unit
+
+  (* Parse the input to type t, invoked for both parts *)
+  let parse _inputs = ()
+
+  (* Run part 1 with parsed inputs *)
+  let part1 _ = ()
+
+  (* Run part 2 with parsed inputs *)
+  let part2 _ = ()
+end
+
+include M
+include Day.Make (M)
+
+(* Example input *)
+let example = ""
+
+(* Expect test for example input *)
+let%expect_test _ = run example ; [%expect {| |}]
diff --git a/lib/day3.ml b/lib/day3.ml
new file mode 100644
index 0000000..5f433e2
--- /dev/null
+++ b/lib/day3.ml
@@ -0,0 +1,24 @@
+open! Imports
+
+module M = struct
+  (* Type to parse the input into *)
+  type t = unit
+
+  (* Parse the input to type t, invoked for both parts *)
+  let parse _inputs = ()
+
+  (* Run part 1 with parsed inputs *)
+  let part1 _ = ()
+
+  (* Run part 2 with parsed inputs *)
+  let part2 _ = ()
+end
+
+include M
+include Day.Make (M)
+
+(* Example input *)
+let example = ""
+
+(* Expect test for example input *)
+let%expect_test _ = run example ; [%expect {| |}]
diff --git a/lib/day4.ml b/lib/day4.ml
new file mode 100644
index 0000000..5f433e2
--- /dev/null
+++ b/lib/day4.ml
@@ -0,0 +1,24 @@
+open! Imports
+
+module M = struct
+  (* Type to parse the input into *)
+  type t = unit
+
+  (* Parse the input to type t, invoked for both parts *)
+  let parse _inputs = ()
+
+  (* Run part 1 with parsed inputs *)
+  let part1 _ = ()
+
+  (* Run part 2 with parsed inputs *)
+  let part2 _ = ()
+end
+
+include M
+include Day.Make (M)
+
+(* Example input *)
+let example = ""
+
+(* Expect test for example input *)
+let%expect_test _ = run example ; [%expect {| |}]
diff --git a/lib/day5.ml b/lib/day5.ml
new file mode 100644
index 0000000..5f433e2
--- /dev/null
+++ b/lib/day5.ml
@@ -0,0 +1,24 @@
+open! Imports
+
+module M = struct
+  (* Type to parse the input into *)
+  type t = unit
+
+  (* Parse the input to type t, invoked for both parts *)
+  let parse _inputs = ()
+
+  (* Run part 1 with parsed inputs *)
+  let part1 _ = ()
+
+  (* Run part 2 with parsed inputs *)
+  let part2 _ = ()
+end
+
+include M
+include Day.Make (M)
+
+(* Example input *)
+let example = ""
+
+(* Expect test for example input *)
+let%expect_test _ = run example ; [%expect {| |}]
diff --git a/lib/day6.ml b/lib/day6.ml
new file mode 100644
index 0000000..5f433e2
--- /dev/null
+++ b/lib/day6.ml
@@ -0,0 +1,24 @@
+open! Imports
+
+module M = struct
+  (* Type to parse the input into *)
+  type t = unit
+
+  (* Parse the input to type t, invoked for both parts *)
+  let parse _inputs = ()
+
+  (* Run part 1 with parsed inputs *)
+  let part1 _ = ()
+
+  (* Run part 2 with parsed inputs *)
+  let part2 _ = ()
+end
+
+include M
+include Day.Make (M)
+
+(* Example input *)
+let example = ""
+
+(* Expect test for example input *)
+let%expect_test _ = run example ; [%expect {| |}]
diff --git a/lib/day7.ml b/lib/day7.ml
new file mode 100644
index 0000000..5f433e2
--- /dev/null
+++ b/lib/day7.ml
@@ -0,0 +1,24 @@
+open! Imports
+
+module M = struct
+  (* Type to parse the input into *)
+  type t = unit
+
+  (* Parse the input to type t, invoked for both parts *)
+  let parse _inputs = ()
+
+  (* Run part 1 with parsed inputs *)
+  let part1 _ = ()
+
+  (* Run part 2 with parsed inputs *)
+  let part2 _ = ()
+end
+
+include M
+include Day.Make (M)
+
+(* Example input *)
+let example = ""
+
+(* Expect test for example input *)
+let%expect_test _ = run example ; [%expect {| |}]
diff --git a/lib/day8.ml b/lib/day8.ml
new file mode 100644
index 0000000..5f433e2
--- /dev/null
+++ b/lib/day8.ml
@@ -0,0 +1,24 @@
+open! Imports
+
+module M = struct
+  (* Type to parse the input into *)
+  type t = unit
+
+  (* Parse the input to type t, invoked for both parts *)
+  let parse _inputs = ()
+
+  (* Run part 1 with parsed inputs *)
+  let part1 _ = ()
+
+  (* Run part 2 with parsed inputs *)
+  let part2 _ = ()
+end
+
+include M
+include Day.Make (M)
+
+(* Example input *)
+let example = ""
+
+(* Expect test for example input *)
+let%expect_test _ = run example ; [%expect {| |}]
diff --git a/lib/day9.ml b/lib/day9.ml
new file mode 100644
index 0000000..5f433e2
--- /dev/null
+++ b/lib/day9.ml
@@ -0,0 +1,24 @@
+open! Imports
+
+module M = struct
+  (* Type to parse the input into *)
+  type t = unit
+
+  (* Parse the input to type t, invoked for both parts *)
+  let parse _inputs = ()
+
+  (* Run part 1 with parsed inputs *)
+  let part1 _ = ()
+
+  (* Run part 2 with parsed inputs *)
+  let part2 _ = ()
+end
+
+include M
+include Day.Make (M)
+
+(* Example input *)
+let example = ""
+
+(* Expect test for example input *)
+let%expect_test _ = run example ; [%expect {| |}]
diff --git a/lib/day_template.ml b/lib/day_template.ml
new file mode 100644
index 0000000..5f433e2
--- /dev/null
+++ b/lib/day_template.ml
@@ -0,0 +1,24 @@
+open! Imports
+
+module M = struct
+  (* Type to parse the input into *)
+  type t = unit
+
+  (* Parse the input to type t, invoked for both parts *)
+  let parse _inputs = ()
+
+  (* Run part 1 with parsed inputs *)
+  let part1 _ = ()
+
+  (* Run part 2 with parsed inputs *)
+  let part2 _ = ()
+end
+
+include M
+include Day.Make (M)
+
+(* Example input *)
+let example = ""
+
+(* Expect test for example input *)
+let%expect_test _ = run example ; [%expect {| |}]
diff --git a/lib/dune b/lib/dune
new file mode 100644
index 0000000..ec706b4
--- /dev/null
+++ b/lib/dune
@@ -0,0 +1,6 @@
+(library
+ (name aoc)
+ (inline_tests)
+ (libraries unix)
+ (preprocess
+  (pps ppx_expect)))
diff --git a/lib/imports.ml b/lib/imports.ml
new file mode 100644
index 0000000..6d1617d
--- /dev/null
+++ b/lib/imports.ml
@@ -0,0 +1,10 @@
+(* Anything helper functions that would be imported for each module *)
+
+let print_endline_int i = print_endline (Int.to_string i)
+
+let time f =
+  let before = Unix.gettimeofday () in
+  let result = f () in
+  let after = Unix.gettimeofday () in
+  print_endline (Printf.sprintf "%f" (after -. before)) ;
+  result