aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--aoc-2020-gleam/src/aoc_2020_gleam.gleam2
-rw-r--r--aoc-2020-gleam/src/days/day09.gleam68
-rw-r--r--aoc-2020-gleam/src/ext/iteratorx.gleam13
-rw-r--r--aoc-2020-gleam/src/ext/listx.gleam10
4 files changed, 93 insertions, 0 deletions
diff --git a/aoc-2020-gleam/src/aoc_2020_gleam.gleam b/aoc-2020-gleam/src/aoc_2020_gleam.gleam
index 25b59d7..bf3fb3c 100644
--- a/aoc-2020-gleam/src/aoc_2020_gleam.gleam
+++ b/aoc-2020-gleam/src/aoc_2020_gleam.gleam
@@ -8,6 +8,7 @@ import days/day05
import days/day06
import days/day07
import days/day08
+import days/day09
pub fn main() -> Nil {
use day <- runner.with_day()
@@ -20,6 +21,7 @@ pub fn main() -> Nil {
6 -> day06.run()
7 -> day07.run()
8 -> day08.run()
+ 9 -> day09.run()
_ -> io.println("Day not found!")
}
}
diff --git a/aoc-2020-gleam/src/days/day09.gleam b/aoc-2020-gleam/src/days/day09.gleam
new file mode 100644
index 0000000..81dac89
--- /dev/null
+++ b/aoc-2020-gleam/src/days/day09.gleam
@@ -0,0 +1,68 @@
+import gleam/io
+import gleam/int
+import gleam/list
+import gleam/pair
+import gleam/result as res
+import gleam/iterator as iter
+import ext/listx
+import ext/iteratorx as iterx
+import ext/resultx as resx
+import util/input_util
+
+fn satisfies_two_sum(numbers: List(Int), sum: Int) -> Bool {
+ numbers
+ |> list.combination_pairs
+ |> list.filter(fn(two) { pair.first(two) != pair.second(two) })
+ |> list.any(satisfying: fn(two) { pair.first(two) + pair.second(two) == sum })
+}
+
+fn part1(numbers: List(Int), preamble_length: Int) -> Int {
+ numbers
+ |> list.window(by: preamble_length + 1)
+ |> iter.from_list
+ |> iter.drop_while(satisfying: fn(window) {
+ let assert [sum, ..numbers] = list.reverse(window)
+ satisfies_two_sum(numbers, sum)
+ })
+ |> iter.first
+ |> resx.assert_unwrap
+ |> list.last
+ |> resx.assert_unwrap
+}
+
+fn part2(numbers: List(Int), preamble_length: Int) -> Int {
+ let sum = part1(numbers, preamble_length)
+ numbers
+ |> iter.from_list
+ |> iter.index
+ |> iterx.filter_map(with: fn(step) {
+ let #(index, _) = step
+ let sublist = list.drop(from: numbers, up_to: index)
+
+ sublist
+ |> list.scan(from: 0, with: int.add)
+ |> list.drop(up_to: 1)
+ |> list.take_while(satisfying: fn(s) { s <= sum })
+ |> listx.index_of(sum)
+ |> res.map(with: fn(offset) { list.take(from: sublist, up_to: offset + 2) })
+ })
+ |> iter.first
+ |> resx.assert_unwrap
+ |> fn(set) {
+ let assert Ok(min) = list.reduce(set, with: int.min)
+ let assert Ok(max) = list.reduce(set, with: int.max)
+ min + max
+ }
+}
+
+pub fn run() -> Nil {
+ let test = input_util.read_numbers("test09")
+ let assert 127 = part1(test, 5)
+ let assert 62 = part2(test, 5)
+
+ let input = input_util.read_numbers("day09")
+ io.debug(part1(input, 25))
+ io.debug(part2(input, 25))
+
+ Nil
+}
diff --git a/aoc-2020-gleam/src/ext/iteratorx.gleam b/aoc-2020-gleam/src/ext/iteratorx.gleam
index 0ef5d51..65e06f2 100644
--- a/aoc-2020-gleam/src/ext/iteratorx.gleam
+++ b/aoc-2020-gleam/src/ext/iteratorx.gleam
@@ -10,3 +10,16 @@ pub fn count(iterator: Iterator(a), satisfying predicate: fn(a) -> Bool) -> Int
|> iter.filter(for: predicate)
|> length
}
+
+pub fn filter_map(
+ iterator: Iterator(a),
+ with mapper: fn(a) -> Result(b, c),
+) -> Iterator(b) {
+ iterator
+ |> iter.flat_map(with: fn(elem) {
+ case mapper(elem) {
+ Ok(new) -> iter.single(new)
+ Error(_) -> iter.empty()
+ }
+ })
+}
diff --git a/aoc-2020-gleam/src/ext/listx.gleam b/aoc-2020-gleam/src/ext/listx.gleam
index 2d4f4b6..8d20bd6 100644
--- a/aoc-2020-gleam/src/ext/listx.gleam
+++ b/aoc-2020-gleam/src/ext/listx.gleam
@@ -1,4 +1,6 @@
+import gleam/pair
import gleam/iterator as iter
+import gleam/result as res
import ext/iteratorx as iterx
pub fn count(list: List(a), satisfying predicate: fn(a) -> Bool) -> Int {
@@ -18,3 +20,11 @@ fn set_helper(list: List(a), value: a, index: Int, counter: Int) -> List(a) {
pub fn set(list: List(a), value: a, at index: Int) -> List(a) {
set_helper(list, value, index, 0)
}
+
+pub fn index_of(list: List(a), value: a) -> Result(Int, Nil) {
+ list
+ |> iter.from_list
+ |> iter.index
+ |> iter.find(one_that: fn(elem) { pair.second(elem) == value })
+ |> res.map(with: pair.first)
+}