changeset 33:00f7efc7934e

Initial commit for 2023 (day 01)
author Lewin Bormann <lbo@spheniscida.de>
date Sat, 02 Dec 2023 12:26:52 +0100
parents 05ddc45b4210
children 6f2c271c91da
files .hgignore 2023/.ocamlformat 2023/aoc23.opam 2023/bin/day01.ml 2023/bin/dune 2023/bin/main.ml 2023/day01.ml 2023/dune 2023/dune-project 2023/lib/dune 2023/test/aoc23.ml 2023/test/dune
diffstat 10 files changed, 191 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore	Sat Dec 02 12:26:52 2023 +0100
@@ -0,0 +1,1 @@
+.*/_build
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/2023/aoc23.opam	Sat Dec 02 12:26:52 2023 +0100
@@ -0,0 +1,34 @@
+# This file is generated by dune, edit dune-project instead
+opam-version: "2.0"
+synopsis: "A short synopsis"
+description: "A longer description"
+maintainer: ["Maintainer Name"]
+authors: ["Author Name"]
+license: "LICENSE"
+tags: ["topics" "to describe" "your" "project"]
+homepage: "https://github.com/username/reponame"
+doc: "https://url/to/documentation"
+bug-reports: "https://github.com/username/reponame/issues"
+depends: [
+  "ocaml"
+  "dune" {>= "3.10"}
+  "base"
+  "core"
+  "stdio"
+  "odoc" {with-doc}
+]
+build: [
+  ["dune" "subst"] {dev}
+  [
+    "dune"
+    "build"
+    "-p"
+    name
+    "-j"
+    jobs
+    "@install"
+    "@runtest" {with-test}
+    "@doc" {with-doc}
+  ]
+]
+dev-repo: "git+https://github.com/username/reponame.git"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/2023/bin/day01.ml	Sat Dec 02 12:26:52 2023 +0100
@@ -0,0 +1,1 @@
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/2023/bin/dune	Sat Dec 02 12:26:52 2023 +0100
@@ -0,0 +1,5 @@
+(executable
+ (public_name aoc23)
+ (name main)
+ (libraries aoc23))
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/2023/bin/main.ml	Sat Dec 02 12:26:52 2023 +0100
@@ -0,0 +1,1 @@
+let () = print_endline "Hello, World!"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/2023/day01.ml	Sat Dec 02 12:26:52 2023 +0100
@@ -0,0 +1,114 @@
+open Stdio
+open Base
+
+let input () = In_channel.stdin
+
+(* Part 1 *)
+module Part1 = struct
+  let calibration_value_of_string s =
+    let digits = String.filter s ~f:Char.is_digit in
+    let first, last = (String.prefix digits 1, String.suffix digits 1) in
+    Int.of_string (String.concat [ first; last ])
+
+  let process ch =
+    let f lines line = calibration_value_of_string line :: lines in
+    List.rev @@ In_channel.fold_lines ch ~init:[] ~f
+
+  let _part1 () =
+    let r = process (input ()) in
+    Out_channel.printf "%d\n" (List.fold ~init:0 ~f:( + ) r)
+end
+
+(* Part 2 *)
+
+module Part2 = struct
+  let folder ix acc x =
+    match (ix, acc, x) with
+    | ix, None, d ->
+        let i = Int.of_string_opt (String.of_char d) in
+        Option.map i ~f:(fun i -> (ix, i))
+    | _, Some d, _ -> Some d
+
+  let find_first_digit s = String.foldi ~init:None ~f:folder s
+
+  let find_last_digit s =
+    let%map.Option ix, v = find_first_digit (String.rev s) in
+    (String.length s - ix, v)
+
+  let digits =
+    [
+      (1, "one");
+      (2, "two");
+      (3, "three");
+      (4, "four");
+      (5, "five");
+      (6, "six");
+      (7, "seven");
+      (8, "eight");
+      (9, "nine");
+    ]
+
+  let count_seq (from : int) (upto : int) : int Sequence.t =
+    let f c =
+      if Int.equal c upto then None
+      else Some (c, if upto > from then c + 1 else c - 1)
+    in
+    Sequence.unfold ~init:from ~f
+
+  let find_number ~fwd s value number =
+    let ixs =
+      if fwd then count_seq 0 (String.length s)
+      else count_seq (String.length s - 1) 0
+    in
+    let check pos = String.is_substring_at s ~pos ~substring:number in
+    (Sequence.find ixs ~f:check, value)
+
+  let find_any_number ~fwd s =
+    let f (value, number) = find_number ~fwd s value number in
+    let found = List.map digits ~f in
+    let compare (ix1, _) (ix2, _) =
+      match (ix1, ix2) with
+      | Some a, Some b -> Int.compare a b * if fwd then 1 else -1
+      | Some _, None -> -1
+      | None, Some _ -> 1
+      | None, None -> 0
+    in
+    (* sort by index *)
+    let sorted = List.sort found ~compare in
+    match List.hd_exn sorted with Some ix, d -> Some (ix, d) | None, _ -> None
+
+  let handle line =
+    let maybe_first_dig = find_first_digit line in
+    let maybe_first_wrd = find_any_number ~fwd:true line in
+    let maybe_last_dig = find_last_digit line in
+    let maybe_last_wrd = find_any_number ~fwd:false line in
+    let match_num ~fwd (dig : (int * int) option) (wrd : (int * int) option) =
+      let se v =
+        Sexp.(
+          Option.sexp_of_t
+            (fun (a, b) ->
+              List [ Atom (Int.to_string a); Atom (Int.to_string b) ])
+            v)
+      in
+      let s = Sexp.to_string Sexp.(List [ se dig; se wrd ]) in
+      let () = Out_channel.printf "%s\n" s in
+      match (dig, wrd) with
+      | Some (ix1, d1), Some (ix2, d2) ->
+          if (fwd && ix1 < ix2) || ((not fwd) && ix1 > ix2) then d1 else d2
+      | Some (_, d), None | None, Some (_, d) -> d
+      | None, None -> assert false
+    in
+    let first_dig = match_num ~fwd:true maybe_first_dig maybe_first_wrd in
+    let last_dig = match_num ~fwd:false maybe_last_dig maybe_last_wrd in
+    (10 * first_dig) + last_dig
+
+  let process ch =
+    let f lines line = handle line :: lines in
+    List.rev @@ In_channel.fold_lines ch ~init:[] ~f
+
+  let part2 () =
+    let r = process In_channel.stdin in
+    Out_channel.printf "%d\n" (List.fold ~init:0 ~f:( + ) r)
+end
+
+let () = Part2.part2 ()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/2023/dune	Sat Dec 02 12:26:52 2023 +0100
@@ -0,0 +1,5 @@
+(executable
+ (name day01)
+ (libraries base core)
+ (preprocess (pps ppx_let))
+ )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/2023/dune-project	Sat Dec 02 12:26:52 2023 +0100
@@ -0,0 +1,26 @@
+(lang dune 3.10)
+
+(name aoc23)
+
+(generate_opam_files true)
+
+(source
+ (github username/reponame))
+
+(authors "Author Name")
+
+(maintainers "Maintainer Name")
+
+(license LICENSE)
+
+(documentation https://url/to/documentation)
+
+(package
+ (name aoc23)
+ (synopsis "A short synopsis")
+ (description "A longer description")
+ (depends ocaml dune base core stdio)
+ (tags
+  (topics "to describe" your project)))
+
+; See the complete stanza docs at https://dune.readthedocs.io/en/stable/dune-files.html#dune-project
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/2023/lib/dune	Sat Dec 02 12:26:52 2023 +0100
@@ -0,0 +1,2 @@
+(library
+ (name aoc23))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/2023/test/dune	Sat Dec 02 12:26:52 2023 +0100
@@ -0,0 +1,2 @@
+(test
+ (name aoc23))