aboutsummaryrefslogtreecommitdiff
path: root/aoc-2020-gleam
diff options
context:
space:
mode:
authorTomasz Chojnacki <tomaszchojnacki2001@gmail.com>2023-04-06 22:00:05 +0200
committerTomasz Chojnacki <tomaszchojnacki2001@gmail.com>2023-04-06 22:00:05 +0200
commit76e1d24c9cb3f2461f4dca08271fa25f97e820b7 (patch)
tree232859b85c356d71fdb89e8c627df17455bd812b /aoc-2020-gleam
parent20852d6e60bee896e84c9bae77f45211773dbf60 (diff)
downloadgleam_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.gleam2
-rw-r--r--aoc-2020-gleam/src/days/day13.gleam113
-rw-r--r--aoc-2020-gleam/src/ext/intx.gleam21
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
+ }
+}