my solutions to advent of code
aoc
advent-of-code
1import gleam/dict.{type Dict}
2import gleam/dynamic/decode
3import gleam/int.{to_string}
4import gleam/io.{println}
5import gleam/json
6import gleam/list
7import gleam/result.{unwrap}
8import simplifile.{read}
9
10type Nested {
11 NestedList(List(Nested))
12 NestedDict(Dict(String, Nested))
13 IntValue(Int)
14 StringValue(String)
15}
16
17fn nested_decoder() -> decode.Decoder(Nested) {
18 use <- decode.recursive
19 decode.one_of(decode.int |> decode.map(IntValue), or: [
20 decode.list(nested_decoder()) |> decode.map(NestedList),
21 decode.dict(decode.string, nested_decoder()) |> decode.map(NestedDict),
22 decode.string |> decode.map(StringValue),
23 ])
24}
25
26// unfortunately this isn't tail call optimised. making it so would make it ugly :(
27fn get_total_number(data: Nested, no_red no_red) {
28 case data {
29 NestedList(items) ->
30 items
31 |> list.fold(0, fn(acc, data) { acc + get_total_number(data, no_red) })
32 NestedDict(items) -> {
33 items
34 |> dict.values
35 |> list.fold_until(0, fn(acc, data) {
36 case no_red, data {
37 True, StringValue("red") -> list.Stop(0)
38 _, _ -> list.Continue(acc + get_total_number(data, no_red))
39 }
40 })
41 }
42 IntValue(v) -> v
43 _ -> 0
44 }
45}
46
47pub fn main() {
48 let assert Ok(input) =
49 read(from: "../input.json")
50 |> unwrap("")
51 |> json.parse(nested_decoder())
52
53 println(
54 get_total_number(input, no_red: False)
55 |> to_string,
56 )
57 println(
58 get_total_number(input, no_red: True)
59 |> to_string,
60 )
61}