From ace0f38373873846957cf748247f07922145e14f Mon Sep 17 00:00:00 2001 From: Rupus Reinefjord <rupus@reinefjord.net> Date: Tue, 3 Dec 2024 00:06:46 +0100 Subject: [PATCH] day02 --- 2024/day02/.gitignore | 4 +++ 2024/day02/gleam.toml | 20 +++++++++++ 2024/day02/manifest.toml | 13 +++++++ 2024/day02/src/day02.gleam | 74 ++++++++++++++++++++++++++++++++++++++ 2024/day02/src/stdin.gleam | 24 +++++++++++++ 5 files changed, 135 insertions(+) create mode 100644 2024/day02/.gitignore create mode 100644 2024/day02/gleam.toml create mode 100644 2024/day02/manifest.toml create mode 100644 2024/day02/src/day02.gleam create mode 100644 2024/day02/src/stdin.gleam diff --git a/2024/day02/.gitignore b/2024/day02/.gitignore new file mode 100644 index 0000000..599be4e --- /dev/null +++ b/2024/day02/.gitignore @@ -0,0 +1,4 @@ +*.beam +*.ez +/build +erl_crash.dump diff --git a/2024/day02/gleam.toml b/2024/day02/gleam.toml new file mode 100644 index 0000000..448d48d --- /dev/null +++ b/2024/day02/gleam.toml @@ -0,0 +1,20 @@ +name = "day02" +version = "1.0.0" + +# Fill out these fields if you intend to generate HTML documentation or publish +# your project to the Hex package manager. +# +# description = "" +# licences = ["Apache-2.0"] +# repository = { type = "github", user = "", repo = "" } +# links = [{ title = "Website", href = "" }] +# +# For a full reference of all the available options, you can have a look at +# https://gleam.run/writing-gleam/gleam-toml/. + +[dependencies] +gleam_stdlib = ">= 0.34.0 and < 2.0.0" +gleam_yielder = ">= 1.1.0 and < 2.0.0" + +[dev-dependencies] +gleeunit = ">= 1.0.0 and < 2.0.0" diff --git a/2024/day02/manifest.toml b/2024/day02/manifest.toml new file mode 100644 index 0000000..0e33798 --- /dev/null +++ b/2024/day02/manifest.toml @@ -0,0 +1,13 @@ +# This file was generated by Gleam +# You typically do not need to edit this file + +packages = [ + { name = "gleam_stdlib", version = "0.45.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "206FCE1A76974AECFC55AEBCD0217D59EDE4E408C016E2CFCCC8FF51278F186E" }, + { name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" }, + { name = "gleeunit", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "F7A7228925D3EE7D0813C922E062BFD6D7E9310F0BEE585D3A42F3307E3CFD13" }, +] + +[requirements] +gleam_stdlib = { version = ">= 0.34.0 and < 2.0.0" } +gleam_yielder = { version = ">= 1.1.0 and < 2.0.0" } +gleeunit = { version = ">= 1.0.0 and < 2.0.0" } diff --git a/2024/day02/src/day02.gleam b/2024/day02/src/day02.gleam new file mode 100644 index 0000000..c87b60b --- /dev/null +++ b/2024/day02/src/day02.gleam @@ -0,0 +1,74 @@ +import gleam/bool +import gleam/int +import gleam/io +import gleam/list +import gleam/result +import gleam/string +import gleam/yielder +import stdin.{stdin} + +pub fn main() { + let reports = + stdin() + |> yielder.map(fn(line) { + let assert #(ints, []) = + string.trim_end(line) + |> string.split(" ") + |> list.map(int.parse) + |> result.partition + ints + }) + |> yielder.to_list + + part1(reports) + |> int.to_string + |> io.println + + part2(reports) + |> int.to_string + |> io.println +} + +fn part1(reports: List(List(Int))) -> Int { + list.map(reports, is_safe) + |> list.count(fn(x) { x }) +} + +fn part2(reports: List(List(Int))) { + let #(safe, unsafe) = list.partition(reports, is_safe) + let non_unsafe = + list.map(unsafe, fn(report) { + list.combinations(report, list.length(report) - 1) + |> until_true(is_safe) + }) + list.length(safe) + list.count(non_unsafe, fn(x) { x }) +} + +fn until_true(over list: List(a), with fun: fn(a) -> Bool) -> Bool { + case list { + [] -> False + [head] -> fun(head) + [head, ..tail] -> + case fun(head) { + True -> True + False -> until_true(tail, fun) + } + } +} + +fn is_safe(report: List(Int)) -> Bool { + list.window_by_2(report) + |> list.try_fold(0, fn(sum, window) { + let diff = window.1 - window.0 + case int.absolute_value(diff) { + x if x >= 1 && x <= 3 -> + case bool.exclusive_nor(sum > 0, diff > 0) { + True -> Ok(sum + diff) + False if sum == 0 -> Ok(sum + diff) + False -> Error(Nil) + } + _ -> Error(Nil) + } + }) + |> result.is_ok +} diff --git a/2024/day02/src/stdin.gleam b/2024/day02/src/stdin.gleam new file mode 100644 index 0000000..560c4ec --- /dev/null +++ b/2024/day02/src/stdin.gleam @@ -0,0 +1,24 @@ +import gleam/dynamic +import gleam/result +import gleam/yielder + +@external(erlang, "io", "get_line") +fn ffi_read_line(prompt: String) -> dynamic.Dynamic + +fn read_line() -> Result(String, Nil) { + ffi_read_line("") + |> dynamic.from() + |> dynamic.string() + |> result.replace_error(Nil) +} + +fn assert_upwrap(res: Result(a, _)) -> a { + let assert Ok(a) = res + a +} + +pub fn stdin() -> yielder.Yielder(String) { + yielder.repeatedly(read_line) + |> yielder.take_while(result.is_ok) + |> yielder.map(assert_upwrap) +}