first commit

This commit is contained in:
Shoofle 2024-12-05 15:49:00 -05:00
commit 33b031c8da
13 changed files with 403 additions and 0 deletions

14
.gitignore vendored Normal file
View File

@ -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

6
day01/Cargo.toml Normal file
View File

@ -0,0 +1,6 @@
[package]
name = "day01"
version = "0.1.0"
edition = "2021"
[dependencies]

54
day01/src/main.rs Normal file
View File

@ -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<String> = 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<i32> = Vec::new();
let mut second: Vec<i32> = Vec::new();
let mut counts: HashMap<i32, i32> = 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}");
}

6
day02/Cargo.toml Normal file
View File

@ -0,0 +1,6 @@
[package]
name = "day02"
version = "0.1.0"
edition = "2021"
[dependencies]

71
day02/src/main.rs Normal file
View File

@ -0,0 +1,71 @@
use std::fs;
use std::env;
fn main() {
println!("Hello, AoC day 02!");
let args: Vec<String> = 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<i32> = 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;
}

7
day03/Cargo.toml Normal file
View File

@ -0,0 +1,7 @@
[package]
name = "day03"
version = "0.1.0"
edition = "2021"
[dependencies]
regex = "1.11.1"

70
day03/src/main.rs Normal file
View File

@ -0,0 +1,70 @@
use std::fs;
use std::env;
use regex::Regex;
fn main() {
println!("Hello, AoC day 03!");
let args: Vec<String> = 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<usize> =
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}");
}

6
day04/Cargo.toml Normal file
View File

@ -0,0 +1,6 @@
[package]
name = "day04"
version = "0.1.0"
edition = "2021"
[dependencies]

82
day04/src/main.rs Normal file
View File

@ -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<String> = 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<Coord, char> = 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<Coord, char>, 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<Coord, char>) -> 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;
}

8
day05/Cargo.toml Normal file
View File

@ -0,0 +1,8 @@
[package]
name = "day05"
version = "0.1.0"
edition = "2021"
[dependencies]
regex = "1.11.1"
topological-sort = "0.2.2"

70
day05/src/main.rs Normal file
View File

@ -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<String> = 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<Rule> = 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<i32> = update
.split(",")
.map(|page| page.parse::<i32>().unwrap())
.collect();
let mut my_sort: TopologicalSort::<i32> = 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<i32> = 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<T>(v: &[T]) -> Option<&T> {
if v.len() == 0 { return None; }
return v.get((v.len() - 1) / 2)
}

6
day06/Cargo.toml Normal file
View File

@ -0,0 +1,6 @@
[package]
name = "day06"
version = "0.1.0"
edition = "2021"
[dependencies]

3
day06/src/main.rs Normal file
View File

@ -0,0 +1,3 @@
fn main() {
println!("Hello, world!");
}