diff --git a/Cargo.toml b/Cargo.toml index f9ceaf8..d80e963 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,4 +19,31 @@ path = "src/2024/day1/rust/mod.rs" name = "2024_day2" path = "src/2024/day2/rust/mod.rs" +[[bin]] +name = "2024_day3" +path = "src/2024/day3/rust/mod.rs" + +[[bin]] +name = "2024_day4" +path = "src/2024/day4/rust/mod.rs" + +[lints.rust] +unsafe_code = "forbid" + +[lints.clippy] +enum_glob_use = "deny" +# pedantic = "deny" +nursery = "deny" +unwrap_used = "deny" + +[profile.release] +opt-level = 'z' +lto = true +codegen-units = 1 +panic = 'abort' +strip = "symbols" + +[dependencies] +regex = "1.11.1" + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/2024/day3/rust/mod.rs b/src/2024/day3/rust/mod.rs new file mode 100644 index 0000000..e9aef61 --- /dev/null +++ b/src/2024/day3/rust/mod.rs @@ -0,0 +1,69 @@ +use regex::Regex; + +pub fn part_a(input: &str) -> i32 { + Regex::new(r"mul\((\d+),(\d+)\)") + .expect("Regex should be valid") + .captures_iter(input) + .map(|capture| { + capture[1].parse::().expect("should be a number") + * capture[2].parse::().expect("should be a number") + }) + .sum() +} + +pub fn part_b(input: &str) -> i32 { + Regex::new(r"(mul\((\d+),(\d+)\)|do\(\)|don't\(\))") + .expect("Regex should be valid") + .captures_iter(input) + .fold((0, true), |(sum, enabled), capture| match &capture[0] { + "do()" => (sum, true), + "don't()" => (sum, false), + _ if enabled => { + let x = capture[2].parse::().expect("should be a number"); + let y = capture[3].parse::().expect("should be a number"); + (sum + x * y, enabled) + } + _ => (sum, enabled), + }) + .0 +} + +pub fn main() { + let input = include_str!("../input.txt"); + let example_input = include_str!("../input_example.txt"); + let example_input_b = include_str!("../input_example_b.txt"); + let day: u8 = 3; + println!("Day {} Example Part A: {}", day, part_a(example_input)); + println!("Day {} Part A: {}", day, part_a(input)); + println!("Day {} Example Part B: {}", day, part_b(example_input_b)); + println!("Day {} Part B: {}", day, part_b(input)); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_part_a_example() { + let example_input = include_str!("../input_example.txt"); + assert_eq!(part_a(example_input), 161); + } + + #[test] + fn test_part_a() { + let input = include_str!("../input.txt"); + assert_eq!(part_a(input), 184576302); + } + + #[test] + fn test_part_b_example() { + let example_input_b = include_str!("../input_example_b.txt"); + assert_eq!(part_b(example_input_b), 48); + } + + #[test] + fn test_part_b() { + let input = include_str!("../input.txt"); + assert_eq!(part_b(input), 118173507); + } +} diff --git a/src/2024/day4/rust/mod.rs b/src/2024/day4/rust/mod.rs new file mode 100644 index 0000000..2bde1e8 --- /dev/null +++ b/src/2024/day4/rust/mod.rs @@ -0,0 +1,93 @@ +pub fn part_a(input: &str) -> i32 { + let grid: Vec> = input.lines().map(|line| line.chars().collect()).collect(); + let target_word = "XMAS"; + grid.iter().enumerate().fold(0, |acc, (y, row)| { + acc + row.iter().enumerate().fold(0, |inner_acc, (x, _)| { + inner_acc + + [ + (1, 0), + (-1, 0), + (0, 1), + (0, -1), + (1, 1), + (-1, -1), + (-1, 1), + (1, -1), + ] + .iter() + .filter(|&&(dx, dy)| { + (0..target_word.len()).all(|i| { + let nx = (x as isize + i as isize * dx) as usize; + let ny = (y as isize + i as isize * dy) as usize; + ny < grid.len() + && nx < grid[ny].len() + && grid[ny][nx] + == target_word + .chars() + .nth(i) + .expect("index should not be out of bounds") + }) + }) + .count() + }) + }) as i32 +} + +pub fn part_b(input: &str) -> i32 { + let grid: Vec> = input.lines().map(|line| line.chars().collect()).collect(); + (1..grid.len() - 1).fold(0, |count, y| { + (1..grid[y].len() - 1).fold(count, |inner_count, x| { + if grid[y][x] == 'A' { + match (grid[y - 1][x - 1], grid[y + 1][x + 1]) { + ('M', 'S') | ('S', 'M') => match (grid[y - 1][x + 1], grid[y + 1][x - 1]) { + ('M', 'S') | ('S', 'M') => inner_count + 1, + _ => inner_count, + }, + _ => inner_count, + } + } else { + inner_count + } + }) + }) +} + +pub fn main() { + let input = include_str!("../input.txt"); + let example_input = include_str!("../input_example.txt"); + // let example_input_b = include_str!("../input_example_b.txt"); + let day: u8 = 4; + println!("Day {} Example Part A: {}", day, part_a(example_input)); + println!("Day {} Part A: {}", day, part_a(input)); + println!("Day {} Example Part B: {}", day, part_b(example_input)); + println!("Day {} Part B: {}", day, part_b(input)); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_part_a_example() { + let example_input = include_str!("../input_example.txt"); + assert_eq!(part_a(example_input), 18); + } + + #[test] + fn test_part_a() { + let input = include_str!("../input.txt"); + assert_eq!(part_a(input), 2378); + } + + #[test] + fn test_part_b_example() { + let example_input_b = include_str!("../input_example.txt"); + assert_eq!(part_b(example_input_b), 9); + } + + #[test] + fn test_part_b() { + let input = include_str!("../input.txt"); + assert_eq!(part_b(input), 1796); + } +}