diff options
author | Tomasz Chojnacki <tomaszchojnacki2001@gmail.com> | 2023-04-06 22:00:05 +0200 |
---|---|---|
committer | Tomasz Chojnacki <tomaszchojnacki2001@gmail.com> | 2023-04-06 22:00:05 +0200 |
commit | 76e1d24c9cb3f2461f4dca08271fa25f97e820b7 (patch) | |
tree | 232859b85c356d71fdb89e8c627df17455bd812b /aoc-2020-gleam | |
parent | 20852d6e60bee896e84c9bae77f45211773dbf60 (diff) | |
download | gleam_aoc2020-76e1d24c9cb3f2461f4dca08271fa25f97e820b7.tar.gz gleam_aoc2020-76e1d24c9cb3f2461f4dca08271fa25f97e820b7.zip |
Finish day 13
Diffstat (limited to 'aoc-2020-gleam')
-rw-r--r-- | aoc-2020-gleam/src/days/day10.gleam | 2 | ||||
-rw-r--r-- | aoc-2020-gleam/src/days/day13.gleam | 113 | ||||
-rw-r--r-- | aoc-2020-gleam/src/ext/intx.gleam | 21 |
3 files changed, 135 insertions, 1 deletions
diff --git a/aoc-2020-gleam/src/days/day10.gleam b/aoc-2020-gleam/src/days/day10.gleam index b53000b..86c0137 100644 --- a/aoc-2020-gleam/src/days/day10.gleam +++ b/aoc-2020-gleam/src/days/day10.gleam @@ -49,7 +49,7 @@ fn arrangements(number: Int, adapters: List(Int), cache: Cache(Int, Int)) -> Int fn part2(numbers: List(Int)) -> Int { let adapters = process_adapters(numbers) - let device_joltage = resx.assert_unwrap(list.last(adapters)) + let assert Ok(device_joltage) = list.last(adapters) use cache <- cache.create() arrangements(device_joltage, adapters, cache) } diff --git a/aoc-2020-gleam/src/days/day13.gleam b/aoc-2020-gleam/src/days/day13.gleam new file mode 100644 index 0000000..c95cd42 --- /dev/null +++ b/aoc-2020-gleam/src/days/day13.gleam @@ -0,0 +1,113 @@ +import gleam/io +import gleam/int +import gleam/list +import gleam/pair +import gleam/string as str +import gleam/iterator as iter +import ext/intx +import ext/resultx as resx +import ext/iteratorx as iterx +import util/input_util + +type Bus { + Any + Line(Int) +} + +type Problem { + Problem(timestamp: Int, buses: List(Bus)) +} + +fn parse_problem(input: String) -> Problem { + let assert Ok(#(timestamp, buses)) = + input + |> str.trim + |> str.split_once(on: "\n") + let assert Ok(timestamp) = int.parse(timestamp) + let buses = + buses + |> str.split(on: ",") + |> list.map(with: fn(b) { + case b == "x" { + True -> Any + False -> + b + |> int.parse + |> resx.assert_unwrap + |> Line + } + }) + Problem(timestamp, buses) +} + +fn part1(input: String) -> Int { + let problem = parse_problem(input) + + problem.buses + |> list.filter_map(with: fn(b) { + case b { + Line(line) -> Ok(line) + Any -> Error(Nil) + } + }) + |> list.map(with: fn(b) { + #(b, b * intx.ceil_divide(problem.timestamp, by: b) - problem.timestamp) + }) + |> list.reduce(with: fn(acc, cur) { + case cur.1 < acc.1 { + True -> cur + False -> acc + } + }) + |> resx.assert_unwrap + |> fn(res: #(Int, Int)) { res.0 * res.1 } +} + +fn part2(input: String) -> Int { + let problem = parse_problem(input) + + let buses = + problem.buses + |> iter.from_list + |> iter.index + |> iter.flat_map(fn(entry) { + let #(i, b) = entry + case b { + Line(line) -> iter.single(#(line, i)) + Any -> iter.empty() + } + }) + |> iter.to_list + + let assert [#(timestamp, _), ..] = buses + + buses + |> list.fold( + from: #(timestamp, timestamp), + with: fn(prev, entry) { + let #(timestamp, period) = prev + let #(id, i) = entry + + let assert Ok(timestamp) = + timestamp + |> iterx.unfold_infinitely(with: int.add(_, period)) + |> iter.find(one_that: fn(t) { { t + i } % id == 0 }) + let period = intx.lcm(period, id) + + #(timestamp, period) + }, + ) + |> pair.first +} + +pub fn main() -> Nil { + let test = input_util.read_text("test13") + let assert 295 = part1(test) + let assert 1_068_781 = part2(test) + + let input = input_util.read_text("day13") + io.debug(part1(input)) + io.debug(part2(input)) + + Nil +} diff --git a/aoc-2020-gleam/src/ext/intx.gleam b/aoc-2020-gleam/src/ext/intx.gleam index 9f06850..077b4f2 100644 --- a/aoc-2020-gleam/src/ext/intx.gleam +++ b/aoc-2020-gleam/src/ext/intx.gleam @@ -1,3 +1,24 @@ +import gleam/int +import gleam/order.{Eq, Gt, Lt} + pub fn is_between(number: Int, min: Int, and max: Int) { min <= number && number <= max } + +pub fn ceil_divide(dividend: Int, by divisor: Int) -> Int { + { dividend + divisor - 1 } / divisor +} + +fn gcd(a: Int, b: Int) -> Int { + case b == 0 { + True -> a + False -> gcd(b, a % b) + } +} + +pub fn lcm(a: Int, b: Int) -> Int { + case int.compare(a, b) { + Gt | Eq -> { a / gcd(a, b) } * b + Lt -> { b / gcd(a, b) } * a + } +} |