my solutions to advent of code
aoc advent-of-code

Compare changes

Choose any two refs to compare.

Changed files
+466 -2
2025
+2 -2
2025/5/gleam/src/main.gleam
··· 85 85 Gt, Gt, Gt, Gt | Lt, Lt, Lt, Lt -> #(range, seen_ranges) 86 86 // if it's inside of the other one 87 87 Gt, Lt, _, _ | Eq, Lt, _, _ | Gt, Eq, _, _ | Eq, Eq, _, _ -> #( 88 - #(0, 0), 88 + #(-1, -1), 89 89 seen_ranges, 90 90 ) 91 91 // if the other one is inside it ··· 106 106 } 107 107 }) 108 108 109 - case range == #(0, 0) { 109 + case range == #(-1, -1) { 110 110 False -> seen_ranges |> set.insert(range) 111 111 True -> seen_ranges 112 112 }
+7
2025/5/rust/Cargo.lock
··· 1 + # This file is automatically @generated by Cargo. 2 + # It is not intended for manual editing. 3 + version = 4 4 + 5 + [[package]] 6 + name = "rust" 7 + version = "0.1.0"
+6
2025/5/rust/Cargo.toml
··· 1 + [package] 2 + name = "rust" 3 + version = "0.1.0" 4 + edition = "2024" 5 + 6 + [dependencies]
+75
2025/5/rust/src/main.rs
··· 1 + use std::{ 2 + cmp::Ordering::{Equal as Eq, Greater as Gt, Less as Lt}, 3 + collections::HashSet, 4 + }; 5 + 6 + fn main() { 7 + let input = include_str!("../../input.txt").trim(); 8 + let (fresh_ranges, available) = input.split_once("\n\n").unwrap(); 9 + let fresh_ranges: Vec<(u64, u64)> = fresh_ranges 10 + .split("\n") 11 + .map(|i| { 12 + let (a, b) = i.split_once("-").unwrap(); 13 + (a.parse().unwrap(), b.parse().unwrap()) 14 + }) 15 + .collect(); 16 + let available = available.split("\n").map(|i| { 17 + let i: u64 = i.parse().unwrap(); 18 + i 19 + }); 20 + 21 + let part_1 = available.fold(0, |acc, i| { 22 + acc + fresh_ranges 23 + .iter() 24 + .any(|(start, end)| &i >= start && &i <= end) as u64 25 + }); 26 + println!("Part 1: {}", part_1); 27 + 28 + let mut seen_ranges: HashSet<(u64, u64)> = 29 + HashSet::with_capacity(fresh_ranges.len()); 30 + fresh_ranges.iter().for_each(|range| { 31 + let range = seen_ranges.clone().iter().try_fold( 32 + *range, 33 + |range: (u64, u64), seen_range: &(u64, u64)| { 34 + // btw im refusing to ever do something better than this idc about your sorting and whatever this is the way shut the fuck up i spent three hours on this i will be using it 35 + match ( 36 + range.0.cmp(&seen_range.0), 37 + range.1.cmp(&seen_range.1), 38 + range.0.cmp(&seen_range.1), 39 + range.1.cmp(&seen_range.0), 40 + ) { 41 + // if there's no touching 42 + (Gt, Gt, Gt, Gt) | (Lt, Lt, Lt, Lt) => Some(range), 43 + // if it's inside of the other one 44 + (Gt, Lt, _, _) 45 + | (Eq, Lt, _, _) 46 + | (Gt, Eq, _, _) 47 + | (Eq, Eq, _, _) => None, 48 + // if the other one is inside it 49 + (Lt, Gt, _, _) | (Eq, Gt, _, _) | (Lt, Eq, _, _) => { 50 + seen_ranges.remove(seen_range); 51 + Some(range) 52 + } 53 + // if it's touching on the left side make them touch 54 + (Lt, Lt, _, _) => { 55 + seen_ranges.remove(seen_range); 56 + Some((range.0, seen_range.1)) 57 + } 58 + // if it's touching on the right size make them touch 59 + (Gt, Gt, _, _) => { 60 + seen_ranges.remove(seen_range); 61 + Some((seen_range.0, range.1)) 62 + } 63 + } 64 + }, 65 + ); 66 + 67 + if range.is_some() { 68 + seen_ranges.insert(range.unwrap()); 69 + } 70 + }); 71 + let part_2 = seen_ranges 72 + .into_iter() 73 + .fold(0, |acc, range| acc + range.1 - range.0 + 1); 74 + println!("Part 2: {}", part_2); 75 + }
+20
2025/6/gleam/gleam.toml
··· 1 + name = "main" 2 + version = "1.0.0" 3 + 4 + # Fill out these fields if you intend to generate HTML documentation or publish 5 + # your project to the Hex package manager. 6 + # 7 + # description = "" 8 + # licences = ["Apache-2.0"] 9 + # repository = { type = "github", user = "", repo = "" } 10 + # links = [{ title = "Website", href = "" }] 11 + # 12 + # For a full reference of all the available options, you can have a look at 13 + # https://gleam.run/writing-gleam/gleam-toml/. 14 + 15 + [dependencies] 16 + gleam_stdlib = ">= 0.44.0 and < 2.0.0" 17 + simplifile = ">= 2.3.0 and < 3.0.0" 18 + 19 + [dev-dependencies] 20 + gleeunit = ">= 1.0.0 and < 2.0.0"
+14
2025/6/gleam/manifest.toml
··· 1 + # This file was generated by Gleam 2 + # You typically do not need to edit this file 3 + 4 + packages = [ 5 + { name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" }, 6 + { name = "gleam_stdlib", version = "0.65.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "7C69C71D8C493AE11A5184828A77110EB05A7786EBF8B25B36A72F879C3EE107" }, 7 + { name = "gleeunit", version = "1.7.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "CD701726CBCE5588B375D157B4391CFD0F2F134CD12D9B6998A395484DE05C58" }, 8 + { name = "simplifile", version = "2.3.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "0A868DAC6063D9E983477981839810DC2E553285AB4588B87E3E9C96A7FB4CB4" }, 9 + ] 10 + 11 + [requirements] 12 + gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" } 13 + gleeunit = { version = ">= 1.0.0 and < 2.0.0" } 14 + simplifile = { version = ">= 2.3.0 and < 3.0.0" }
+140
2025/6/gleam/src/main.gleam
··· 1 + import gleam/dict 2 + import gleam/int 3 + import gleam/io 4 + import gleam/list 5 + import gleam/result 6 + import gleam/string 7 + import simplifile as file 8 + 9 + type Part2Dict = 10 + dict.Dict(Int, Int) 11 + 12 + type Align { 13 + Left 14 + Right 15 + } 16 + 17 + type Operation { 18 + Sum 19 + Mul 20 + } 21 + 22 + type Part2Line { 23 + Part2Line(align: Align, op: Operation, numbers: List(String)) 24 + } 25 + 26 + pub fn main() { 27 + let assert Ok(input) = file.read(from: "../input.txt") 28 + as "Input file not found" 29 + let input = input |> string.trim 30 + let input_pt_1 = 31 + list.fold(list.range(1, 10), input, fn(acc, _) { 32 + acc |> string.replace(" ", " ") 33 + }) 34 + 35 + input_pt_1 36 + |> string.split("\n") 37 + |> list.map(fn(i) { string.trim(i) |> string.split(" ") }) 38 + |> list.transpose 39 + |> list.map(fn(i) { 40 + let i = list.reverse(i) 41 + let assert Ok(s) = list.first(i) 42 + let i = 43 + list.drop(i, 1) |> list.map(fn(i) { int.parse(i) |> result.unwrap(0) }) 44 + let r = case s { 45 + "+" -> int.sum(i) 46 + "*" -> list.reduce(i, int.multiply) |> result.unwrap(0) 47 + _ -> panic as "invalid" 48 + } 49 + r 50 + }) 51 + |> int.sum 52 + |> int.to_string 53 + |> io.println 54 + 55 + let lines = 56 + input 57 + |> string.split("\n") 58 + |> list.reverse 59 + let assert Ok(last_line) = list.first(lines) 60 + let #(_, bounds) = 61 + { last_line <> " *" } 62 + |> string.to_graphemes 63 + |> list.index_fold(#(0, list.new()), fn(acc, char, i) { 64 + let #(bound_start, bounds) = acc 65 + case char { 66 + "*" | "+" if i > 0 -> #(i, list.append([#(bound_start, i - 1)], bounds)) 67 + _ -> acc 68 + } 69 + }) 70 + bounds 71 + |> list.index_fold(dict.new(), fn(d, bound, i) { 72 + let numbers = 73 + list.map(lines, fn(line) { 74 + string.slice(line, bound.0, bound.1 - bound.0) 75 + }) 76 + let align = 77 + numbers 78 + |> list.drop(1) 79 + |> list.fold_until(Left, fn(res, number) { 80 + case 81 + string.trim(number) == number, 82 + string.trim_start(number) == number 83 + { 84 + True, _ -> list.Continue(res) 85 + _, True -> list.Stop(Left) 86 + _, _ -> list.Stop(Right) 87 + } 88 + }) 89 + let assert Ok(sign) = list.first(numbers) 90 + let sign = case string.trim(sign) { 91 + "*" -> Mul 92 + "+" -> Sum 93 + _ -> panic as sign 94 + } 95 + dict.insert( 96 + d, 97 + i, 98 + Part2Line( 99 + align, 100 + sign, 101 + numbers |> list.drop(1) |> list.map(string.trim) |> list.reverse, 102 + ), 103 + ) 104 + }) 105 + |> dict.to_list 106 + |> list.map(fn(i) { i.1 }) 107 + |> list.map(fn(line) { 108 + let d: Part2Dict = dict.new() 109 + let d = 110 + line.numbers 111 + |> list.fold(d, fn(d, number) { 112 + let number_len = string.length(number) 113 + string.to_graphemes(number) 114 + |> list.index_fold(d, fn(d, digit, index) { 115 + let assert Ok(digit) = digit |> int.parse 116 + let pos = case line.align { 117 + Right -> number_len - index 118 + Left -> index 119 + } 120 + dict.insert( 121 + d, 122 + pos, 123 + { dict.get(d, pos) |> result.unwrap(0) } * 10 + digit, 124 + ) 125 + }) 126 + }) 127 + let numbers = 128 + dict.to_list(d) 129 + |> list.map(fn(n) { n.1 }) 130 + 131 + let r = case line.op { 132 + Sum -> int.sum(numbers) 133 + Mul -> list.reduce(numbers, int.multiply) |> result.unwrap(0) 134 + } 135 + r 136 + }) 137 + |> int.sum 138 + |> int.to_string 139 + |> io.println 140 + }
+20
2025/7/gleam/gleam.toml
··· 1 + name = "main" 2 + version = "1.0.0" 3 + 4 + # Fill out these fields if you intend to generate HTML documentation or publish 5 + # your project to the Hex package manager. 6 + # 7 + # description = "" 8 + # licences = ["Apache-2.0"] 9 + # repository = { type = "github", user = "", repo = "" } 10 + # links = [{ title = "Website", href = "" }] 11 + # 12 + # For a full reference of all the available options, you can have a look at 13 + # https://gleam.run/writing-gleam/gleam-toml/. 14 + 15 + [dependencies] 16 + gleam_stdlib = ">= 0.44.0 and < 2.0.0" 17 + simplifile = ">= 2.3.0 and < 3.0.0" 18 + 19 + [dev-dependencies] 20 + gleeunit = ">= 1.0.0 and < 2.0.0"
+14
2025/7/gleam/manifest.toml
··· 1 + # This file was generated by Gleam 2 + # You typically do not need to edit this file 3 + 4 + packages = [ 5 + { name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" }, 6 + { name = "gleam_stdlib", version = "0.65.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "7C69C71D8C493AE11A5184828A77110EB05A7786EBF8B25B36A72F879C3EE107" }, 7 + { name = "gleeunit", version = "1.7.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "CD701726CBCE5588B375D157B4391CFD0F2F134CD12D9B6998A395484DE05C58" }, 8 + { name = "simplifile", version = "2.3.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "0A868DAC6063D9E983477981839810DC2E553285AB4588B87E3E9C96A7FB4CB4" }, 9 + ] 10 + 11 + [requirements] 12 + gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" } 13 + gleeunit = { version = ">= 1.0.0 and < 2.0.0" } 14 + simplifile = { version = ">= 2.3.0 and < 3.0.0" }
+93
2025/7/gleam/src/main.gleam
··· 1 + import gleam/dict 2 + import gleam/int 3 + import gleam/io 4 + import gleam/list 5 + import gleam/set 6 + import gleam/string 7 + import simplifile as file 8 + 9 + pub fn main() { 10 + let assert Ok(input) = file.read(from: "../input.txt") 11 + as "Input file not found" 12 + let input = input |> string.trim |> string.split("\n") 13 + let assert Ok(start) = input |> list.first 14 + let start = 15 + start 16 + |> string.to_graphemes 17 + |> list.index_fold(0, fn(acc, v, i) { 18 + case v { 19 + "S" -> i 20 + _ -> acc 21 + } 22 + }) 23 + let splitters_map = 24 + input 25 + |> list.drop(1) 26 + |> list.index_map(fn(line, i) { 27 + case i % 2 { 28 + 0 -> "" 29 + _ -> line 30 + } 31 + }) 32 + |> list.filter(fn(line) { line != "" }) 33 + |> list.map(fn(line) { 34 + line 35 + |> string.to_graphemes 36 + |> list.index_fold(set.new(), fn(d, char, i) { 37 + case char { 38 + "^" -> set.insert(d, i) 39 + _ -> d 40 + } 41 + }) 42 + }) 43 + let #(_beams, times) = 44 + splitters_map 45 + |> list.fold(#(set.new() |> set.insert(start), 0), fn(acc, splitters) { 46 + let #(beams, times) = acc 47 + beams 48 + |> set.fold(#(beams, times), fn(acc, beam) { 49 + let #(beams, times) = acc 50 + case splitters |> set.contains(beam) { 51 + False -> acc 52 + True -> #( 53 + beams 54 + |> set.delete(beam) 55 + |> set.insert(beam - 1) 56 + |> set.insert(beam + 1), 57 + times + 1, 58 + ) 59 + } 60 + }) 61 + }) 62 + 63 + times 64 + |> int.to_string 65 + |> io.println 66 + 67 + let timelines = 68 + splitters_map 69 + |> list.index_fold( 70 + dict.new() |> dict.insert("", start), 71 + fn(timelines, splitters, i) { 72 + echo i 73 + // echo #(timelines, splitters) 74 + timelines 75 + |> dict.fold(timelines, fn(timelines, timeline, beam) { 76 + case splitters |> set.contains(beam) { 77 + False -> timelines 78 + True -> { 79 + timelines 80 + |> dict.delete(timeline) 81 + |> dict.insert(timeline <> "-", beam - 1) 82 + |> dict.insert(timeline <> "+", beam + 1) 83 + } 84 + } 85 + }) 86 + }, 87 + ) 88 + echo timelines 89 + timelines 90 + |> dict.size 91 + |> int.to_string 92 + |> io.println 93 + }
+7
2025/7/rust/Cargo.lock
··· 1 + # This file is automatically @generated by Cargo. 2 + # It is not intended for manual editing. 3 + version = 4 4 + 5 + [[package]] 6 + name = "rust" 7 + version = "0.1.0"
+6
2025/7/rust/Cargo.toml
··· 1 + [package] 2 + name = "rust" 3 + version = "0.1.0" 4 + edition = "2024" 5 + 6 + [dependencies]
+62
2025/7/rust/src/main.rs
··· 1 + use std::{ 2 + collections::{HashMap, HashSet}, 3 + mem::swap, 4 + }; 5 + 6 + fn main() { 7 + let input = include_str!("../../input.txt").trim(); 8 + 9 + let input: Vec<&str> = input.trim().split("\n").collect(); 10 + // let width = input[0].len() as u64; 11 + let start = input[0].find("S").unwrap() as u64; 12 + let splitters_map: Vec<HashSet<u64>> = input[0..input.len()] 13 + .iter() 14 + .enumerate() 15 + .map(|(i, line)| if i % 2 != 0 { "" } else { line }) 16 + .filter(|line| line != &"") 17 + .map(|line| { 18 + line.chars() 19 + .enumerate() 20 + .fold(HashSet::new(), |mut s, (i, char)| { 21 + if char == '^' { 22 + s.insert(i as u64); 23 + } 24 + s 25 + }) 26 + }) 27 + .collect(); 28 + 29 + let timelines = { 30 + let mut timelines: HashMap<u64, u64> = HashMap::new(); 31 + timelines.insert(start, 1); 32 + let mut timelines_new: HashMap<u64, u64> = HashMap::new(); 33 + for splitters in splitters_map { 34 + for (pos, amount) in &timelines { 35 + if splitters.contains(&pos) { 36 + let m1 = timelines_new.entry(pos - 1).or_insert(0); 37 + *m1 += amount; 38 + let p1 = timelines_new.entry(pos + 1).or_insert(0); 39 + *p1 += amount; 40 + } else { 41 + let e = timelines_new.entry(*pos).or_insert(0); 42 + *e += amount; 43 + } 44 + } 45 + // for pos in 0..width as u64 { 46 + // if splitters.contains(&pos) { 47 + // print!("^"); 48 + // } else if timelines_new.contains_key(&pos) { 49 + // print!("|"); 50 + // } else { 51 + // print!("."); 52 + // } 53 + // } 54 + // print!("\n\n"); 55 + swap(&mut timelines, &mut timelines_new); 56 + timelines_new.clear(); 57 + } 58 + timelines 59 + }; 60 + // println!("{:?}", timelines); 61 + println!("{}", timelines.iter().fold(0, |acc, v| { acc + v.1 })) 62 + }