my solutions to advent of code
aoc advent-of-code
at main 4.0 kB view raw
1import gleam/int 2import gleam/io 3import gleam/list 4import gleam/result 5import gleam/string 6import simplifile as file 7 8pub fn do(input, digits) { 9 input 10 // ok so here we're just iterating through all the battery banks in the input 11 |> list.fold(0, fn(acc, bank) { 12 let #(n, _) = 13 // and here we're going and doing it the amount of times necessary. it's backwards for obvious reasons, we start from the end and this let's us not have like duplicated logic where we're doing digits - i constantly 14 // it needs to be digits - 1 to zero because otherwise it will cut too much when dropping stuff at list.reverse list.drop(i) list.reverse 15 list.range(digits - 1, 0) 16 // didn't want to create a type for it so yeah #(the digit we're at, the remaining part of the bank) 17 |> list.fold(#(0, bank), fn(acc, i) { 18 // annoying gleam stuff i wish i could destructure it from the function 19 let #(number, bank) = acc 20 21 // that's the part that matters, and the one i took forever in and ended up splitting in multiple variables when i didn't need to 22 // but like it's very simple 23 // gleam doesn't let you drop from the end of lists, so we reverse the list, drop the digits we cannot use because they will necessarily be used latter in the number. the last i is the minimum because like we need at the very least finish the number yk 24 // and then the really annoying part, we turn it into an index map, so we can get the location of the number to later drop that part off for the next digit 25 // and then we get the highest number 26 // and done here 27 // little assert because failing is better than the silent failing of unwrap 28 // list.take instead of drop would allow me to do it without reversing two times but like it would also need list.length which also goes through the whole list but without letting me put it in just pipes 29 // i mean i COULD count it once when starting it when then after getting the location subtracting from it but meh already did the rust version and this would put too much stuff on here 30 let assert Ok(#(max, loc)) = 31 bank 32 |> list.reverse 33 |> list.drop(i) 34 |> list.reverse 35 |> list.index_map(fn(n, i) { #(n, i) }) 36 |> list.max(fn(a, b) { int.compare(a.0, b.0) }) 37 38 // and then we send it off to the next digit 39 // i wasn't using this number trick when i was doing it, i was literally just finding a power of 10 and multiplying it but like the power thing in gleam sucks it's like float only. i now learned this trick from *someone* and will be using it. don't know how i didn't figure out myself. oh wait i do it's because i'm stupid 40 // but yeah it just multiplies the number by ten so like 4 becomes 40 and then we add our like 3 to it 43 and then 43 to 430 and the 5 you get the gist of it. again don't know how i didn't see it myself 41 // and then we drop the parts of the list that can't be used for the subsequent numbers. like off by one evil thing in here to not include the number we just used too 42 // why don't we add 1 to everything in the thing above? because that would be more math than just adding it only once here duh 43 #(number * 10 + max, list.drop(bank, loc + 1)) 44 }) 45 // and then like every advent of code we add it to the acc 46 acc + n 47 }) 48} 49 50pub fn main() { 51 let assert Ok(input) = file.read(from: "../input.txt") 52 as "Input file not found" 53 let input = 54 input 55 |> string.trim 56 |> string.split("\n") 57 |> list.map(fn(bank) { 58 // just get all the battery banks, separate them by character and turn each character in a member of a list 59 // and here we unwrap because only let's you do it with variables and that would be less clean here 60 string.to_graphemes(bank) 61 |> list.map(fn(s) { int.parse(s) |> result.unwrap(0) }) 62 }) 63 64 do(input, 2) 65 |> int.to_string 66 |> io.println 67 68 do(input, 12) 69 |> int.to_string 70 |> io.println 71}