aoc2024/src/day3_p2.gleam
2024-12-04 01:42:20 +01:00

96 lines
2.2 KiB
Gleam

import gleam/int
import gleam/io
import gleam/iterator
import gleam/list.{reverse, take_while}
import gleam/option.{type Option, None, Some}
import gleam/string.{join}
import stdin.{stdin}
pub fn main() {
stdin()
|> read_input
|> find_and_calculate(0, can_mul: True)
|> io.debug
}
type FindResult {
Expression(Int, Int, String)
Nothing
}
fn find_and_calculate(s: String, acc: Int, can_mul mul_enabled: Bool) -> Int {
case s {
"" -> acc
"do()" <> rest -> find_and_calculate(rest, acc, can_mul: True)
"don't()" <> rest -> find_and_calculate(rest, acc, can_mul: False)
"mul(" <> rest if mul_enabled -> {
case find_expression(rest) {
Expression(a, b, rest) ->
find_and_calculate(rest, acc + a * b, can_mul: mul_enabled)
Nothing -> find_and_calculate(rest, acc, can_mul: mul_enabled)
}
}
_ -> find_and_calculate(string.drop_start(s, 1), acc, can_mul: mul_enabled)
}
}
fn find_expression(str: String) -> FindResult {
case
str
|> read_num
|> then(read_char(","))
|> then(read_num)
|> then(read_char(")"))
{
Some(#(#(#(#(a, _), b), _), rest)) -> Expression(a, b, rest)
None -> Nothing
}
}
fn read_char(char: String) {
fn(str: String) -> Option(#(String, String)) {
case string.pop_grapheme(str) {
Ok(#(ch, rest)) if ch == char -> Some(#(char, rest))
_ -> None
}
}
}
fn then(
current: Option(#(a, String)),
next: fn(String) -> Option(#(b, String)),
) -> Option(#(#(a, b), String)) {
case current {
None -> None
Some(#(a, s)) ->
next(s)
|> option.map(fn(result) {
let #(b, rest) = result
#(#(a, b), rest)
})
}
}
const numbers = "0123456789"
fn read_num(str: String) -> Option(#(Int, String)) {
let to_parse =
str
|> string.to_graphemes
|> take_while(fn(c) { string.contains(does: numbers, contain: c) })
|> join(with: "")
to_parse
|> int.parse
|> option.from_result
|> option.map(fn(n) {
#(n, string.drop_start(str, up_to: string.length(to_parse)))
})
}
fn read_input(it: iterator.Iterator(String)) -> String {
it
|> iterator.fold([], fn(acc, line) { [line, ..acc] })
|> reverse
|> join(with: "")
}