my solutions to advent of code
aoc advent-of-code
at main 4.3 kB view raw
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}