This commit is contained in:
Hamcha 2024-12-04 01:42:20 +01:00
parent 43035cf142
commit 7c03dd3d6a
Signed by: hamcha
GPG key ID: 1669C533B8CF6D89
4 changed files with 196 additions and 0 deletions

1
sample/day3-sample.txt Normal file
View file

@ -0,0 +1 @@
xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))

2
sample/day3-sample2.txt Normal file
View file

@ -0,0 +1,2 @@
xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))

97
src/day3_p1.gleam Normal file
View file

@ -0,0 +1,97 @@
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)
|> io.debug
}
type FindResult {
Expression(Int, Int, String)
Nothing
}
fn find_and_calculate(s: String, acc: Int) -> Int {
// Drop all until first 'mul('
let next =
string.crop(from: s, before: "mul(")
|> string.drop_start(up_to: 4)
case next {
"" -> acc
str -> {
case find_expression(str) {
Expression(a, b, rest) -> find_and_calculate(rest, acc + a * b)
Nothing -> find_and_calculate(next, acc)
}
}
}
}
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: "")
}

96
src/day3_p2.gleam Normal file
View file

@ -0,0 +1,96 @@
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: "")
}