commit 33b031c8da441a4c1f137249236f6d9832e6530d Author: shoofle Date: Thu Dec 5 15:49:00 2024 -0500 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7c8ca24 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +**/*.input + +# Generated by Cargo +# will have compiled files and executables +*/debug/ +*/target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +*/Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + diff --git a/day01/Cargo.toml b/day01/Cargo.toml new file mode 100644 index 0000000..e7d55b7 --- /dev/null +++ b/day01/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "day01" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/day01/src/main.rs b/day01/src/main.rs new file mode 100644 index 0000000..df5662a --- /dev/null +++ b/day01/src/main.rs @@ -0,0 +1,54 @@ +use std::collections::HashMap; +use std::fs; +use std::env; +use std::iter; + + +fn main() { + println!("Hello, AoC day 01!"); + + let args: Vec = env::args().collect(); + if args.len() != 2 { + println!("wrong number of arguments!"); + std::process::exit(1); + } + + let file_path = &args[1]; + + let contents = fs::read_to_string(file_path).expect("Should have been able to read the file"); + let mut first: Vec = Vec::new(); + let mut second: Vec = Vec::new(); + + let mut counts: HashMap = HashMap::new(); + + for line in contents.lines() { + let numbers: Vec<_> = line.split_whitespace().collect(); + let (first_str, second_str) = (numbers[0], numbers[1]); + let (first_num, second_num) = (first_str.parse().unwrap(), second_str.parse().unwrap()); + + first.push(first_num); + second.push(second_num); + + let count = counts.entry(second_num).or_insert(0); + *count = *count + 1; + } + + first.sort(); + second.sort(); + + let mut sum:i32 = 0; + for (first_num, second_num) in iter::zip(first.iter(), second.iter()) { + let difference = (first_num - second_num).abs(); + + sum = sum + difference; + } + + println!("the sum of the differences is {sum}"); + + let mut similarity: i32 = 0; + for num in first { + similarity += num * counts.get(&num).unwrap_or(&0); + } + + println!("similarity score is {similarity}"); +} \ No newline at end of file diff --git a/day02/Cargo.toml b/day02/Cargo.toml new file mode 100644 index 0000000..854585a --- /dev/null +++ b/day02/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "day02" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/day02/src/main.rs b/day02/src/main.rs new file mode 100644 index 0000000..1764dc9 --- /dev/null +++ b/day02/src/main.rs @@ -0,0 +1,71 @@ +use std::fs; +use std::env; + +fn main() { + println!("Hello, AoC day 02!"); + + let args: Vec = env::args().collect(); + if args.len() != 2 { + println!("wrong number of arguments!"); + std::process::exit(1); + } + + let file_path = &args[1]; + let contents = fs::read_to_string(file_path).expect("Should have been able to read the file"); + + let mut safe_reports: i32 = 0; + let mut safe_reports_with_dampener: i32 = 0; + + for line in contents.lines() { + let report: Vec = line.split_whitespace().map(|s| s.parse().unwrap()).collect(); + + let safe = is_safe(&report); + + if safe { + safe_reports += 1; + } + + for i in 0..report.len() { + let skipped = [ &report[..i], &report[(i+1)..] ].concat(); + + if is_safe(&skipped) || safe { + safe_reports_with_dampener += 1; + break; + } + } + } + + println!("there were {safe_reports} safe reports"); + println!("there were {safe_reports_with_dampener} safe reports with the dampener turned on"); +} + +fn is_safe(report: &[i32]) -> bool { + let mut increasing = false; + let mut last_value = 0; + + for (i, &value) in report.iter().enumerate() { + if i == 0 { + last_value = value; + continue; + } + if i == 1 { + increasing = value > last_value; + } else { + if increasing && (value < last_value) { + return false; + } + if !increasing && (value > last_value) { + return false; + } + } + + let difference = (value - last_value).abs(); + if difference < 1 || difference > 3 { + return false; + } + + last_value = value; + } + + return true; +} \ No newline at end of file diff --git a/day03/Cargo.toml b/day03/Cargo.toml new file mode 100644 index 0000000..b60e1e9 --- /dev/null +++ b/day03/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "day03" +version = "0.1.0" +edition = "2021" + +[dependencies] +regex = "1.11.1" diff --git a/day03/src/main.rs b/day03/src/main.rs new file mode 100644 index 0000000..d836b04 --- /dev/null +++ b/day03/src/main.rs @@ -0,0 +1,70 @@ +use std::fs; +use std::env; +use regex::Regex; + +fn main() { + println!("Hello, AoC day 03!"); + + let args: Vec = env::args().collect(); + if args.len() != 2 { + println!("wrong number of arguments!"); + std::process::exit(1); + } + + let file_path = &args[1]; + let contents = fs::read_to_string(file_path).expect("Should have been able to read the file"); + + let mul_instructions = Regex::new(r"mul\(([0-9]{1,3}),([0-9]{1,3})\)").unwrap(); + let mut sum = 0; + for (_, [a, b]) in mul_instructions.captures_iter(&contents).map(|n| n.extract()) { + let (first, second): (i32, i32) = (a.parse().unwrap(), b.parse().unwrap()); + sum = sum + first*second; + } + + println!("the sum is {sum}"); + + let initial_dont = Regex::new(r"^don't()").unwrap(); + + let donts = contents.match_indices("don't()"); + let dos = contents.match_indices("do()"); + + let donts_indices = donts.map(|(i, _sep)| i); + let dos_indices = dos.map(|(i, _sep)| i); + let mut dos_and_donts_indices: Vec = + donts_indices + .chain(dos_indices) + .chain([contents.len()]) // just to make sure the last segment gets caught! + .collect(); + + dos_and_donts_indices.sort(); + + let mut sum = 0; + let mut last_index = 0; + for current_index in dos_and_donts_indices { + let current_slice = &contents[last_index..current_index]; + last_index = current_index; + + if initial_dont.is_match(current_slice) { + continue; + } + + for (_, [a, b]) in mul_instructions.captures_iter(current_slice).map(|n| n.extract()) { + let (first, second): (i32, i32) = (a.parse().unwrap(), b.parse().unwrap()); + sum = sum + first * second; + } + } + + println!("the sum for part b is {sum}"); +} + + + + + + + + + + + + diff --git a/day04/Cargo.toml b/day04/Cargo.toml new file mode 100644 index 0000000..5c2674d --- /dev/null +++ b/day04/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "day04" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/day04/src/main.rs b/day04/src/main.rs new file mode 100644 index 0000000..55937b2 --- /dev/null +++ b/day04/src/main.rs @@ -0,0 +1,82 @@ +use std::collections::HashMap; +use std::fs; +use std::env; +use crate::Dir::{North, South, East, West, NorthEast, NorthWest, SouthEast, SouthWest}; + +// nodes are (coord, direction) pairs. +// neighbors are step1+turnleft, step2+turnleft, step3+turnleft, step1+turnright, etc +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +enum Dir { North, South, East, West, NorthEast, NorthWest, SouthEast, SouthWest } + +fn step(start: &Coord, d: Dir, steps: i32) -> Coord { + match d { + North => (start.0, start.1 - steps), + South => (start.0, start.1 + steps), + East => (start.0 + steps, start.1), + West => (start.0 - steps, start.1), + NorthEast => (start.0 + steps, start.1 - steps), + NorthWest => (start.0 - steps, start.1 - steps), + SouthEast => (start.0 + steps, start.1 + steps), + SouthWest => (start.0 - steps, start.1 + steps) + } +} + +type Coord = (i32, i32); + +fn main() { + println!("Hello, AoC day 04!"); + + let args: Vec = env::args().collect(); + if args.len() != 2 { + println!("wrong number of arguments!"); + std::process::exit(1); + } + + let file_path = &args[1]; + + let contents = fs::read_to_string(file_path).expect("Should have been able to read the file"); + let mut grid: HashMap = HashMap::new(); + + let mut x; + // build our grid! + let mut y = 0; + for line in contents.lines() { + x = 0; + for c in line.chars() { + grid.insert((x,y), c); + x += 1; + } + y += 1; + } + + let mut sum = 0; + let mut xsum = 0; + + let directions = vec![North, South, East, West, NorthEast, NorthWest, SouthEast, SouthWest]; + for (position, _letter) in &grid { + for dir in &directions { + if check(position, &grid, *dir) { sum += 1 } + } + if xcheck(position, &grid) { xsum += 1 } + } + + println!("there are {sum} xmases"); + println!("there are {xsum} x-mases"); +} + +fn check(position: &Coord, grid: &HashMap, direction: Dir) -> bool { + if grid.get(&step(position, direction, 0)) != Some(&'X') { return false; } + if grid.get(&step(position, direction, 1)) != Some(&'M') { return false; } + if grid.get(&step(position, direction, 2)) != Some(&'A') { return false; } + if grid.get(&step(position, direction, 3)) != Some(&'S') { return false; } + return true; +} + +fn xcheck(position: &Coord, grid: &HashMap) -> bool { + if grid.get(position) != Some(&'A') { return false; } + let a = (grid.get(&step(position, NorthEast, 1)), grid.get(&step(position, SouthWest, 1))); + let b = (grid.get(&step(position, SouthEast, 1)), grid.get(&step(position, NorthWest, 1))); + if a != (Some(&'M'), Some(&'S')) && a != (Some(&'S'), Some(&'M')) { return false; } + if b != (Some(&'M'), Some(&'S')) && b != (Some(&'S'), Some(&'M')) { return false; } + return true; +} \ No newline at end of file diff --git a/day05/Cargo.toml b/day05/Cargo.toml new file mode 100644 index 0000000..88289b6 --- /dev/null +++ b/day05/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "day05" +version = "0.1.0" +edition = "2021" + +[dependencies] +regex = "1.11.1" +topological-sort = "0.2.2" diff --git a/day05/src/main.rs b/day05/src/main.rs new file mode 100644 index 0000000..0d0ed27 --- /dev/null +++ b/day05/src/main.rs @@ -0,0 +1,70 @@ +use std::iter; +use std::fs; +use std::env; +use topological_sort::TopologicalSort; + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +struct Rule ( i32, i32 ); + +fn main() { + println!("Hello, AoC day 05!"); + + let args: Vec = env::args().collect(); + if args.len() != 2 { + println!("wrong number of arguments!"); + std::process::exit(1); + } + + let file_path = &args[1]; + + let contents = fs::read_to_string(file_path).expect("Should have been able to read the file"); + let (first, second) = contents.split_once("\n\n").unwrap(); + + let rules: Vec = first + .lines() + .map(|line| { + let (before, after) = line.split_once("|").unwrap(); + Rule(before.parse().unwrap(), after.parse().unwrap()) + }) + .collect(); + let updates = second.lines(); + + let mut good_sum: i32 = 0; + let mut bad_sum: i32 = 0; + for update in updates { + let pages: Vec = update + .split(",") + .map(|page| page.parse::().unwrap()) + .collect(); + + let mut my_sort: TopologicalSort:: = TopologicalSort::new(); + + rules + .iter() + .filter(|&Rule(a, b)| pages.contains(a) && pages.contains(b)) + .for_each(|&Rule(a, b)| my_sort.add_dependency(a, b)); + + let true_pages: Vec = iter::from_fn(|| my_sort.pop()) + .filter(|p| pages.contains(p)) + .collect(); + + let middle: i32 = *halfway(&true_pages).expect("error finding the halfway point"); + + if iter::zip(pages.iter(), true_pages.iter()).all(|(a, b)| a==b) { + // it's good! + good_sum += middle; + } else { + // it's bad! + bad_sum += middle; + } + + } + + println!("the sum of middle pages of good updates is {good_sum}"); + println!("and the bad updates is {bad_sum}"); +} + +fn halfway(v: &[T]) -> Option<&T> { + if v.len() == 0 { return None; } + return v.get((v.len() - 1) / 2) +} \ No newline at end of file diff --git a/day06/Cargo.toml b/day06/Cargo.toml new file mode 100644 index 0000000..6bd04ba --- /dev/null +++ b/day06/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "day06" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/day06/src/main.rs b/day06/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/day06/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +}