my solutions to advent of code
aoc advent-of-code
at main 3.6 kB view raw
1import gleam/dict.{type Dict} 2import gleam/int 3import gleam/io 4import gleam/list 5import gleam/order.{Eq, Gt, Lt} 6import gleam/result 7import gleam/set.{type Set} 8import gleam/string 9import simplifile as file 10 11pub type Reindeer { 12 Reindeer(name: String, speed: Int, run: Int, rest: Int) 13} 14 15pub type Action { 16 Run 17 Rest 18} 19 20pub type ReindeerState { 21 ReindeerState(points: Int, km: Int, action: Action, time_until_change: Int) 22} 23 24pub type LeadKm { 25 LeadKm(km: Int, leads: Set(String)) 26} 27 28pub type RunState = 29 Dict(String, ReindeerState) 30 31pub fn to_int(number_string) { 32 let assert Ok(number) = number_string |> int.base_parse(10) 33 as { number_string <> " is not a number" } 34 number 35} 36 37pub fn do_calculate_run_state(state: RunState, reindeers: List(Reindeer), sec) { 38 case sec > 0 { 39 False -> state 40 True -> { 41 let #(LeadKm(_, leads), state) = 42 reindeers 43 |> list.fold(#(LeadKm(0, set.new()), state), fn(s, reindeer) { 44 let #(lead, state) = s 45 let Reindeer(name, speed, run, rest) = reindeer 46 let ReindeerState(points, km, action, time_until_change) = 47 state 48 |> dict.get(reindeer.name) 49 |> result.unwrap(ReindeerState(0, 0, Run, run)) 50 51 let km = case action { 52 Run -> km + speed 53 Rest -> km 54 } 55 let state = 56 case time_until_change, action { 57 1, Run -> ReindeerState(points, km, Rest, rest) 58 1, Rest -> ReindeerState(points, km, Run, run) 59 _, _ -> ReindeerState(points, km, action, time_until_change - 1) 60 } 61 |> dict.insert(state, name, _) 62 63 let lead = case int.compare(km, lead.km) { 64 Eq -> LeadKm(km, lead.leads |> set.insert(name)) 65 Gt -> LeadKm(km, set.new() |> set.insert(name)) 66 Lt -> lead 67 } 68 69 #(lead, state) 70 }) 71 72 leads 73 |> set.fold(state, fn(state, reindeer_name) { 74 let assert Ok(ReindeerState(points, km, action, time_until_change)) = 75 state 76 |> dict.get(reindeer_name) 77 state 78 |> dict.insert( 79 reindeer_name, 80 ReindeerState(points + 1, km, action, time_until_change), 81 ) 82 }) 83 |> do_calculate_run_state(reindeers, sec - 1) 84 } 85 } 86} 87 88pub fn calculate_run_state(reindeers: List(Reindeer), sec: Int) { 89 do_calculate_run_state(dict.new(), reindeers, sec) 90} 91 92pub fn get_winner_km(state: RunState) { 93 state 94 |> dict.fold(0, fn(winner, _, state) { 95 case state.km > winner { 96 True -> state.km 97 False -> winner 98 } 99 }) 100} 101 102pub fn get_winner_points(state: RunState) { 103 state 104 |> dict.fold(0, fn(winner, _, state) { 105 case state.points > winner { 106 True -> state.points 107 False -> winner 108 } 109 }) 110} 111 112pub fn main() { 113 let assert Ok(reindeer) = file.read(from: "../input.txt") 114 as "Input file not found" 115 let reindeer = 116 reindeer 117 |> string.trim 118 |> string.split("\n") 119 |> list.map(fn(v) { 120 case v |> string.split(" ") { 121 // (name) can fly (speed) km/s for (run) seconds, but then must rest for (rest) seconds. 122 [name, _, _, speed, _, _, run, _, _, _, _, _, _, rest, _] -> 123 Reindeer(name, speed |> to_int, run |> to_int, rest |> to_int) 124 _ -> panic as { v <> " is not a valid line" } 125 } 126 }) 127 128 "Part 1" |> io.println 129 reindeer 130 |> calculate_run_state(2503) 131 |> get_winner_km 132 |> int.to_string 133 |> io.println 134 135 "Part 2" |> io.println 136 reindeer 137 |> calculate_run_state(2503) 138 |> get_winner_points 139 |> int.to_string 140 |> io.println 141}