diff options
-rw-r--r-- | aoc-2020-gleam/gleam.toml | 1 | ||||
-rw-r--r-- | aoc-2020-gleam/manifest.toml | 2 | ||||
-rw-r--r-- | aoc-2020-gleam/src/aoc_2020_gleam.gleam | 2 | ||||
-rw-r--r-- | aoc-2020-gleam/src/days/day10.gleam | 67 | ||||
-rw-r--r-- | aoc-2020-gleam/src/ext/pairx.gleam | 4 | ||||
-rw-r--r-- | aoc-2020-gleam/src/util/cache.gleam | 53 |
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 +} |