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
5import gleam/result.{unwrap}
6import gleam/set.{type Set}
7import gleam/string.{trim}
8import simplifile.{read}
9
10type Distance {
11 Distance(place1: String, place2: String, value: Int)
12}
13
14type TwoPlaces {
15 TwoPlaces(place1: String, place2: String)
16}
17
18type DistanceDict =
19 Dict(TwoPlaces, Int)
20
21type MapPlaces {
22 MapPlaces(dict: DistanceDict, places: Set(String))
23}
24
25fn find_shortest_path(distance_dict, places, shortest_path, path, place place1) {
26 case set.size(places) == 0 {
27 True -> path
28 False ->
29 places
30 |> set.fold(shortest_path, fn(shortest_path, place2) {
31 let assert Ok(dist) = dict.get(distance_dict, TwoPlaces(place1, place2))
32 let path = path + dist
33 case path < shortest_path {
34 True ->
35 find_shortest_path(
36 distance_dict,
37 places |> set.delete(place2),
38 shortest_path,
39 path,
40 place2,
41 )
42 False -> shortest_path
43 }
44 })
45 }
46}
47
48fn find_shortest_path_helper(distance_dict: DistanceDict, places: Set(String)) {
49 places
50 |> set.fold(1_000_000, fn(shortest_path, place1) {
51 let places = places |> set.delete(place1)
52 let path =
53 places
54 |> set.fold(shortest_path, fn(shortest_path, place2) {
55 let assert Ok(path) = dict.get(distance_dict, TwoPlaces(place1, place2))
56 find_shortest_path(
57 distance_dict,
58 places |> set.delete(place2),
59 shortest_path,
60 path,
61 place2,
62 )
63 })
64 case path < shortest_path {
65 True -> path
66 False -> shortest_path
67 }
68 })
69}
70
71fn find_longest_path(distance_dict, places, longest_path, path, place place1) {
72 case set.size(places) == 0 {
73 True ->
74 case path > longest_path {
75 True -> path
76 False -> longest_path
77 }
78 False -> {
79 let #(place2, longest_distance) =
80 places
81 |> set.fold(#("", 0), fn(longest_distance_tuple, place2) {
82 let assert Ok(distance) =
83 dict.get(distance_dict, TwoPlaces(place1, place2))
84 let #(_, longest_distance) = longest_distance_tuple
85 case distance > longest_distance {
86 True -> #(place2, distance)
87 False -> longest_distance_tuple
88 }
89 })
90
91 let path = path + longest_distance
92 find_longest_path(
93 distance_dict,
94 places |> set.delete(place2),
95 longest_path,
96 path,
97 place2,
98 )
99 }
100 }
101}
102
103fn find_longest_path_helper(distance_dict: DistanceDict, places: Set(String)) {
104 places
105 |> set.fold(0, fn(longest_path, place1) {
106 let places = places |> set.delete(place1)
107 let path =
108 places
109 |> set.fold(longest_path, fn(longest_path, place2) {
110 let assert Ok(path) = dict.get(distance_dict, TwoPlaces(place1, place2))
111 find_longest_path(
112 distance_dict,
113 places |> set.delete(place2),
114 longest_path,
115 path,
116 place2,
117 )
118 })
119 case path > longest_path {
120 True -> path
121 False -> longest_path
122 }
123 })
124}
125
126pub fn main() {
127 let input =
128 read(from: "../input.txt")
129 |> unwrap("")
130 |> trim()
131 |> string.split("\n")
132 |> list.map(fn(v) {
133 case string.split(v, " ") {
134 [place1, "to", place2, "=", distance] ->
135 Distance(place1, place2, distance |> int.base_parse(10) |> unwrap(0))
136 _ -> Distance("silent_fail", "because_we_are_lazy", 0)
137 }
138 })
139
140 let MapPlaces(distance_dict, places) =
141 input
142 |> list.fold(MapPlaces(dict.new(), set.new()), fn(v, distance) {
143 let map =
144 dict.insert(
145 v.dict,
146 TwoPlaces(distance.place1, distance.place2),
147 distance.value,
148 )
149 let map =
150 dict.insert(
151 map,
152 TwoPlaces(distance.place2, distance.place1),
153 distance.value,
154 )
155 let places = set.insert(v.places, distance.place1)
156 let places = set.insert(places, distance.place2)
157 MapPlaces(map, places)
158 })
159
160 println(
161 find_shortest_path_helper(distance_dict, places)
162 |> to_string,
163 )
164 println(
165 find_longest_path_helper(distance_dict, places)
166 |> to_string,
167 )
168}