my solutions to advent of code
aoc
advent-of-code
1import gleam/dict.{type Dict}
2import gleam/int.{to_string}
3import gleam/io.{println}
4import gleam/list.{fold}
5import gleam/result.{unwrap}
6import gleam/string.{split, trim}
7import simplifile.{read}
8
9pub type Circuit =
10 Dict(String, Operation)
11
12pub type CircuitCache =
13 Dict(String, Int)
14
15pub type Operation {
16 Set(n: String)
17 Not(var: String)
18 And(var1: String, var2: String)
19 Or(var1: String, var2: String)
20 Rshift(var1: String, var2: String)
21 Lshift(var1: String, var2: String)
22}
23
24pub type GetRes {
25 GetRes(value: Int, cache: CircuitCache)
26}
27
28pub fn get_circuit_var(
29 circuit: Circuit,
30 name: String,
31 cache: CircuitCache,
32) -> GetRes {
33 let get = fn(name, cache) { get_circuit_var(circuit, name, cache) }
34
35 let parsed_name = int.base_parse(name, 10)
36 case result.is_ok(parsed_name) {
37 True -> GetRes(parsed_name |> unwrap(0), cache)
38 False -> {
39 case dict.get(cache, name) {
40 Ok(value) -> GetRes(value, cache)
41 Error(Nil) -> {
42 // will crash if it gets bad data
43 let assert Ok(op) = dict.get(circuit, name)
44
45 let #(value1, value2, cache) = case op {
46 Not(v) | Set(v) -> {
47 let GetRes(value, cache) = get(v, cache)
48 #(value, 0, cache)
49 }
50 And(v1, v2) | Or(v1, v2) | Rshift(v1, v2) | Lshift(v1, v2) -> {
51 let GetRes(value1, cache) = get(v1, cache)
52 let GetRes(value2, cache) = get(v2, cache)
53 #(value1, value2, cache)
54 }
55 }
56
57 let res = case op {
58 Set(_) -> value1
59 Not(_) -> int.bitwise_not(value1)
60 And(_, _) -> int.bitwise_and(value1, value2)
61 Or(_, _) -> int.bitwise_or(value1, value2)
62 Rshift(_, _) -> int.bitwise_shift_right(value1, value2)
63 Lshift(_, _) -> int.bitwise_shift_left(value1, value2)
64 }
65 GetRes(res, dict.insert(cache, name, res))
66 }
67 }
68 }
69 }
70}
71
72pub fn main() {
73 let input: Circuit =
74 read(from: "../input.txt")
75 |> unwrap("")
76 |> trim()
77 |> split("\n")
78 |> fold(dict.new(), fn(circ, v) {
79 case split(v, " ") {
80 ["NOT", var, "->", target] -> dict.insert(circ, target, Not(var))
81 [var1, "AND", var2, "->", target] ->
82 dict.insert(circ, target, And(var1, var2))
83 [var1, "OR", var2, "->", target] ->
84 dict.insert(circ, target, Or(var1, var2))
85 [var1, "RSHIFT", var2, "->", target] ->
86 dict.insert(circ, target, Rshift(var1, var2))
87 [var1, "LSHIFT", var2, "->", target] ->
88 dict.insert(circ, target, Lshift(var1, var2))
89 [v, "->", target] -> dict.insert(circ, target, Set(v))
90
91 _ -> circ
92 }
93 })
94
95 let result_part_1 = get_circuit_var(input, "a", dict.new()).value
96 println(result_part_1 |> to_string)
97
98 let input_part_2 = dict.insert(input, "b", Set(int.to_string(result_part_1)))
99 let result_part_2 = get_circuit_var(input_part_2, "a", dict.new()).value
100 println(result_part_2 |> to_string)
101}