Giving of on Day 3 Part 2 (for now at least)

This commit is contained in:
April Eaton 2025-12-03 19:59:54 +01:00
parent 77d9537bdd
commit 1154c1489d
8 changed files with 594 additions and 0 deletions

View file

@ -0,0 +1,169 @@
import gleam/int
import gleam/io
import gleam/list
import gleam/order
import gleam/pair
import gleam/result
import gleam/string
import simplifile
pub type Bank {
Bank(List(Digit))
}
pub type Digit {
Digit(Int)
}
pub fn bank_parse(s: String) -> Bank {
string.trim(s)
|> int.parse
|> result.map(digits(_, 10))
|> result.flatten
|> result.unwrap([])
|> list.map(Digit)
|> Bank
}
pub fn file_to_banks(f: String) -> List(Bank) {
simplifile.read(f)
|> result.unwrap("")
|> string.trim
|> string.split("\n")
|> list.map(bank_parse)
}
fn digits(x: Int, base: Int) -> Result(List(Int), Nil) {
case base < 2 {
True -> Error(Nil)
False -> Ok(digits_loop(x, base, []))
}
}
fn digits_loop(x: Int, base: Int, acc: List(Int)) -> List(Int) {
case int.absolute_value(x) < base {
True -> [x, ..acc]
False -> digits_loop(x / base, base, [x % base, ..acc])
}
}
fn digit_outof(d: Digit) -> Int {
let Digit(d) = d
d
}
pub fn undigits(numbers: List(Int), base: Int) -> Result(Int, Nil) {
case base < 2 {
True -> Error(Nil)
False -> undigits_loop(numbers, base, 0)
}
}
fn undigits_loop(numbers: List(Int), base: Int, acc: Int) -> Result(Int, Nil) {
case numbers {
[] -> Ok(acc)
[digit, ..] if digit >= base -> Error(Nil)
[digit, ..rest] -> undigits_loop(rest, base, acc * base + digit)
}
}
pub fn int_list_to_bank(l: List(Int)) -> Bank {
Bank(list.map(l, Digit))
}
pub fn prepend_bank_with_max_joltage(
new_digit: Digit,
curr: #(Bank, List(Digit)),
length: Int,
) -> #(Bank, List(Digit)) {
let #(old_bank, old_max) = curr
case new_digit, old_bank, old_max, length {
_, Bank([]), [_, ..], _ -> panic as "old_bank should be longer than old_max"
Digit(n), Bank(b), max, length ->
case list.length(max), length {
m, l if m > l ->
panic as "length of max should never exceed target lenght"
m, l if m < l -> #(
Bank(list.append([Digit(n)], b)),
list.append([Digit(n)], max),
)
m, l if m == l -> {
case n, max {
n, [] -> #(Bank(list.append([Digit(n)], b)), [Digit(n)])
n, [Digit(h), ..t] if n >= h -> {
let #(_, inner) =
prepend_bank_with_max_joltage(
Digit(h),
#(
Bank(list.drop(b, 1)),
t,
// |> list.map(digit_outof)
// |> drop_first_min
// |> list.map(Digit),
),
length,
)
#(
Bank(list.append([Digit(n)], b)),
list.prepend(
inner
|> list.map(digit_outof)
|> drop_first_min
|> list.map(Digit),
Digit(n),
),
)
}
n, m -> {
#(Bank(list.append([Digit(n)], b)), m)
}
}
}
_, _ -> panic as "Kris, where the fuck are we?"
}
|> pair.map_second(fn(l) {
list.map(l, digit_outof)
// |> echo
|> list.map(Digit)
})
}
}
pub fn drop_first_min(l: List(Int)) -> List(Int) {
let min = list.max(l, int.compare |> order.reverse) |> result.unwrap(-1)
let #(left, right) =
l
|> list.split_while(fn(n) { n > min })
|> pair.map_second(fn(s) {
case s {
[] -> []
[_] -> []
[_, ..t] -> t
}
})
list.append(left, right)
}
pub fn max_joltage_from_bank(b: Bank) {
let Bank(b) = b
let #(_, max) =
b
|> list.fold_right(#(Bank([]), []), fn(p, d) {
prepend_bank_with_max_joltage(d, p, 12)
})
max
|> list.map(digit_outof)
|> undigits(10)
|> result.unwrap(0)
}
pub fn file_to_max_joltage(f: String) {
file_to_banks(f)
|> list.map(max_joltage_from_bank)
|> echo
|> list.fold(0, int.add)
}
pub fn main() -> Nil {
file_to_max_joltage("02.txt") |> int.to_string |> io.println
}