my solutions to advent of code
aoc
advent-of-code
1import gleam/dict.{type Dict}
2import gleam/int
3import gleam/io
4import gleam/list
5import gleam/set.{type Set}
6import gleam/string
7import simplifile.{read}
8
9pub type Relation {
10 Relation(person: String, neighbor: String)
11}
12
13pub type SingularHappinessDict =
14 Dict(Relation, Int)
15
16pub type HappinessDict =
17 Dict(Relation, Int)
18
19pub type People =
20 Set(String)
21
22pub type Sign {
23 Gain
24 Lose
25}
26
27fn do_find_happiest_table(
28 happiness_dict,
29 people,
30 first_person first_person,
31 last_person last_person,
32 table table,
33) {
34 case people |> set.is_empty {
35 True -> {
36 let assert Ok(relation) =
37 happiness_dict |> dict.get(Relation(last_person, first_person))
38 as "There should be more than one person"
39 table + relation
40 }
41 False -> {
42 people
43 |> set.fold(0, fn(happiest_table, person) {
44 let assert Ok(relation) =
45 happiness_dict |> dict.get(Relation(last_person, person))
46 as {
47 "Relation between "
48 <> { last_person <> " and " <> person }
49 <> " was not found"
50 }
51 // ok so i figured out why this works, it's because it's only comparing to stuff that starts at the same level
52 let table =
53 do_find_happiest_table(
54 happiness_dict,
55 people |> set.delete(person),
56 first_person,
57 last_person: person,
58 table: table + relation,
59 )
60 case table > happiest_table {
61 True -> table
62 False -> happiest_table
63 }
64 })
65 }
66 }
67}
68
69pub fn find_happiest_table(happiness_dict: HappinessDict, people: People) {
70 let assert Ok(person) = people |> set.to_list |> list.first
71 as "People list is empty"
72 do_find_happiest_table(
73 happiness_dict,
74 people |> set.delete(person),
75 first_person: person,
76 last_person: person,
77 table: 0,
78 )
79}
80
81pub fn parse_sign(sign: String) {
82 case sign {
83 "gain" -> Ok(Gain)
84 "lose" -> Ok(Lose)
85 _ -> Error("Some sign input was neither gain or lose: " <> sign)
86 }
87}
88
89pub fn main() {
90 let assert Ok(input) = read(from: "../input.txt") as "Input file not found"
91
92 let singular_happiness_dict: SingularHappinessDict =
93 input
94 |> string.trim
95 |> string.split("\n")
96 |> list.map(fn(value) {
97 case value |> string.split(" ") {
98 // (person) would (gain/lose) (amount) happiness units by sitting next to (neighbor.)
99 [person, _, sign, happiness, _, _, _, _, _, _, neighbor] -> {
100 let assert Ok(happiness) = happiness |> int.base_parse(10)
101 as { "Happiness values should be integers: " <> happiness }
102 let sign = case parse_sign(sign) {
103 Ok(sign) -> sign
104 Error(message) -> panic as message
105 }
106 let happiness = case sign {
107 Gain -> happiness
108 Lose -> happiness |> int.negate
109 }
110
111 let neighbor = case neighbor |> string.last {
112 Ok(".") -> neighbor |> string.drop_end(1)
113 _ -> panic as { "Neighbor didn't end in a dot: " <> neighbor }
114 }
115
116 #(Relation(person, neighbor), happiness)
117 }
118 _ -> panic as { "Value doesn't match constrainsts" <> value }
119 }
120 })
121 |> dict.from_list
122
123 let happiness_dict: HappinessDict =
124 singular_happiness_dict
125 |> dict.fold(dict.new(), fn(hd, relation, singular_happiness) {
126 let Relation(person1, person2) = relation
127
128 case hd |> dict.has_key(relation) {
129 False -> {
130 let other_relation = Relation(person2, person1)
131 let assert Ok(other_singular_happiness) =
132 singular_happiness_dict |> dict.get(other_relation)
133 as "Malformed singular_happiness_dict"
134 let total_happiness = singular_happiness + other_singular_happiness
135
136 hd
137 |> dict.insert(relation, total_happiness)
138 |> dict.insert(other_relation, total_happiness)
139 }
140 True -> hd
141 }
142 })
143
144 let people: People =
145 singular_happiness_dict
146 |> dict.fold(set.new(), fn(people, relation, _) {
147 people |> set.insert(relation.person)
148 })
149
150 "Part 1" |> io.println
151 let happiest_table = find_happiest_table(happiness_dict, people)
152 happiest_table |> int.to_string |> io.println
153
154 "Part 2" |> io.println
155 let relations_with_me: HappinessDict =
156 people
157 |> set.to_list
158 |> list.map(fn(person) {
159 [#(Relation(person, "Me"), 0), #(Relation("Me", person), 0)]
160 })
161 |> list.flatten
162 |> dict.from_list
163 let happiness_dict = happiness_dict |> dict.merge(relations_with_me)
164 let people = people |> set.insert("Me")
165
166 let happiest_table_with_me = find_happiest_table(happiness_dict, people)
167 happiest_table_with_me |> int.to_string |> io.println
168}