diff options
-rw-r--r-- | aoc-2020-gleam/src/aoc_2020_gleam.gleam | 2 | ||||
-rw-r--r-- | aoc-2020-gleam/src/days/day09.gleam | 68 | ||||
-rw-r--r-- | aoc-2020-gleam/src/ext/iteratorx.gleam | 13 | ||||
-rw-r--r-- | aoc-2020-gleam/src/ext/listx.gleam | 10 |
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) +} |