aboutsummaryrefslogtreecommitdiff
path: root/aoc2023-gleam/src/utilities
diff options
context:
space:
mode:
authorJ.J <thechairman@thechairman.info>2024-05-30 21:49:58 -0400
committerJ.J <thechairman@thechairman.info>2024-05-30 21:49:58 -0400
commit231c2b688d1e6cf0846d46e883da30e042a9c6cf (patch)
tree98a6d3a461fe190b38b2cf33a708a1d01703fa70 /aoc2023-gleam/src/utilities
parentfe088aa5778dcdbaab4dd8d4a7395a91c444b45c (diff)
parenta2c2b728ec6051323ed937f54816089cd2ae9d20 (diff)
downloadgleam_aoc-231c2b688d1e6cf0846d46e883da30e042a9c6cf.tar.gz
gleam_aoc-231c2b688d1e6cf0846d46e883da30e042a9c6cf.zip
Merge branch 'main' of https://github.com/hunkyjimpjorps/AdventOfCode
Diffstat (limited to 'aoc2023-gleam/src/utilities')
-rw-r--r--aoc2023-gleam/src/utilities/array2d.gleam74
-rw-r--r--aoc2023-gleam/src/utilities/memo.gleam57
-rw-r--r--aoc2023-gleam/src/utilities/prioqueue.gleam64
3 files changed, 195 insertions, 0 deletions
diff --git a/aoc2023-gleam/src/utilities/array2d.gleam b/aoc2023-gleam/src/utilities/array2d.gleam
new file mode 100644
index 0000000..8538129
--- /dev/null
+++ b/aoc2023-gleam/src/utilities/array2d.gleam
@@ -0,0 +1,74 @@
+import gleam/list
+import gleam/dict.{type Dict}
+import gleam/string
+import gleam/int
+import gleam/result
+
+pub type Posn {
+ Posn(r: Int, c: Int)
+}
+
+pub type Array2D(a) =
+ Dict(Posn, a)
+
+pub fn add_posns(p1: Posn, p2: Posn) -> Posn {
+ case p1, p2 {
+ Posn(r1, c1), Posn(r2, c2) -> Posn(r1 + r2, c1 + c2)
+ }
+}
+
+pub fn ortho_neighbors(p: Posn) -> List(Posn) {
+ let Posn(r, c) = p
+ [Posn(r + 1, c), Posn(r - 1, c), Posn(r, c + 1), Posn(r, c - 1)]
+}
+
+pub fn to_2d_array(xss: List(List(a))) -> Array2D(a) {
+ to_2d_array_using(xss, fn(x) { Ok(x) })
+}
+
+pub fn to_2d_array_using(
+ xss: List(List(a)),
+ f: fn(a) -> Result(b, Nil),
+) -> Array2D(b) {
+ {
+ use r, row <- list.index_map(xss)
+ use c, cell <- list.index_map(row)
+ case f(cell) {
+ Ok(contents) -> Ok(#(Posn(r, c), contents))
+ Error(Nil) -> Error(Nil)
+ }
+ }
+ |> list.flatten
+ |> result.values
+ |> dict.from_list
+}
+
+pub fn to_2d_intarray(xss: List(List(String))) -> Array2D(Int) {
+ {
+ use r, row <- list.index_map(xss)
+ use c, cell <- list.index_map(row)
+ let assert Ok(n) = int.parse(cell)
+ #(Posn(r, c), n)
+ }
+ |> list.flatten
+ |> dict.from_list
+}
+
+pub fn to_list_of_lists(str: String) -> List(List(String)) {
+ str
+ |> string.split("\n")
+ |> list.map(string.to_graphemes)
+}
+
+pub fn parse_grid(str: String) -> Array2D(String) {
+ parse_grid_using(str, fn(x) { Ok(x) })
+}
+
+pub fn parse_grid_using(
+ str: String,
+ f: fn(String) -> Result(a, Nil),
+) -> Array2D(a) {
+ str
+ |> to_list_of_lists
+ |> to_2d_array_using(f)
+}
diff --git a/aoc2023-gleam/src/utilities/memo.gleam b/aoc2023-gleam/src/utilities/memo.gleam
new file mode 100644
index 0000000..b06d8fd
--- /dev/null
+++ b/aoc2023-gleam/src/utilities/memo.gleam
@@ -0,0 +1,57 @@
+import gleam/dict.{type Dict}
+import gleam/otp/actor.{type Next, Continue, Stop}
+import gleam/erlang/process.{type Subject, Normal}
+import gleam/option.{None}
+
+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))
+
+pub opaque type Cache(k, v) {
+ Cache(server: Server(k, v))
+}
+
+fn handle_message(
+ message: Message(k, v),
+ dict: Dict(k, v),
+) -> Next(Message(k, v), Dict(k, v)) {
+ case message {
+ Shutdown -> Stop(Normal)
+ Get(key, client) -> {
+ process.send(client, dict.get(dict, key))
+ Continue(dict, None)
+ }
+ Set(key, value) -> Continue(dict.insert(dict, key, value), None)
+ }
+}
+
+pub fn create(apply fun: fn(Cache(k, v)) -> t) -> t {
+ let assert Ok(server) = actor.start(dict.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
+}
diff --git a/aoc2023-gleam/src/utilities/prioqueue.gleam b/aoc2023-gleam/src/utilities/prioqueue.gleam
new file mode 100644
index 0000000..abf21b9
--- /dev/null
+++ b/aoc2023-gleam/src/utilities/prioqueue.gleam
@@ -0,0 +1,64 @@
+//adapted from https://github.com/byronanderson/adventofcode2021/blob/main/gleam_advent/src/priority_queue.gleam
+
+import gleam/dict.{type Dict}
+
+type Ref
+
+@external(erlang, "erlang", "make_ref")
+fn make_ref() -> Ref
+
+type PQueue(a)
+
+pub opaque type PriorityQueue(a) {
+ PriorityQueue(queue: PQueue(#(a, Ref)), refs: Dict(a, Ref))
+}
+
+type OutResult(a) {
+ Empty
+ Value(a, Int)
+}
+
+@external(erlang, "pqueue2", "new")
+fn new_() -> PQueue(a)
+
+@external(erlang, "pqueue2", "in")
+fn insert_(item: a, prio: Int, queue: PQueue(a)) -> PQueue(a)
+
+@external(erlang, "pqueue2", "pout")
+fn pop_(queue: PQueue(a)) -> #(OutResult(a), PQueue(a))
+
+pub fn new() -> PriorityQueue(a) {
+ PriorityQueue(queue: new_(), refs: dict.new())
+}
+
+pub fn insert(
+ queue: PriorityQueue(a),
+ value: a,
+ priority: Int,
+) -> PriorityQueue(a) {
+ let ref = make_ref()
+
+ let refs =
+ queue.refs
+ |> dict.insert(value, ref)
+
+ PriorityQueue(
+ refs: refs,
+ queue: insert_(#(value, ref), priority, queue.queue),
+ )
+}
+
+pub fn pop(queue: PriorityQueue(a)) -> Result(#(a, PriorityQueue(a)), Nil) {
+ case pop_(queue.queue) {
+ #(Value(#(value, ref), _priority), pqueue) -> {
+ let assert Ok(recently_enqueued_ref) = dict.get(queue.refs, value)
+ case recently_enqueued_ref == ref {
+ True -> Ok(#(value, PriorityQueue(refs: queue.refs, queue: pqueue)))
+ False -> pop(PriorityQueue(refs: queue.refs, queue: pqueue))
+ }
+ }
+ #(Empty, _pqueue) -> {
+ Error(Nil)
+ }
+ }
+}