Advent of Code solutions

Use crane and stuff

bwc9876.dev bd581c2f 45589225

verified
+393 -193
+1 -6
Cargo.toml
··· 5 5 6 6 [workspace] 7 7 8 - members = [ 9 - "advent_core", 10 - "macros", 11 - "utils", 12 - "years/*" 13 - ] 8 + members = ["advent_core", "macros", "utils", "years/*"] 14 9 15 10 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 16 11
+1 -1
advent_core/src/lib.rs
··· 7 7 8 8 pub use bootstrap::make_year; 9 9 pub use day::Day; 10 - pub use parser::{DP, Selection, YDP, get_dp_and_input, get_ydp_and_input}; 10 + pub use parser::{get_dp_and_input, get_ydp_and_input, Selection, DP, YDP}; 11 11 pub use year::Year;
+1 -1
advent_core/src/parser.rs
··· 1 1 use std::env::args; 2 2 use std::fs; 3 - use std::io::{Read, stdin}; 3 + use std::io::{stdin, Read}; 4 4 5 5 #[derive(Clone, Debug)] 6 6 pub enum Selection {
+1 -1
advent_core/src/year.rs
··· 1 - use crate::parser::{DP, Selection}; 1 + use crate::parser::{Selection, DP}; 2 2 3 3 use super::MAX_DAY; 4 4
+108 -4
flake.lock
··· 1 1 { 2 2 "nodes": { 3 + "crane": { 4 + "locked": { 5 + "lastModified": 1765145449, 6 + "narHash": "sha256-aBVHGWWRzSpfL++LubA0CwOOQ64WNLegrYHwsVuVN7A=", 7 + "owner": "ipetkov", 8 + "repo": "crane", 9 + "rev": "69f538cdce5955fcd47abfed4395dc6d5194c1c5", 10 + "type": "github" 11 + }, 12 + "original": { 13 + "owner": "ipetkov", 14 + "repo": "crane", 15 + "type": "github" 16 + } 17 + }, 18 + "fenix": { 19 + "inputs": { 20 + "nixpkgs": "nixpkgs", 21 + "rust-analyzer-src": "rust-analyzer-src" 22 + }, 23 + "locked": { 24 + "lastModified": 1765003156, 25 + "narHash": "sha256-k4YrPUhRj7Ciq385vREU57RHiDFycY5RaJwdCOmsLhU=", 26 + "owner": "nix-community", 27 + "repo": "fenix", 28 + "rev": "e8361cc010853d17740a63aae00385061ac9de51", 29 + "type": "github" 30 + }, 31 + "original": { 32 + "owner": "nix-community", 33 + "repo": "fenix", 34 + "type": "github" 35 + } 36 + }, 37 + "flakelight": { 38 + "inputs": { 39 + "nixpkgs": "nixpkgs_2" 40 + }, 41 + "locked": { 42 + "lastModified": 1765198385, 43 + "narHash": "sha256-pFzfw2g98QdI69IUueBWx/peDG+HGnToelHXHS82p/8=", 44 + "owner": "nix-community", 45 + "repo": "flakelight", 46 + "rev": "b6028a5af905d29cfc20fa80e0eac915c840f9a8", 47 + "type": "github" 48 + }, 49 + "original": { 50 + "owner": "nix-community", 51 + "repo": "flakelight", 52 + "type": "github" 53 + } 54 + }, 3 55 "nixpkgs": { 4 56 "locked": { 5 - "lastModified": 1732937961, 6 - "narHash": "sha256-B5pYT+IVaqcrfOekkwKvx/iToDnuQWzc2oyDxzzBDc4=", 57 + "lastModified": 1764667669, 58 + "narHash": "sha256-7WUCZfmqLAssbDqwg9cUDAXrSoXN79eEEq17qhTNM/Y=", 7 59 "owner": "nixos", 8 60 "repo": "nixpkgs", 9 - "rev": "4703b8d2c708e13a8cab03d865f90973536dcdf5", 61 + "rev": "418468ac9527e799809c900eda37cbff999199b6", 62 + "type": "github" 63 + }, 64 + "original": { 65 + "owner": "nixos", 66 + "ref": "nixos-unstable", 67 + "repo": "nixpkgs", 68 + "type": "github" 69 + } 70 + }, 71 + "nixpkgs_2": { 72 + "locked": { 73 + "lastModified": 1764950072, 74 + "narHash": "sha256-BmPWzogsG2GsXZtlT+MTcAWeDK5hkbGRZTeZNW42fwA=", 75 + "owner": "NixOS", 76 + "repo": "nixpkgs", 77 + "rev": "f61125a668a320878494449750330ca58b78c557", 78 + "type": "github" 79 + }, 80 + "original": { 81 + "owner": "NixOS", 82 + "ref": "nixos-unstable", 83 + "repo": "nixpkgs", 84 + "type": "github" 85 + } 86 + }, 87 + "nixpkgs_3": { 88 + "locked": { 89 + "lastModified": 1764947035, 90 + "narHash": "sha256-EYHSjVM4Ox4lvCXUMiKKs2vETUSL5mx+J2FfutM7T9w=", 91 + "owner": "nixos", 92 + "repo": "nixpkgs", 93 + "rev": "a672be65651c80d3f592a89b3945466584a22069", 10 94 "type": "github" 11 95 }, 12 96 "original": { ··· 18 102 }, 19 103 "root": { 20 104 "inputs": { 21 - "nixpkgs": "nixpkgs" 105 + "crane": "crane", 106 + "fenix": "fenix", 107 + "flakelight": "flakelight", 108 + "nixpkgs": "nixpkgs_3" 109 + } 110 + }, 111 + "rust-analyzer-src": { 112 + "flake": false, 113 + "locked": { 114 + "lastModified": 1764925941, 115 + "narHash": "sha256-zldc1SrUIhGMdQp+0woSqvBS51Mi8PW6JukONBQXZBY=", 116 + "owner": "rust-lang", 117 + "repo": "rust-analyzer", 118 + "rev": "2cbf3587d36dfc7b701ebb744d3dd5064355d04f", 119 + "type": "github" 120 + }, 121 + "original": { 122 + "owner": "rust-lang", 123 + "ref": "nightly", 124 + "repo": "rust-analyzer", 125 + "type": "github" 22 126 } 23 127 } 24 128 },
+119 -31
flake.nix
··· 1 1 { 2 - inputs.nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; 2 + inputs = { 3 + nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; 4 + flakelight.url = "github:nix-community/flakelight"; 5 + crane.url = "github:ipetkov/crane"; 6 + fenix.url = "github:nix-community/fenix"; 7 + }; 3 8 4 9 outputs = { 5 10 self, 6 11 nixpkgs, 12 + flakelight, 13 + crane, 14 + fenix, 7 15 }: let 8 - forAllSystems = nixpkgs.lib.genAttrs [ 9 - "aarch64-linux" 10 - "aarch64-darwin" 11 - "x86_64-darwin" 12 - "x86_64-linux" 13 - ]; 14 - pkgsFor = system: import nixpkgs {inherit system;}; 15 - in { 16 - packages = 17 - forAllSystems 18 - (system: let 19 - pkgs = pkgsFor system; 20 - in { 21 - default = pkgs.rustPlatform.buildRustPackage { 22 - pname = "advent"; 23 - version = "0.1.0"; 24 - src = ./.; 25 - cargoLock.lockFile = ./Cargo.lock; 16 + inherit (nixpkgs) lib; 17 + selectToolchain = fenix: fenix.complete; 18 + mkCrane = pkgs: let 19 + inherit (selectToolchain pkgs.fenix) toolchain; 20 + craneLib = (crane.mkLib nixpkgs.legacyPackages.${pkgs.system}).overrideToolchain toolchain; 21 + rawSrc = ./.; 22 + src = lib.fileset.toSource { 23 + root = rawSrc; 24 + fileset = lib.fileset.unions [ 25 + ./advent_core 26 + ./src 27 + ./macros 28 + ./utils 29 + ./years 30 + ./Cargo.lock 31 + ./Cargo.toml 32 + ]; 33 + }; 34 + commonArgs = { 35 + inherit src; 36 + strictDeps = true; 37 + }; 38 + cargoArtifacts = craneLib.buildDepsOnly commonArgs; 39 + individualCrateArgs = 40 + commonArgs 41 + // { 42 + inherit cargoArtifacts src; 43 + inherit (craneLib.crateNameFromCargoToml {inherit src;}) version; 44 + # NB: we disable tests since we'll run them all via cargo-nextest 45 + doCheck = false; 26 46 }; 27 - }); 28 - devShells = forAllSystems: ( 29 - system: let 30 - pkgs = pkgsFor system; 47 + buildCrate = pname: 48 + craneLib.buildPackage ( 49 + individualCrateArgs 50 + // { 51 + inherit pname; 52 + cargoExtraArgs = "-p ${pname}"; 53 + } 54 + ); 55 + in { 56 + inherit 57 + craneLib 58 + src 59 + commonArgs 60 + cargoArtifacts 61 + individualCrateArgs 62 + buildCrate 63 + ; 64 + }; 65 + years = builtins.attrNames (lib.filterAttrs (_: v: v == "directory") (builtins.readDir ./years)); 66 + allCrates = 67 + (builtins.map (y: "y_${y}") years) 68 + ++ [ 69 + "advent" 70 + "advent_core" 71 + "utils" 72 + "macros" 73 + ]; 74 + forAllCrates = lib.genAttrs' allCrates; 75 + in 76 + flakelight ./. { 77 + lib = { 78 + inherit years allCrates; 79 + }; 80 + nixpkgs.overlays = [fenix.overlays.default]; 81 + flakelight.builtinFormatters = false; 82 + formatters = pkgs: let 83 + alejandra = "${pkgs.lib.getExe pkgs.alejandra} ."; 84 + rustfmt = "${(selectToolchain pkgs.fenix).rustfmt}/bin/rustfmt ."; 85 + taplo = "${pkgs.lib.getExe pkgs.taplo} fmt ."; 31 86 in { 32 - default = pkgs.mkShell { 33 - packages = with pkgs; [ 34 - cargo 35 - just 36 - ]; 87 + "*.nix" = alejandra; 88 + "*.rs" = rustfmt; 89 + "*.toml" = taplo; 90 + }; 91 + packages = 92 + forAllCrates (name: { 93 + inherit name; 94 + value = pkgs: (mkCrane pkgs).buildCrate name; 95 + }) 96 + // { 97 + default = pkgs: (mkCrane pkgs).buildCrate "advent"; 98 + }; 99 + checks = pkgs: let 100 + inherit (mkCrane pkgs) commonArgs craneLib cargoArtifacts; 101 + in 102 + forAllCrates (name: { 103 + name = "clippy-${name}"; 104 + value = craneLib.cargoClippy ( 105 + commonArgs 106 + // { 107 + inherit cargoArtifacts; 108 + cargoClippyExtraArgs = "--all-targets -p ${name} -- --deny warnings"; 109 + } 110 + ); 111 + }) 112 + // forAllCrates (name: { 113 + name = "nextest-${name}"; 114 + value = craneLib.cargoNextest ( 115 + commonArgs 116 + // { 117 + inherit cargoArtifacts; 118 + partitions = 1; 119 + partitionType = "count"; 120 + cargoNextestPartitionsExtraArgs = "--no-tests=pass -p ${name}"; 121 + } 122 + ); 123 + }); 124 + devShell = pkgs: 125 + (mkCrane pkgs).craneLib.devShell { 126 + checks = self.checks.${pkgs.system}; 37 127 }; 38 - } 39 - ); 40 - }; 128 + }; 41 129 }
+1 -1
macros/Cargo.toml
··· 9 9 proc-macro = true 10 10 11 11 [dependencies] 12 - advent_core = { path = "../advent_core" } 12 + advent_core = { path = "../advent_core" }
+1 -1
utils/src/grid.rs
··· 157 157 } 158 158 159 159 /// Obtain a mutable reference to a tile in the grid 160 - pub fn get_mut<'a>(&'a mut self, pos: Position) -> Option<&'a mut T> { 160 + pub fn get_mut(&mut self, pos: Position) -> Option<&mut T> { 161 161 self.data 162 162 .get_mut(pos.y as usize) 163 163 .and_then(|row| row.get_mut(pos.x as usize))
+22 -21
years/2024/src/day_1.rs
··· 1 - use advent_core::{Day, day_stuff, ex_for_day}; 1 + use advent_core::{day_stuff, ex_for_day, Day}; 2 2 use utils::misc::counts; 3 3 4 4 pub struct Day1; 5 5 6 6 impl Day for Day1 { 7 - 8 7 day_stuff!(1, "11", "31", (Vec<i32>, Vec<i32>)); 9 8 10 9 fn part_1(input: Self::Input) -> Option<String> { ··· 12 11 l.sort_unstable(); 13 12 r.sort_unstable(); 14 13 15 - Some(l.into_iter() 16 - .zip(r) 17 - .map(|(l, r)| (l - r).abs()) 18 - .sum::<i32>() 19 - .to_string() 14 + Some( 15 + l.into_iter() 16 + .zip(r) 17 + .map(|(l, r)| (l - r).abs()) 18 + .sum::<i32>() 19 + .to_string(), 20 20 ) 21 21 } 22 22 23 23 fn part_2(input: Self::Input) -> Option<String> { 24 24 let (l, r) = input; 25 25 let apr = counts(r.into_iter()); 26 - Some(l.into_iter() 27 - .map(|l| 28 - l as u64 * apr.get(&l).unwrap_or(&0) 29 - ) 30 - .sum::<u64>() 31 - .to_string() 26 + Some( 27 + l.into_iter() 28 + .map(|l| l as u64 * apr.get(&l).unwrap_or(&0)) 29 + .sum::<u64>() 30 + .to_string(), 32 31 ) 33 32 } 34 - 33 + 35 34 fn parse_input(input: &str) -> Self::Input { 36 - input.split("\n").map(|line| { 37 - let mut split = line.trim().split_ascii_whitespace(); 38 - let left = split.next().unwrap().parse::<i32>().unwrap(); 39 - let right = split.next().unwrap().parse::<i32>().unwrap(); 40 - (left, right) 41 - }).collect() 35 + input 36 + .split("\n") 37 + .map(|line| { 38 + let mut split = line.trim().split_ascii_whitespace(); 39 + let left = split.next().unwrap().parse::<i32>().unwrap(); 40 + let right = split.next().unwrap().parse::<i32>().unwrap(); 41 + (left, right) 42 + }) 43 + .collect() 42 44 } 43 - 44 45 }
+5 -7
years/2024/src/day_11.rs
··· 20 20 for (num, count) in stone_map { 21 21 if num == 0 { 22 22 *new_map.entry(1).or_insert(0) += count; 23 + } else if num_digits(num).is_multiple_of(2) { 24 + let (left, right) = split_num_once(num); 25 + *new_map.entry(left).or_insert(0) += count; 26 + *new_map.entry(right).or_insert(0) += count; 23 27 } else { 24 - if num_digits(num) % 2 == 0 { 25 - let (left, right) = split_num_once(num); 26 - *new_map.entry(left).or_insert(0) += count; 27 - *new_map.entry(right).or_insert(0) += count; 28 - } else { 29 - *new_map.entry(num * 2024).or_insert(0) += count; 30 - } 28 + *new_map.entry(num * 2024).or_insert(0) += count; 31 29 } 32 30 } 33 31
+1 -1
years/2024/src/day_12.rs
··· 19 19 ) -> (usize, HashSet<Position>) { 20 20 let mut perims = HashSet::with_capacity(100); 21 21 let mut turns = 0; 22 - let mut curs = GridCursor::new(&grid, starting_pos, initial_dir); 22 + let mut curs = GridCursor::new(grid, starting_pos, initial_dir); 23 23 let mut init = false; 24 24 25 25 while (curs.pos, curs.dir) != (starting_pos, initial_dir) || !init {
+4 -4
years/2024/src/day_17.rs
··· 10 10 } 11 11 12 12 impl Registers { 13 - fn from_combo_op(&self, combo_op: &ComboOperand) -> u128 { 13 + fn with_combo_op(&self, combo_op: &ComboOperand) -> u128 { 14 14 match combo_op { 15 15 ComboOperand::RegA => self.a, 16 16 ComboOperand::RegB => self.b, ··· 44 44 match self { 45 45 Self::Literal(v) => *v, 46 46 Self::Reserved => panic!(), 47 - reg => regs.from_combo_op(reg), 47 + reg => regs.with_combo_op(reg), 48 48 } 49 49 } 50 50 } ··· 85 85 regs.a /= 2_u128.pow(op.get_val(regs) as u32); 86 86 } 87 87 Self::Bxl(v) => { 88 - regs.b = regs.b ^ v; 88 + regs.b ^= v; 89 89 } 90 90 Self::Bst(op) => { 91 91 regs.b = op.get_val(regs) % 8; ··· 96 96 } 97 97 } 98 98 Self::Bxc(_) => { 99 - regs.b = regs.b ^ regs.c; 99 + regs.b ^= regs.c; 100 100 } 101 101 Self::Out(op) => { 102 102 return (ip + 2, Some(op.get_val(regs) % 8));
+34 -15
years/2024/src/day_2.rs
··· 1 - 2 - use advent_core::{Day, day_stuff, ex_for_day}; 1 + use advent_core::{day_stuff, ex_for_day, Day}; 3 2 use utils::misc::{all_combos_remove_one, follows_diff_range, FollowRangeResult}; 4 3 5 4 pub struct Day2; 6 5 7 6 fn line_valid(line: &[i64]) -> bool { 8 7 let res = follows_diff_range(line, -3..4, true, false); 9 - matches!(res, FollowRangeResult::Increasing | FollowRangeResult::Decreasing) 8 + matches!( 9 + res, 10 + FollowRangeResult::Increasing | FollowRangeResult::Decreasing 11 + ) 10 12 } 11 13 12 14 impl Day for Day2 { 13 - 14 15 day_stuff!(2, "2", "4", Vec<Vec<i64>>); 15 16 16 17 fn part_1(input: Self::Input) -> Option<String> { 17 - Some(input.into_iter().filter(|v| line_valid(v)).count().to_string()) 18 + Some( 19 + input 20 + .into_iter() 21 + .filter(|v| line_valid(v)) 22 + .count() 23 + .to_string(), 24 + ) 18 25 } 19 26 20 27 fn part_2(input: Self::Input) -> Option<String> { 21 - Some(input.into_iter().filter(|line| { 22 - line_valid(line) || 23 - all_combos_remove_one(line) 24 - .any(|combo| { 25 - let v = combo.copied().collect::<Vec<_>>(); 26 - line_valid(&v) 27 - }) 28 - }).count().to_string()) 28 + Some( 29 + input 30 + .into_iter() 31 + .filter(|line| { 32 + line_valid(line) 33 + || all_combos_remove_one(line).any(|combo| { 34 + let v = combo.copied().collect::<Vec<_>>(); 35 + line_valid(&v) 36 + }) 37 + }) 38 + .count() 39 + .to_string(), 40 + ) 29 41 } 30 - 42 + 31 43 fn parse_input(input: &str) -> Self::Input { 32 - input.split('\n').map(|l| l.split_ascii_whitespace().map(|x| x.parse::<i64>().unwrap()).collect()).collect() 44 + input 45 + .split('\n') 46 + .map(|l| { 47 + l.split_ascii_whitespace() 48 + .map(|x| x.parse::<i64>().unwrap()) 49 + .collect() 50 + }) 51 + .collect() 33 52 } 34 53 }
+4 -6
years/2024/src/day_20.rs
··· 28 28 costs.insert(curs, cost); 29 29 let (_, next_pos, _) = input 30 30 .relatives(curs, &CARDINALS) 31 - .filter(|(_, p, t)| **t != Tile::Wall && !costs.contains_key(p)) 32 - .next() 31 + .find(|(_, p, t)| **t != Tile::Wall && !costs.contains_key(p)) 33 32 .unwrap(); 34 33 curs = next_pos; 35 34 cost += 1; ··· 41 40 for (pos_b, cost_b) in costs.iter() { 42 41 if cost_b < cost_a { 43 42 let diff = *cost_a - *cost_b; 44 - let dist = pos_a.manhattan(&pos_b).abs() as usize; 43 + let dist = pos_a.manhattan(pos_b).unsigned_abs(); 45 44 if dist <= 2 { 46 45 cheat_set.insert((*pos_a, *pos_b), diff - dist); 47 46 } ··· 64 63 costs.insert(curs, cost); 65 64 let (_, next_pos, _) = input 66 65 .relatives(curs, &CARDINALS) 67 - .filter(|(_, p, t)| **t != Tile::Wall && !costs.contains_key(p)) 68 - .next() 66 + .find(|(_, p, t)| **t != Tile::Wall && !costs.contains_key(p)) 69 67 .unwrap(); 70 68 curs = next_pos; 71 69 cost += 1; ··· 77 75 for (pos_b, cost_b) in costs.iter() { 78 76 if cost_b < cost_a { 79 77 let diff = *cost_a - *cost_b; 80 - let dist = pos_a.manhattan(&pos_b).abs() as usize; 78 + let dist = pos_a.manhattan(pos_b).unsigned_abs(); 81 79 if dist <= 20 { 82 80 cheat_set.insert((*pos_a, *pos_b), diff - dist); 83 81 }
+1 -3
years/2024/src/day_22.rs
··· 35 35 .fold(HashMap::with_capacity(times / 4), |mut acc, w| { 36 36 let changes = [w[0].0, w[1].0, w[2].0, w[3].0]; 37 37 let final_val = w[3].1; 38 - if !acc.contains_key(&changes) { 39 - acc.insert(changes, final_val); 40 - } 38 + acc.entry(changes).or_insert(final_val); 41 39 acc 42 40 }) 43 41 }
+5 -5
years/2024/src/day_24.rs
··· 42 42 let lhs = s.next().unwrap().to_string(); 43 43 let op = s.next().unwrap(); 44 44 let rhs = s.next().unwrap().to_string(); 45 - let target = s.skip(1).next().unwrap().to_string(); 45 + let target = s.nth(1).unwrap().to_string(); 46 46 let op = match op { 47 47 "AND" => Op::And, 48 48 "OR" => Op::Or, ··· 134 134 // #2 & #5, ^ 135 135 // #4 & #5, ^ 136 136 // 137 - fn test_adder(num: usize, carry_input: &String, gates: &Gates) -> AdderTestResult { 137 + fn test_adder(num: usize, carry_input: &str, gates: &Gates) -> AdderTestResult { 138 138 let x = format!("x{num:02}"); 139 139 let y = format!("y{num:02}"); 140 140 let z = format!("z{num:02}"); ··· 153 153 ) { 154 154 if let Some(Gate { 155 155 target: z_target, .. 156 - }) = find_gate(gates, &carry_input, xy_xor_target.as_str(), Op::Xor) 156 + }) = find_gate(gates, carry_input, xy_xor_target.as_str(), Op::Xor) 157 157 { 158 158 if *z_target != z { 159 159 // We know gate #3 is pointing to the wrong target, as it should be pointing to z[] ··· 173 173 174 174 // From here we've checked all test cases, we can confidently attempt to find the carry 175 175 // output now 176 - let carry_xy_target = &find_gate(&gates, xy_xor_target, &carry_input, Op::And) 176 + let carry_xy_target = &find_gate(gates, xy_xor_target, carry_input, Op::And) 177 177 .expect("Failed to find carry_xy_target") 178 178 .target; 179 - let carry_out = &find_gate(&gates, carry_xy_target, xy_and_target, Op::Or) 179 + let carry_out = &find_gate(gates, carry_xy_target, xy_and_target, Op::Or) 180 180 .expect("Failed to find carry_out") 181 181 .target; 182 182 if *carry_out == format!("z{:02}", num + 1) {
+14 -11
years/2024/src/day_3.rs
··· 1 - 2 - use advent_core::{Day, day_stuff, ex_for_day}; 1 + use advent_core::{day_stuff, ex_for_day, Day}; 3 2 use regex::RegexBuilder; 4 3 5 4 pub struct Day3; ··· 8 7 9 8 fn re_do(i: &str) -> u64 { 10 9 let re = RegexBuilder::new(RE).multi_line(true).build().unwrap(); 11 - re.captures_iter(i).map(|c| { 12 - c.get(1).unwrap().as_str().parse::<u64>().unwrap() 13 - * 14 - c.get(2).unwrap().as_str().parse::<u64>().unwrap() 15 - }).sum::<u64>() 10 + re.captures_iter(i) 11 + .map(|c| { 12 + c.get(1).unwrap().as_str().parse::<u64>().unwrap() 13 + * c.get(2).unwrap().as_str().parse::<u64>().unwrap() 14 + }) 15 + .sum::<u64>() 16 16 } 17 17 18 18 impl Day for Day3 { 19 - 20 19 day_stuff!(3, "161", "48"); 21 20 22 21 fn part_1(input: Self::Input) -> Option<String> { ··· 24 23 } 25 24 26 25 fn part_2(input: Self::Input) -> Option<String> { 27 - Some(input.split("do()").map(|v| 28 - re_do(v.split("don't()").nth(0).unwrap()) 29 - ).sum::<u64>().to_string()) 26 + Some( 27 + input 28 + .split("do()") 29 + .map(|v| re_do(v.split("don't()").nth(0).unwrap())) 30 + .sum::<u64>() 31 + .to_string(), 32 + ) 30 33 } 31 34 }
+48 -29
years/2024/src/day_5.rs
··· 1 - 2 1 use std::collections::{HashMap, HashSet}; 3 2 4 - use advent_core::{Day, day_stuff, ex_for_day}; 3 + use advent_core::{day_stuff, ex_for_day, Day}; 5 4 6 5 pub struct Day5; 7 6 8 7 #[derive(Clone, Debug)] 9 - pub struct Rules(HashMap<i64,Vec<i64>>); 8 + pub struct Rules(HashMap<i64, Vec<i64>>); 10 9 11 10 impl Rules { 12 11 pub fn take(&mut self, lhs: i64, rhs: i64) { 13 - self.0.entry(lhs).and_modify(|seen| { seen.push(rhs); }).or_insert(vec![rhs]); 12 + self.0 13 + .entry(lhs) 14 + .and_modify(|seen| { 15 + seen.push(rhs); 16 + }) 17 + .or_insert(vec![rhs]); 14 18 } 15 19 16 20 fn good(&self, up: &[i64]) -> bool { 17 21 let mut seen = HashSet::new(); 18 22 for u in up.iter() { 19 - if self.0.get(u).is_none_or(|should| should.iter().all(|s| !seen.contains(s))) { 20 - seen.insert(*u); 23 + if self 24 + .0 25 + .get(u) 26 + .is_none_or(|should| should.iter().all(|s| !seen.contains(s))) 27 + { 28 + seen.insert(*u); 21 29 } else { 22 30 return false; 23 31 } ··· 25 33 true 26 34 } 27 35 28 - fn sort_to_rules(&self, up: &mut[i64]) { 36 + fn sort_to_rules(&self, up: &mut [i64]) { 29 37 while !self.good(up) { 30 38 self.sort_step(up); 31 39 } 32 40 } 33 41 34 - fn sort_step(&self, up: &mut[i64]) { 35 - for i in 0..up.len()-1 { 36 - for j in i+1..up.len() { 42 + fn sort_step(&self, up: &mut [i64]) { 43 + for i in 0..up.len() - 1 { 44 + for j in i + 1..up.len() { 37 45 if self.0.get(&up[j]).is_some_and(|shld| shld.contains(&up[i])) { 38 46 up.swap(i, j); 39 - } 47 + } 40 48 } 41 49 } 42 50 } 43 51 } 44 52 45 53 impl Day for Day5 { 46 - 47 54 day_stuff!(5, "143", "123", (Rules, Vec<Vec<i64>>)); 48 55 49 56 fn part_1(input: Self::Input) -> Option<String> { 50 57 let (rules, updates) = input; 51 - let ans = updates.into_iter().filter_map(|up| { 52 - if rules.good(&up) { 53 - Some(up[up.len() / 2]) 54 - } else { 55 - None 56 - } 57 - }).sum::<i64>(); 58 + let ans = updates 59 + .into_iter() 60 + .filter_map(|up| { 61 + if rules.good(&up) { 62 + Some(up[up.len() / 2]) 63 + } else { 64 + None 65 + } 66 + }) 67 + .sum::<i64>(); 58 68 Some(ans.to_string()) 59 69 } 60 70 61 71 fn part_2(input: Self::Input) -> Option<String> { 62 72 let (rules, updates) = input; 63 - let ans = updates.into_iter().filter_map(|mut up| { 64 - if !rules.good(&up) { 65 - rules.sort_to_rules(&mut up); 66 - Some(up[up.len() / 2]) 67 - } else { 68 - None 69 - } 70 - }).sum::<i64>(); 73 + let ans = updates 74 + .into_iter() 75 + .filter_map(|mut up| { 76 + if !rules.good(&up) { 77 + rules.sort_to_rules(&mut up); 78 + Some(up[up.len() / 2]) 79 + } else { 80 + None 81 + } 82 + }) 83 + .sum::<i64>(); 71 84 Some(ans.to_string()) 72 85 } 73 - 86 + 74 87 fn parse_input(input: &str) -> Self::Input { 75 88 let (rules, updates) = input.split_once("\n\n").unwrap(); 76 89 let mut rules_o = Rules(HashMap::with_capacity(50)); ··· 78 91 let (lhs, rhs) = l.split_once('|').unwrap(); 79 92 rules_o.take(lhs.parse().unwrap(), rhs.parse().unwrap()); 80 93 } 81 - (rules_o, updates.split('\n').map(|l| l.split(',').map(|x| x.parse().unwrap()).collect()).collect()) 94 + ( 95 + rules_o, 96 + updates 97 + .split('\n') 98 + .map(|l| l.split(',').map(|x| x.parse().unwrap()).collect()) 99 + .collect(), 100 + ) 82 101 } 83 102 }
+4 -6
years/2024/src/day_9.rs
··· 107 107 loop { 108 108 if let (Block::File(_), _) = input.data[i] { 109 109 let next_blank = input.iter_blanks_before(i).next(); 110 - if let Some((j, _)) = next_blank { 111 - if input.swap_blocks(i, j) { 110 + if let Some((j, _)) = next_blank 111 + && input.swap_blocks(i, j) { 112 112 i += 1; 113 113 } 114 - } 115 114 } 116 115 if i == 0 { 117 116 break; ··· 131 130 let next_blank = input 132 131 .iter_blanks_before(i) 133 132 .find(|(_, b_amnt)| *b_amnt >= size); 134 - if let Some((j, _)) = next_blank { 135 - if input.swap_blocks(i, j) { 133 + if let Some((j, _)) = next_blank 134 + && input.swap_blocks(i, j) { 136 135 i += 1; 137 136 } 138 - } 139 137 } 140 138 if i == 0 { 141 139 break;
+1 -1
years/2025/src/day_1.rs
··· 1 - use advent_core::{Day, day_stuff, ex_for_day}; 1 + use advent_core::{day_stuff, ex_for_day, Day}; 2 2 3 3 pub struct Day1; 4 4
+1 -3
years/2025/src/day_10.rs
··· 1 - 2 - use advent_core::{Day, day_stuff, ex_for_day}; 1 + use advent_core::{day_stuff, ex_for_day, Day}; 3 2 4 3 pub struct Day10; 5 4 6 5 impl Day for Day10 { 7 - 8 6 day_stuff!(10, "", ""); 9 7 10 8 fn part_1(_input: Self::Input) -> Option<String> {
+1 -3
years/2025/src/day_11.rs
··· 1 - 2 - use advent_core::{Day, day_stuff, ex_for_day}; 1 + use advent_core::{day_stuff, ex_for_day, Day}; 3 2 4 3 pub struct Day11; 5 4 6 5 impl Day for Day11 { 7 - 8 6 day_stuff!(11, "", ""); 9 7 10 8 fn part_1(_input: Self::Input) -> Option<String> {
+1 -3
years/2025/src/day_12.rs
··· 1 - 2 - use advent_core::{Day, day_stuff, ex_for_day}; 1 + use advent_core::{day_stuff, ex_for_day, Day}; 3 2 4 3 pub struct Day12; 5 4 6 5 impl Day for Day12 { 7 - 8 6 day_stuff!(12, "", ""); 9 7 10 8 fn part_1(_input: Self::Input) -> Option<String> {
+1 -1
years/2025/src/day_2.rs
··· 1 1 use std::ops::RangeInclusive; 2 2 3 - use advent_core::{Day, day_stuff, ex_for_day}; 3 + use advent_core::{day_stuff, ex_for_day, Day}; 4 4 use utils::num::{num_digits, split_num_at, split_num_once}; 5 5 6 6 pub struct Day2;
+1 -1
years/2025/src/day_3.rs
··· 1 - use advent_core::{Day, day_stuff, ex_for_day}; 1 + use advent_core::{day_stuff, ex_for_day, Day}; 2 2 3 3 pub struct Day3; 4 4
+1 -1
years/2025/src/day_4.rs
··· 1 - use advent_core::{Day, day_stuff, ex_for_day}; 1 + use advent_core::{day_stuff, ex_for_day, Day}; 2 2 use utils::{dir::ALL_8, tiles}; 3 3 4 4 pub struct Day4;
+1 -1
years/2025/src/day_5.rs
··· 1 - use advent_core::{Day, day_stuff, ex_for_day}; 1 + use advent_core::{day_stuff, ex_for_day, Day}; 2 2 use utils::range::BetterRange; 3 3 4 4 pub struct Day5;
+3 -9
years/2025/src/day_6.rs
··· 1 - use advent_core::{Day, day_stuff, ex_for_day}; 1 + use advent_core::{day_stuff, ex_for_day, Day}; 2 2 3 3 pub struct Day6; 4 4 ··· 22 22 .collect::<Vec<_>>() 23 23 }) 24 24 .collect::<Vec<_>>(); 25 - let ops = uno 26 - .iter() 27 - .skip(uno.len() - 1) 28 - .next() 29 - .unwrap() 30 - .split_whitespace() 31 - .collect::<Vec<_>>(); 25 + let ops = uno.last().unwrap().split_whitespace().collect::<Vec<_>>(); 32 26 let mut problems = Vec::with_capacity(uno.len()); 33 27 34 28 for i in 0..dos[0].len() { ··· 57 51 fn part_2(input: Self::Input) -> Option<String> { 58 52 let mut cols: Vec<Vec<_>> = vec![]; 59 53 60 - for (_, row) in input.lines().enumerate() { 54 + for row in input.lines() { 61 55 for (j, c) in row.chars().enumerate() { 62 56 if let Some(r) = cols.get_mut(j) { 63 57 r.push(c);
+1 -1
years/2025/src/day_7.rs
··· 1 1 use std::collections::{HashMap, HashSet, VecDeque}; 2 2 3 - use advent_core::{Day, day_stuff, ex_for_day}; 3 + use advent_core::{day_stuff, ex_for_day, Day}; 4 4 use utils::{dir::Direction, pos::Position, tiles}; 5 5 6 6 pub struct Day7;
+5 -12
years/2025/src/day_8.rs
··· 1 1 use std::{collections::HashMap, ops::Sub}; 2 2 3 - use advent_core::{Day, day_stuff, ex_for_day}; 3 + use advent_core::{day_stuff, ex_for_day, Day}; 4 4 5 5 pub struct Day8; 6 6 ··· 48 48 49 49 let mut counts = circuits 50 50 .into_iter() 51 - .fold(HashMap::new(), |mut acc, (_, c)| { 51 + .fold(HashMap::with_capacity(input.len()), |mut acc, (_, c)| { 52 52 *(acc.entry(c).or_insert(0)) += 1; 53 53 acc 54 54 }) 55 - .into_iter() 56 - .map(|(_, count)| count) 55 + .into_values() 57 56 .collect::<Vec<_>>(); 58 57 59 58 counts.sort_by(|a, b| a.cmp(b).reverse()); 60 59 61 - Some( 62 - counts 63 - .into_iter() 64 - .take(3) 65 - .fold(1, |acc, x| acc * x) 66 - .to_string(), 67 - ) 60 + Some(counts.into_iter().take(3).product::<i32>().to_string()) 68 61 } 69 62 70 63 fn part_2((_amnt, input): Self::Input) -> Option<String> { ··· 99 92 } 100 93 } 101 94 102 - let (a, b) = last_2.unwrap(); 95 + let (a, b) = last_2.expect("Womp womp"); 103 96 104 97 Some((a.0 * b.0).to_string()) 105 98 }
+1 -3
years/2025/src/day_9.rs
··· 1 - 2 - use advent_core::{Day, day_stuff, ex_for_day}; 1 + use advent_core::{day_stuff, ex_for_day, Day}; 3 2 4 3 pub struct Day9; 5 4 6 5 impl Day for Day9 { 7 - 8 6 day_stuff!(9, "", ""); 9 7 10 8 fn part_1(_input: Self::Input) -> Option<String> {