moved code around so each year is a package.

This commit is contained in:
2025-08-29 16:14:42 -04:00
parent 8aa7fe572f
commit 46b91dae30
67 changed files with 246 additions and 77 deletions
+7
View File
@@ -0,0 +1,7 @@
[package]
name="aoc2024"
version = "0.1.0"
edition = "2024"
[dependencies]
core = { path = "../core" }
+81
View File
@@ -0,0 +1,81 @@
use std::{fs, io};
use std::fs::File;
use std::io::BufRead;
use std::path::Path;
/// Given 2 lists, sort the lists smallest to largest and then compare each pair of digits,
/// finding the difference between the two.
///
/// Ex:
///
/// 3 4 -> 1 3 = 2
/// 4 3 -> 2 3 = 1
/// 2 5 -> 3 3 = 0
/// 1 3 -> 3 4 = 1
/// 3 9 -> 3 5 = 2
/// 3 3 -> 4 9 = 5
/// SUM 11
///
///
fn bubble_sort(mut nums: Vec<i32>) -> Vec<i32> {
let n = nums.len();
let mut swapped = true;
while swapped {
swapped = false;
for i in 1..n {
if nums[i - 1] > nums[i] {
nums.swap(i - 1, i);
swapped = true;
}
}
}
nums
}
fn read_two_columns<P: AsRef<Path>>(filename: P) -> io::Result<(Vec<i32>, Vec<i32>)> {
let file = File::open(filename)?;
let reader = io::BufReader::new(file);
let mut col1 = Vec::new();
let mut col2 = Vec::new();
for line in reader.lines() {
let line = line?;
let parts: Vec<&str> = line.split_whitespace().collect();
if parts.len() == 2 {
let a: i32 = parts[0].parse().unwrap_or(0);
let b: i32 = parts[1].parse().unwrap_or(0);
col1.push(a);
col2.push(b);
}
}
Ok((col1, col2))
}
fn main() {
println!("Loading Data...");
let input_file = format!("{}/{}" ,
std::env::var("CARGO_MANIFEST_DIR").unwrap(),
"data/01_data.txt"
);
let (mut list1, mut list2) = read_two_columns(input_file).unwrap();
list1 = bubble_sort(list1);
list2 = bubble_sort(list2);
let mut running_total = 0;
for index in 0..list1.len() {
let n1 = list1[index].max(list2[index]);
let n2 = list1[index].min(list2[index]);
running_total += n1 - n2;
}
println!("Total = {}", running_total);
}
// 2375403
+102
View File
@@ -0,0 +1,102 @@
use std::{fs, io};
use std::fs::File;
use std::io::BufRead;
use std::path::Path;
// Your analysis only confirmed what everyone feared: the two lists of location IDs are indeed
// very different.
//
// Or are they?
//
// The Historians can't agree on which group made the mistakes or how to read most of the Chief's
// handwriting, but in the commotion you notice an interesting detail: a lot of location IDs appear
// in both lists! Maybe the other numbers aren't location IDs at all but rather misinterpreted
// handwriting.
//
// This time, you'll need to figure out exactly how often each number from the left list appears in
// the right list. Calculate a total similarity score by adding up each number in the left list
// after multiplying it by the number of times that number appears in the right list.
//
// Here are the same example lists again:
//
// 3 4
// 4 3
// 2 5
// 1 3
// 3 9
// 3 3
// For these example lists, here is the process of finding the similarity score:
//
// The first number in the left list is 3. It appears in the right list three times, so the
// similarity score increases by 3 * 3 = 9.
// The second number in the left list is 4. It appears in the right list once, so the similarity
// score increases by 4 * 1 = 4.
// The third number in the left list is 2. It does not appear in the right list, so the similarity
// score does not increase (2 * 0 = 0).
// The fourth number, 1, also does not appear in the right list.
// The fifth number, 3, appears in the right list three times; the similarity score increases by 9.
// The last number, 3, appears in the right list three times; the similarity score again increases
// by 9.
// So, for these example lists, the similarity score at the end of this process is
// 31 (9 + 4 + 0 + 0 + 9 + 9).
//
// Once again consider your left and right lists. What is their similarity score?
fn num_in_list(needle: i32, haystack: &Vec<i32>) -> i32 {
let mut working = 0;
for straw in haystack {
if *straw == needle {
working += 1;
}
}
working
}
fn count_occurances_in_list(needles: &Vec<i32>, haystack: &Vec<i32>) -> i32 {
// looking for a needle in a haystack...lets go!
let mut working = 0;
for needle in needles {
let num_in_list = num_in_list(*needle, haystack);
println!("Found {}, {} times. / {}", needle, num_in_list, working);
working += needle * num_in_list;
}
working
}
fn read_two_columns<P: AsRef<Path>>(filename: P) -> io::Result<(Vec<i32>, Vec<i32>)> {
let file = File::open(filename)?;
let reader = io::BufReader::new(file);
let mut col1 = Vec::new();
let mut col2 = Vec::new();
for line in reader.lines() {
let line = line?;
let parts: Vec<&str> = line.split_whitespace().collect();
if parts.len() == 2 {
let a: i32 = parts[0].parse().unwrap_or(0);
let b: i32 = parts[1].parse().unwrap_or(0);
col1.push(a);
col2.push(b);
}
}
Ok((col1, col2))
}
fn main() {
println!("Loading Data...");
let file_path = std::env::var("CARGO_MANIFEST_DIR").unwrap();
let (list1, list2) = read_two_columns(format!("{}/data/01_data.txt", file_path)).unwrap();
println!("List 1 -> {:?}", list1);
let final_value = count_occurances_in_list(&list1, &list2);
println!("Final value = {final_value}");
}
// 23082277
+103
View File
@@ -0,0 +1,103 @@
// Fortunately, the first location The Historians want to search isn't a long walk from the Chief
// Historian's office.
//
// While the Red-Nosed Reindeer nuclear fusion/fission plant appears to contain no sign of the
// Chief Historian, the engineers there run up to you as soon as they see you. Apparently, they
// still talk about the time Rudolph was saved through molecular synthesis from a single electron.
//
// They're quick to add that - since you're already here - they'd really appreciate your help
// analyzing some unusual data from the Red-Nosed reactor. You turn to check if The Historians are
// waiting for you, but they seem to have already divided into groups that are currently searching
// every corner of the facility. You offer to help with the unusual data.
//
// The unusual data (your puzzle input) consists of many reports, one report per line. Each report
// is a list of numbers called levels that are separated by spaces. For example:
//
// 7 6 4 2 1
// 1 2 7 8 9
// 9 7 6 2 1
// 1 3 2 4 5
// 8 6 4 4 1
// 1 3 6 7 9
// This example data contains six reports each containing five levels.
//
// The engineers are trying to figure out which reports are safe. The Red-Nosed reactor safety
// systems can only tolerate levels that are either gradually increasing or gradually decreasing.
// So, a report only counts as safe if both of the following are true:
//
// The levels are either all increasing or all decreasing.
// Any two adjacent levels differ by at least one and at most three.
// In the example above, the reports can be found safe or unsafe by checking those rules:
//
// 7 6 4 2 1: Safe because the levels are all decreasing by 1 or 2.
// 1 2 7 8 9: Unsafe because 2 7 is an increase of 5.
// 9 7 6 2 1: Unsafe because 6 2 is a decrease of 4.
// 1 3 2 4 5: Unsafe because 1 3 is increasing but 3 2 is decreasing.
// 8 6 4 4 1: Unsafe because 4 4 is neither an increase or a decrease.
// 1 3 6 7 9: Safe because the levels are all increasing by 1, 2, or 3.
// So, in this example, 2 reports are safe.
use std::{env, fs};
fn min_max(num1: u32, num2: u32) -> (u32, u32) {
(num1.min(num2), num1.max(num2))
}
fn in_range(min: u32, max:u32, target: u32) -> bool {
min <= target && target <= max
}
fn parse_numbers(s: &str) -> Vec<u32> {
s.split_whitespace() // split on whitespace
.filter_map(|num| num.parse::<u32>().ok()) // try to parse each piece
.collect()
}
fn is_safe(report: &str) -> bool {
let mut is_safe = true;
let mut last_reading = 0;
let numbers = parse_numbers(report);
println!("numbers: {:?}", numbers);
let mut is_increasing = numbers[0] < numbers[1];
println!("Checking report {report}");
println!("Found is_increasing = {is_increasing} from {}/{}", numbers[0], numbers[1]);
for (index, reading) in numbers.iter().enumerate() {
println!("Checking {index}->{reading} in {report} / {is_increasing}");
}
// for (index, reading) in numbers.enumerate() {
// let reading_u32: u32 = reading.parse().unwrap();
// if index == 0 {
// // prime it for the report
// last_reading = reading_u32;
// } else if index == 1 {
// if last_reading > reading_u32 {
// is_increasing = false;
// }
// } else {
// let (min,max) = min_max(last_reading as u32, reading_u32);
//
// // changing too fast
// if (max - min) > 2 { is_safe = false; }
// }
// }
is_safe
}
fn main() {
let input_file = format!("{}/{}" ,
std::env::var("CARGO_MANIFEST_DIR").unwrap(),
"data/02_data.txt"
);
let binding = fs::read_to_string(input_file).unwrap();
let reports = binding.lines();
for report in reports {
if is_safe(report) {
println!("Handling report of {report} -> Safe: {}", is_safe(report));
}
}
}