Mercurial > lbo > hg > aoc22
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