aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--aoc-2020-gleam/gleam.toml1
-rw-r--r--aoc-2020-gleam/manifest.toml2
-rw-r--r--aoc-2020-gleam/src/aoc_2020_gleam.gleam2
-rw-r--r--aoc-2020-gleam/src/days/day10.gleam67
-rw-r--r--aoc-2020-gleam/src/ext/pairx.gleam4
-rw-r--r--aoc-2020-gleam/src/util/cache.gleam53
6 files changed, 129 insertions, 0 deletions
diff --git a/aoc-2020-gleam/gleam.toml b/aoc-2020-gleam/gleam.toml
index cf6aa37..1ac9a67 100644
--- a/aoc-2020-gleam/gleam.toml
+++ b/aoc-2020-gleam/gleam.toml
@@ -5,3 +5,4 @@ description = "A Gleam project"
[dependencies]
gleam_stdlib = "~> 0.26"
gleam_erlang = "~> 0.17"
+gleam_otp = "~> 0.5"
diff --git a/aoc-2020-gleam/manifest.toml b/aoc-2020-gleam/manifest.toml
index e349bd0..fd44967 100644
--- a/aoc-2020-gleam/manifest.toml
+++ b/aoc-2020-gleam/manifest.toml
@@ -3,9 +3,11 @@
packages = [
{ name = "gleam_erlang", version = "0.18.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "C69F59D086AD50B80DE294FB0963550630971C9DC04E92B1F7AEEDD2C0BE226C" },
+ { name = "gleam_otp", version = "0.5.3", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "6E705B69464237353E0380AC8143BDB29A3F0BF6168755D5F2D6E55A34A8B077" },
{ name = "gleam_stdlib", version = "0.27.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "9DBDD21B48C654182CDD8AA15ACF85E8E74A0438583C68BD7EF08BE89F999C6F" },
]
[requirements]
gleam_erlang = "~> 0.17"
+gleam_otp = "~> 0.5"
gleam_stdlib = "~> 0.26"
diff --git a/aoc-2020-gleam/src/aoc_2020_gleam.gleam b/aoc-2020-gleam/src/aoc_2020_gleam.gleam
index bf3fb3c..6a58229 100644
--- a/aoc-2020-gleam/src/aoc_2020_gleam.gleam
+++ b/aoc-2020-gleam/src/aoc_2020_gleam.gleam
@@ -9,6 +9,7 @@ import days/day06
import days/day07
import days/day08
import days/day09
+import days/day10
pub fn main() -> Nil {
use day <- runner.with_day()
@@ -22,6 +23,7 @@ pub fn main() -> Nil {
7 -> day07.run()
8 -> day08.run()
9 -> day09.run()
+ 10 -> day10.run()
_ -> io.println("Day not found!")
}
}
diff --git a/aoc-2020-gleam/src/days/day10.gleam b/aoc-2020-gleam/src/days/day10.gleam
new file mode 100644
index 0000000..ea97ed0
--- /dev/null
+++ b/aoc-2020-gleam/src/days/day10.gleam
@@ -0,0 +1,67 @@
+import gleam/io
+import gleam/int
+import gleam/list
+import gleam/bool
+import ext/listx
+import ext/pairx
+import ext/genericx as genx
+import ext/resultx as resx
+import util/input_util
+import util/cache.{Cache}
+
+const outlet_joltage = 0
+
+const max_increase = 3
+
+fn process_adapters(numbers: List(Int)) -> List(Int) {
+ let numbers = list.sort(numbers, by: int.compare)
+
+ let device_joltage =
+ numbers
+ |> list.last
+ |> resx.assert_unwrap
+ |> int.add(max_increase)
+
+ list.flatten([[outlet_joltage], numbers, [device_joltage]])
+}
+
+fn part1(numbers: List(Int)) -> Int {
+ let adapters = process_adapters(numbers)
+ let diffs =
+ adapters
+ |> list.window_by_2
+ |> list.map(with: pairx.difference)
+
+ let ones = listx.count(diffs, satisfying: genx.equals(_, 1))
+ let threes = listx.count(diffs, satisfying: genx.equals(_, 3))
+ ones * threes
+}
+
+fn arrangements(number: Int, adapters: List(Int), cache: Cache(Int, Int)) -> Int {
+ use <- bool.guard(when: number == 0, return: 1)
+ use <- bool.guard(when: !list.contains(adapters, number), return: 0)
+ use <- cache.memoize(with: cache, this: number)
+
+ list.range(from: 1, to: max_increase)
+ |> list.map(with: fn(j) { arrangements(number - j, adapters, cache) })
+ |> int.sum
+}
+
+fn part2(numbers: List(Int)) -> Int {
+ let adapters = process_adapters(numbers)
+ let device_joltage = resx.assert_unwrap(list.last(adapters))
+ use cache <- cache.create()
+ arrangements(device_joltage, adapters, cache)
+}
+
+pub fn run() -> Nil {
+ let test = input_util.read_numbers("test10")
+ let assert 220 = part1(test)
+ let assert 19_208 = part2(test)
+
+ let input = input_util.read_numbers("day10")
+ io.debug(part1(input))
+ io.debug(part2(input))
+
+ Nil
+}
diff --git a/aoc-2020-gleam/src/ext/pairx.gleam b/aoc-2020-gleam/src/ext/pairx.gleam
new file mode 100644
index 0000000..c6b39df
--- /dev/null
+++ b/aoc-2020-gleam/src/ext/pairx.gleam
@@ -0,0 +1,4 @@
+pub fn difference(pair: #(Int, Int)) -> Int {
+ let #(first, second) = pair
+ second - first
+}
diff --git a/aoc-2020-gleam/src/util/cache.gleam b/aoc-2020-gleam/src/util/cache.gleam
new file mode 100644
index 0000000..e1eefd2
--- /dev/null
+++ b/aoc-2020-gleam/src/util/cache.gleam
@@ -0,0 +1,53 @@
+import gleam/map.{Map}
+import gleam/otp/actor.{Continue, Next, Stop}
+import gleam/erlang/process.{Normal, Subject}
+
+const timeout = 1000
+
+type Message(k, v) {
+ Shutdown
+ Get(key: k, client: Subject(Result(v, Nil)))
+ Set(key: k, value: v)
+}
+
+type Server(k, v) =
+ Subject(Message(k, v))
+
+fn handle_message(message: Message(k, v), dict: Map(k, v)) -> Next(Map(k, v)) {
+ case message {
+ Shutdown -> Stop(Normal)
+ Get(key, client) -> {
+ process.send(client, map.get(dict, key))
+ Continue(dict)
+ }
+ Set(key, value) -> Continue(map.insert(dict, key, value))
+ }
+}
+
+pub opaque type Cache(k, v) {
+ Cache(server: Server(k, v))
+}
+
+pub fn create(apply fun: fn(Cache(k, v)) -> t) -> t {
+ let assert Ok(server) = actor.start(map.new(), handle_message)
+ let result = fun(Cache(server))
+ process.send(server, Shutdown)
+ result
+}
+
+pub fn set(in cache: Cache(k, v), for key: k, insert value: v) -> Nil {
+ process.send(cache.server, Set(key, value))
+}
+
+pub fn get(from cache: Cache(k, v), fetch key: k) -> Result(v, Nil) {
+ process.call(cache.server, fn(c) { Get(key, c) }, timeout)
+}
+
+pub fn memoize(with cache: Cache(k, v), this key: k, apply fun: fn() -> v) -> v {
+ let result = case get(from: cache, fetch: key) {
+ Ok(value) -> value
+ Error(Nil) -> fun()
+ }
+ set(in: cache, for: key, insert: result)
+ result
+}