aboutsummaryrefslogtreecommitdiff
path: root/aoc2017-gleam/src/aoc_2017/day_6.gleam
diff options
context:
space:
mode:
Diffstat (limited to 'aoc2017-gleam/src/aoc_2017/day_6.gleam')
-rw-r--r--aoc2017-gleam/src/aoc_2017/day_6.gleam65
1 files changed, 65 insertions, 0 deletions
diff --git a/aoc2017-gleam/src/aoc_2017/day_6.gleam b/aoc2017-gleam/src/aoc_2017/day_6.gleam
new file mode 100644
index 0000000..84222e1
--- /dev/null
+++ b/aoc2017-gleam/src/aoc_2017/day_6.gleam
@@ -0,0 +1,65 @@
+import gary.{type ErlangArray}
+import gary/array
+import gleam/bool
+import gleam/int
+import gleam/list
+import gleam/result
+import gleam/set.{type Set}
+import gleam/string
+
+pub fn parse(input) -> ErlangArray(Int) {
+ input
+ |> string.split("\t")
+ |> list.map(int.parse)
+ |> result.values()
+ |> array.from_list(default: -1)
+ |> array.make_fixed()
+}
+
+pub fn pt_1(input: ErlangArray(Int)) {
+ check_cycle(input, set.from_list([input]), 1).1
+}
+
+pub fn pt_2(input: ErlangArray(Int)) {
+ let #(target, cycle) = check_cycle(input, set.from_list([input]), 1)
+ cycle - check_cycle(input, set.from_list([input, target]), 1).1
+}
+
+fn get_max(array: ErlangArray(Int)) -> #(Int, Int) {
+ use index, value, max <- array.fold(over: array, from: #(-1, -1))
+ case value > max.1 {
+ True -> #(index, value)
+ False -> max
+ }
+}
+
+fn redistribute(
+ array: ErlangArray(Int),
+ pointer: Int,
+ remaining: Int,
+) -> ErlangArray(Int) {
+ use <- bool.guard(remaining == 0, array)
+ case array.get(from: array, at: pointer) {
+ Error(_) -> redistribute(array, 0, remaining)
+ Ok(n) -> {
+ let assert Ok(updated_array) =
+ array.set(into: array, at: pointer, put: n + 1)
+ redistribute(updated_array, pointer + 1, remaining - 1)
+ }
+ }
+}
+
+fn check_cycle(
+ current: ErlangArray(Int),
+ cache: Set(ErlangArray(Int)),
+ cycle: Int,
+) -> #(ErlangArray(Int), Int) {
+ let #(index, to_redistribute) = current |> get_max
+ let assert Ok(zeroed) = array.set(into: current, at: index, put: 0)
+ let next = redistribute(zeroed, index + 1, to_redistribute)
+
+ case set.contains(cache, next) {
+ True -> #(next, cycle)
+ False -> check_cycle(next, set.insert(cache, next), cycle + 1)
+ }
+}