Initial commit
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
// Santa was hoping for a white Christmas, but his weather machine's "snow" function is powered by
|
||||
// stars, and he's fresh out! To save Christmas, he needs you to collect fifty stars by December
|
||||
// 25th.
|
||||
//
|
||||
// Santa is trying to deliver presents in a large apartment building, but he can't find the right
|
||||
// floor - the directions he got are a little confusing. He starts on the ground floor (floor 0)
|
||||
// and then follows the instructions one character at a time.
|
||||
//
|
||||
// An opening parenthesis, (, means he should go up one floor, and a closing parenthesis, ), means
|
||||
// he should go down one floor.
|
||||
//
|
||||
// The apartment building is very tall, and the basement is very deep; he will never find the top
|
||||
// or bottom floors.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// (()) and ()() both result in floor 0.
|
||||
// ((( and (()(()( both result in floor 3.
|
||||
// ))((((( also results in floor 3.
|
||||
// ()) and ))( both result in floor -1 (the first basement level).
|
||||
// ))) and )())()) both result in floor -3.
|
||||
// To what floor do the instructions take Santa?
|
||||
//
|
||||
|
||||
use aoc::read_data;
|
||||
|
||||
fn main() {
|
||||
let instructions = read_data("2015_01_data.txt");
|
||||
|
||||
let mut current_floor = 0;
|
||||
for next_direction in instructions.chars() {
|
||||
match next_direction {
|
||||
')' => current_floor -= 1,
|
||||
'(' => current_floor += 1,
|
||||
_ => {
|
||||
panic!("Invalid Direction. Santa got lost.");
|
||||
}
|
||||
}
|
||||
}
|
||||
println!("Ending on floor {}", current_floor);
|
||||
}
|
||||
// 232
|
||||
@@ -0,0 +1,32 @@
|
||||
// Now, given the same instructions, find the position of the first character that causes him to enter the basement (floor -1). The first character in the instructions has position 1, the second character has position 2, and so on.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// ) causes him to enter the basement at character position 1.
|
||||
// ()()) causes him to enter the basement at character position 5.
|
||||
// What is the position of the character that causes Santa to first enter the basement?
|
||||
//
|
||||
|
||||
use aoc::read_data;
|
||||
|
||||
fn main() {
|
||||
let instructions = read_data("2015_01_data.txt");
|
||||
|
||||
let mut has_hit_basement = false;
|
||||
|
||||
let mut current_floor = 0;
|
||||
for (index, next_direction) in instructions.chars().enumerate() {
|
||||
match next_direction {
|
||||
')' => current_floor -= 1,
|
||||
'(' => current_floor += 1,
|
||||
_ => {
|
||||
panic!("Invalid Direction. Santa got lost.");
|
||||
}
|
||||
}
|
||||
if !has_hit_basement && current_floor == -1 {
|
||||
has_hit_basement = true;
|
||||
println!("Hit the basement on step {}", index + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 1783
|
||||
@@ -0,0 +1,82 @@
|
||||
// The elves are running low on wrapping paper, and so they need to submit an order for more. They
|
||||
// have a list of the dimensions (length l, width w, and height h) of each present, and only want
|
||||
// to order exactly as much as they need.
|
||||
//
|
||||
// Fortunately, every present is a box (a perfect right rectangular prism), which makes calculating
|
||||
// the required wrapping paper for each gift a little easier: find the surface area of the box,
|
||||
// which is 2*l*w + 2*w*h + 2*h*l. The elves also need a little extra paper for each present: the
|
||||
// area of the smallest side.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// A present with dimensions 2x3x4 requires 2*6 + 2*12 + 2*8 = 52 square feet of wrapping paper
|
||||
// plus 6 square feet of slack, for a total of 58 square feet.
|
||||
// A present with dimensions 1x1x10 requires 2*1 + 2*10 + 2*10 = 42 square feet of wrapping paper
|
||||
// plus 1 square foot of slack, for a total of 43 square feet.
|
||||
// All numbers in the elves' list are in feet. How many total square feet of wrapping paper should
|
||||
// they order?
|
||||
//
|
||||
|
||||
use aoc::read_data;
|
||||
|
||||
fn smallest_of_vec(to_check: &Vec<u32>) -> u32 {
|
||||
let mut working = to_check[0];
|
||||
for current in to_check {
|
||||
if current < &working {
|
||||
working = *current
|
||||
}
|
||||
}
|
||||
working
|
||||
}
|
||||
|
||||
fn sum_of_vec(to_add: &Vec<u32>) -> u32 {
|
||||
let mut working = 0;
|
||||
for current in to_add {
|
||||
working += current
|
||||
}
|
||||
working
|
||||
}
|
||||
|
||||
fn calculate_wrapping_needed(length: u32, width: u32, height: u32) -> u32 {
|
||||
let sides = vec![
|
||||
2 * length * width,
|
||||
2 * width * height,
|
||||
2 * height * length
|
||||
];
|
||||
|
||||
// everything is *2 for size so we need half of it for our calc
|
||||
let min_side = smallest_of_vec(&sides) / 2;
|
||||
sum_of_vec(&sides) + min_side
|
||||
}
|
||||
|
||||
fn split_str(input: &str) -> Option<(u32, u32, u32)> {
|
||||
let parts: Vec<&str> = input.split('x').collect();
|
||||
if parts.len() == 3 {
|
||||
if let (Ok(a), Ok(b), Ok(c)) = (
|
||||
parts[0].parse::<u32>(),
|
||||
parts[1].parse::<u32>(),
|
||||
parts[2].parse::<u32>(),
|
||||
) {
|
||||
return Some((a, b, c));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("Need {} for 2x3x4", calculate_wrapping_needed(2,3,4));
|
||||
println!("Need {} for 1x1x10", calculate_wrapping_needed(1,1,10));
|
||||
|
||||
let binding = read_data("2015_02_data.txt");
|
||||
let sizes = binding.lines();
|
||||
let mut working = 0;
|
||||
|
||||
for size in sizes {
|
||||
let (l, w, h) = split_str(size).unwrap();
|
||||
let needed = calculate_wrapping_needed(l, w, h);
|
||||
// println!("Need {} for {}", needed, size);
|
||||
working += needed;
|
||||
}
|
||||
println!("You need {}.", working);
|
||||
}
|
||||
// 1586300.
|
||||
@@ -0,0 +1,64 @@
|
||||
// The elves are also running low on ribbon. Ribbon is all the same width, so they only have to
|
||||
// worry about the length they need to order, which they would again like to be exact.
|
||||
//
|
||||
// The ribbon required to wrap a present is the shortest distance around its sides, or the smallest
|
||||
// perimeter of any one face. Each present also requires a bow made out of ribbon as well; the feet
|
||||
// of ribbon required for the perfect bow is equal to the cubic feet of volume of the present.
|
||||
// Don't ask how they tie the bow, though; they'll never tell.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// A present with dimensions 2x3x4 requires 2+2+3+3 = 10 feet of ribbon to wrap the present
|
||||
// plus 2*3*4 = 24 feet of ribbon for the bow, for a total of 34 feet.
|
||||
// A present with dimensions 1x1x10 requires 1+1+1+1 = 4 feet of ribbon to wrap the present
|
||||
// plus 1*1*10 = 10 feet of ribbon for the bow, for a total of 14 feet.
|
||||
// How many total feet of ribbon should they order?
|
||||
//
|
||||
|
||||
use aoc::read_data;
|
||||
|
||||
fn bow_ribbon_length(l: u32, w: u32, h: u32) -> u32 {
|
||||
l * w * h
|
||||
}
|
||||
|
||||
fn ribbon_for_sides(l: u32, w: u32, h: u32) -> u32 {
|
||||
let to_remove = l.max(w).max(h) * 2;
|
||||
let working = 2 * l + 2 * w + 2 * h;
|
||||
working - to_remove
|
||||
}
|
||||
|
||||
fn ribbon_for_package(l: u32, w: u32, h: u32) -> u32 {
|
||||
ribbon_for_sides(l, w, h) + bow_ribbon_length(l, w, h)
|
||||
}
|
||||
|
||||
fn split_str(input: &str) -> Option<(u32, u32, u32)> {
|
||||
let parts: Vec<&str> = input.split('x').collect();
|
||||
if parts.len() == 3 {
|
||||
if let (Ok(a), Ok(b), Ok(c)) = (
|
||||
parts[0].parse::<u32>(),
|
||||
parts[1].parse::<u32>(),
|
||||
parts[2].parse::<u32>(),
|
||||
) {
|
||||
return Some((a, b, c));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("Box sized {} requires {}", "2x3x4", ribbon_for_package(2,3,4));
|
||||
println!("Box sized {} requires {}", "1x1x10", ribbon_for_package(1,1,10));
|
||||
|
||||
let sizes = read_data("2015_02_data.txt").lines();
|
||||
let mut total_ribbon = 0;
|
||||
|
||||
for size in sizes {
|
||||
let (l, w, h) = split_str(size).unwrap();
|
||||
let needed = ribbon_for_package(l, w, h);
|
||||
println!("Need {} for {}", needed, size);
|
||||
total_ribbon += needed
|
||||
}
|
||||
|
||||
println!("Need a total of {}", total_ribbon);
|
||||
}
|
||||
// 3737498
|
||||
@@ -0,0 +1,55 @@
|
||||
// Santa is delivering presents to an infinite two-dimensional grid of houses.
|
||||
//
|
||||
// He begins by delivering a present to the house at his starting location, and then an elf at the
|
||||
// North Pole calls him via radio and tells him where to move next. Moves are always exactly one
|
||||
// house to the north (^), south (v), east (>), or west (<). After each move, he delivers another
|
||||
// present to the house at his new location.
|
||||
//
|
||||
// However, the elf back at the north pole has had a little too much eggnog, and so his directions
|
||||
// are a little off, and Santa ends up visiting some houses more than once. How many houses receive
|
||||
// at least one present?
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// > delivers presents to 2 houses: one at the starting location, and one to the east.
|
||||
// ^>v< delivers presents to 4 houses in a square, including twice to the house at his
|
||||
// starting/ending location.
|
||||
// ^v^v^v^v^v delivers a bunch of presents to some very lucky children at only 2 houses.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use aoc::read_data;
|
||||
|
||||
fn main() {
|
||||
let mut visits: HashMap<String, u32> = HashMap::from([("0x0".to_string(), 1)]);
|
||||
let (mut current_x, mut current_y) = (0,0);
|
||||
|
||||
let instructions = read_data("2015_03_data.txt");
|
||||
for current_instruction in instructions.chars() {
|
||||
match current_instruction {
|
||||
'^' => {
|
||||
println!("Move North 1");
|
||||
current_y += 1;
|
||||
},
|
||||
'v' => {
|
||||
println!("Move South 1");
|
||||
current_y -= 1;
|
||||
},
|
||||
'<' => {
|
||||
println!("Move West 1");
|
||||
current_x -= 1;
|
||||
},
|
||||
'>' => {
|
||||
println!("Move East 1");
|
||||
current_x += 1;
|
||||
},
|
||||
_ => { unreachable!("Invalid instruction -> {}", ¤t_instruction); }
|
||||
}
|
||||
let current_address = format!("{}x{}", current_x, current_y);
|
||||
*visits.entry(current_address).and_modify(|x| *x += 1).or_insert(1);
|
||||
}
|
||||
|
||||
println!("Found {} houses got presents.", visits.keys().count());
|
||||
|
||||
println!("Taxation is theft.");
|
||||
}
|
||||
// 2081
|
||||
@@ -0,0 +1,83 @@
|
||||
// The next year, to speed up the process, Santa creates a robot version of himself, Robo-Santa,
|
||||
// to deliver presents with him.
|
||||
//
|
||||
// Santa and Robo-Santa start at the same location (delivering two presents to the same starting
|
||||
// house), then take turns moving based on instructions from the elf, who is eggnoggedly reading
|
||||
// from the same script as the previous year.
|
||||
//
|
||||
// This year, how many houses receive at least one present?
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// ^v delivers presents to 3 houses, because Santa goes north, and then Robo-Santa goes south.
|
||||
// ^>v< now delivers presents to 3 houses, and Santa and Robo-Santa end up back where they started.
|
||||
// ^v^v^v^v^v now delivers presents to 11 houses, with Santa going one direction and Robo-Santa
|
||||
// going the other.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use aoc::read_data;
|
||||
|
||||
fn num_houses(directions: &str) -> u32 {
|
||||
let (mut santa_x, mut santa_y, mut robo_x, mut robo_y) = (0,0,0,0);
|
||||
let mut visits = HashMap::from([("0x0".to_string(), 1)]);
|
||||
let mut santas_turn = true;
|
||||
|
||||
for current_instruction in directions.chars() {
|
||||
match current_instruction {
|
||||
'^' => {
|
||||
if santas_turn {
|
||||
santa_y += 1;
|
||||
} else {
|
||||
robo_y += 1;
|
||||
}
|
||||
},
|
||||
'v' => {
|
||||
if santas_turn {
|
||||
santa_y -= 1;
|
||||
} else {
|
||||
robo_y -= 1;
|
||||
}
|
||||
},
|
||||
'<' => {
|
||||
if santas_turn {
|
||||
santa_x -= 1;
|
||||
} else {
|
||||
robo_x -= 1;
|
||||
}
|
||||
},
|
||||
'>' => {
|
||||
if santas_turn {
|
||||
santa_x += 1;
|
||||
} else {
|
||||
robo_x += 1;
|
||||
}
|
||||
}
|
||||
_ => { unreachable!("Invalid Instruction"); }
|
||||
}
|
||||
let current_address = if santas_turn {
|
||||
format!("{}x{}", santa_x, santa_y)
|
||||
} else {
|
||||
format!("{}x{}", robo_x, robo_y)
|
||||
};
|
||||
println!("V:{} S:{}x{} R:{}x{} V#:{}", current_address, santa_x, santa_y, robo_x, robo_y, visits.keys().count());
|
||||
*visits.entry(current_address).and_modify(|x| *x += 1).or_insert(1);
|
||||
santas_turn = !santas_turn;
|
||||
}
|
||||
|
||||
visits.keys().count() as u32
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let directions = read_data("2015_03_data.txt");
|
||||
let params = vec![
|
||||
("^v", 3),
|
||||
("^>v<", 3),
|
||||
("^v^v^v^v^v", 11),
|
||||
(directions.as_str(), 0)
|
||||
];
|
||||
|
||||
for (input, expected) in params {
|
||||
println!("{:<20} resolves to {} houses.", input, num_houses(input));
|
||||
}
|
||||
}
|
||||
// 2341
|
||||
@@ -0,0 +1,59 @@
|
||||
// Santa needs help mining some AdventCoins (very similar to bitcoins) to use as gifts for all the
|
||||
// economically forward-thinking little girls and boys.
|
||||
//
|
||||
// To do this, he needs to find MD5 hashes which, in hexadecimal, start with at least five zeroes.
|
||||
// The input to the MD5 hash is some secret key (your puzzle input, given below) followed by a
|
||||
// number in decimal. To mine AdventCoins, you must find Santa the lowest positive number (no
|
||||
// leading zeroes: 1, 2, 3, ...) that produces such a hash.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// If your secret key is abcdef, the answer is 609043, because the MD5 hash of abcdef609043 starts
|
||||
// with five zeroes (000001dbbfa...), and it is the lowest such number to do so.
|
||||
// If your secret key is pqrstuv, the lowest number it combines with to make an MD5 hash starting
|
||||
// with five zeroes is 1048970; that is, the MD5 hash of pqrstuv1048970 looks like 000006136ef....
|
||||
|
||||
use std::io::{stdout, Write};
|
||||
use md5::{Digest, Md5};
|
||||
|
||||
const INPUT: &str = "bgvyzdsv";
|
||||
|
||||
fn calculate_hash(input_id: u32, seed: &str) -> String {
|
||||
let to_hash = format!("{}{}", seed, input_id);
|
||||
let as_hash = format!("{:x}", Md5::digest(to_hash.as_bytes()));
|
||||
as_hash
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("abcdef609043 -> {}", calculate_hash(609043, "abcdef"));
|
||||
println!("pqrstuv1048970 -> {}", calculate_hash(1048970, "pqrstuv"));
|
||||
let mut need5 = true;
|
||||
let mut need6 = true;
|
||||
|
||||
for number in 0..u32::MAX {
|
||||
let hashed = calculate_hash(number, INPUT);
|
||||
// are the first 6 characters 0?
|
||||
|
||||
if need5 {
|
||||
if hashed.starts_with("00000") {
|
||||
println!("5 zeros -> {}{} / {}", INPUT, number, hashed);
|
||||
need5 = false;
|
||||
}
|
||||
}
|
||||
|
||||
if need6 {
|
||||
if hashed.starts_with("000000") {
|
||||
println!("6 zeros -> {}{} / {}", INPUT, number, hashed);
|
||||
need6 = false;
|
||||
}
|
||||
}
|
||||
|
||||
if hashed.starts_with("0000000") {
|
||||
println!("7 zeros -> {}{} / {}", INPUT, number, hashed);
|
||||
} // 318_903_846
|
||||
if number % 100_000 == 0 && !need6 && !need5 {
|
||||
print!(".");
|
||||
stdout().flush().unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
// Santa needs help figuring out which strings in his text file are naughty or nice.
|
||||
//
|
||||
// A nice string is one with all of the following properties:
|
||||
//
|
||||
// It contains at least three vowels (aeiou only), like aei, xazegov, or aeiouaeiouaeiou.
|
||||
// It contains at least one letter that appears twice in a row, like xx, abcdde (dd),
|
||||
// or aabbccdd (aa, bb, cc, or dd).
|
||||
// It does not contain the strings ab, cd, pq, or xy, even if they are part of one of the other
|
||||
// requirements.
|
||||
// For example:
|
||||
//
|
||||
// ugknbfddgicrmopn is nice because it has at least three vowels (u...i...o...), a double letter
|
||||
// (...dd...), and none of the disallowed substrings.
|
||||
// aaa is nice because it has at least three vowels and a double letter, even though the letters
|
||||
// used by different rules overlap.
|
||||
// jchzalrnumimnmhp is naughty because it has no double letter.
|
||||
// haegwjzuvuyypxyu is naughty because it contains the string xy.
|
||||
// dvszwmarrgswjxmb is naughty because it contains only one vowel.
|
||||
// How many strings are nice?
|
||||
//
|
||||
|
||||
use aoc::read_data;
|
||||
|
||||
fn no_banned_parts(to_check: &str) -> bool {
|
||||
!to_check.contains("ab") &&
|
||||
!to_check.contains("cd") &&
|
||||
!to_check.contains("pq") &&
|
||||
!to_check.contains("xy")
|
||||
}
|
||||
|
||||
fn has_doubled_letter(to_check: &str) -> bool {
|
||||
let mut has_doubled = false;
|
||||
let mut last_char = ' ';
|
||||
|
||||
for current in to_check.chars() {
|
||||
if current == last_char {
|
||||
has_doubled = true
|
||||
}
|
||||
last_char = current
|
||||
}
|
||||
|
||||
has_doubled
|
||||
}
|
||||
|
||||
fn contains_three_vowels(to_check: &str) -> bool {
|
||||
let mut num_vowels = 0;
|
||||
for current in to_check.chars() {
|
||||
match current {
|
||||
'a' | 'e' | 'i' | 'o' | 'u' => {
|
||||
num_vowels += 1;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
num_vowels >= 3
|
||||
}
|
||||
|
||||
fn is_nice(to_check: &str) -> bool {
|
||||
let vowels = contains_three_vowels(to_check);
|
||||
let has_doubled = has_doubled_letter(to_check);
|
||||
let no_banned = no_banned_parts(to_check);
|
||||
|
||||
// println!("{} -> V{} D{} B{}", to_check, vowels, has_doubled, no_banned);
|
||||
|
||||
vowels && has_doubled && no_banned
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("ugknbfddgicrmopn is nice -> {}", is_nice("ugknbfddgicrmopn"));
|
||||
println!("aaa is nice -> {}", is_nice("aaa"));
|
||||
println!("jchzalrnumimnmhp is NOT nice -> {}", is_nice("jchzalrnumimnmhp"));
|
||||
println!("haegwjzuvuyypxyu is NOT nice -> {}", is_nice("haegwjzuvuyypxyu"));
|
||||
println!("dvszwmarrgswjxmb is NOT nice -> {}", is_nice("dvszwmarrgswjxmb"));
|
||||
|
||||
let binding = read_data("2015_05_data.txt");
|
||||
let lines = binding.lines();
|
||||
let mut nice = 0;
|
||||
let num_lines = lines.clone().count();
|
||||
|
||||
for line in lines {
|
||||
if is_nice(line) {
|
||||
nice += 1;
|
||||
}
|
||||
}
|
||||
|
||||
println!("There are {} nice out of {} words.", nice, num_lines);
|
||||
}
|
||||
// 236
|
||||
@@ -0,0 +1,57 @@
|
||||
#![feature(substr_range)]
|
||||
|
||||
// Realizing the error of his ways, Santa has switched to a better model of determining whether a
|
||||
// string is naughty or nice. None of the old rules apply, as they are all clearly ridiculous.
|
||||
//
|
||||
// Now, a nice string is one with all of the following properties:
|
||||
//
|
||||
// It contains a pair of any two letters that appears at least twice in the string without
|
||||
// overlapping, like xyxy (xy) or aabcdefgaa (aa), but not like aaa (aa, but it overlaps).
|
||||
// It contains at least one letter which repeats with exactly one letter between them, like xyx,
|
||||
// abcdefeghi (efe), or even aaa.
|
||||
// For example:
|
||||
//
|
||||
// qjhvhtzxzqqjkmpb is nice because is has a pair that appears twice (qj) and a letter that repeats
|
||||
// with exactly one letter between them (zxz).
|
||||
// xxyxx is nice because it has a pair that appears twice and a letter that repeats with one
|
||||
// between, even though the letters used by each rule overlap.
|
||||
// uurcxstgmygtbstg is naughty because it has a pair (tg) but no repeat with a single letter
|
||||
// between them.
|
||||
// ieodomkazucvgmuy is naughty because it has a repeating letter with one between (odo), but no
|
||||
// pair that appears twice.
|
||||
|
||||
|
||||
fn appears_twice_without_overlapping(to_check: &str) -> bool {
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn letter_repeated_seperated_by_1(to_check: &str) -> bool {
|
||||
println!("Starting to check for XyX");
|
||||
let mut has_criteria = false;
|
||||
|
||||
let mut two_back = ' ';
|
||||
let mut one_back = ' ';
|
||||
for (index, current) in to_check.chars().enumerate() {
|
||||
if current == two_back {
|
||||
has_criteria = true;
|
||||
println!("Found a seperated pair. {index} / {to_check}");
|
||||
break;
|
||||
}
|
||||
two_back = one_back;
|
||||
one_back = current;
|
||||
}
|
||||
has_criteria
|
||||
}
|
||||
|
||||
fn is_nice(to_check: &str) -> bool {
|
||||
appears_twice_without_overlapping(to_check) &&
|
||||
letter_repeated_seperated_by_1(to_check)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("qjhvhtzxzqqjkmpb is nice -> {}", is_nice("qjhvhtzxzqqjkmpb"));
|
||||
println!("xxyxx is nice -> {}", is_nice("xxyxx"));
|
||||
println!("uurcxstgmygtbstg is NOT nice -> {}", is_nice("uurcxstgmygtbstg"));
|
||||
println!("ieodomkazucvgmuy is NOT nice -> {}", is_nice("ieodomkazucvgmuy"));
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
// Because your neighbors keep defeating you in the holiday house decorating contest year after
|
||||
// year, you've decided to deploy one million lights in a 1000x1000 grid.
|
||||
//
|
||||
// Furthermore, because you've been especially nice this year, Santa has mailed you instructions
|
||||
// on how to display the ideal lighting configuration.
|
||||
//
|
||||
// Lights in your grid are numbered from 0 to 999 in each direction; the lights at each corner are
|
||||
// at 0,0, 0,999, 999,999, and 999,0. The instructions include whether to turn on, turn off, or
|
||||
// toggle various inclusive ranges given as coordinate pairs. Each coordinate pair represents
|
||||
// opposite corners of a rectangle, inclusive; a coordinate pair like 0,0 through 2,2 therefore
|
||||
// refers to 9 lights in a 3x3 square. The lights all start turned off.
|
||||
//
|
||||
// To defeat your neighbors this year, all you have to do is set up your lights by doing the
|
||||
// instructions Santa sent you in order.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// turn on 0,0 through 999,999 would turn on (or leave on) every light.
|
||||
// toggle 0,0 through 999,0 would toggle the first line of 1000 lights, turning off the ones that
|
||||
// were on, and turning on the ones that were off.
|
||||
// turn off 499,499 through 500,500 would turn off (or leave off) the middle four lights.
|
||||
// After following the instructions, how many lights are lit?
|
||||
|
||||
use aoc::read_data;
|
||||
|
||||
fn main() {
|
||||
let mut block: [bool; 1000*1000] = [false; 1000*1000];
|
||||
let binding = read_data("2015_06_data.txt");
|
||||
let lines: Vec<&str> = binding.lines().collect();
|
||||
|
||||
for instruction in lines {
|
||||
let parts: Vec<&str> = instruction.split(' ').collect();
|
||||
match parts.len() {
|
||||
5 => {
|
||||
let start_parts: Vec<u32> = parts[2].split(',').map(|x| x.parse().unwrap()).collect();
|
||||
let end_parts: Vec<u32> =parts[4].split(',').map(|x| x.parse().unwrap()).collect();
|
||||
// figure out if the [1] item is 'on' or 'off'
|
||||
let target_state = if parts[1] == "on" { true } else { false };
|
||||
for x in start_parts[0]..=end_parts[0] {
|
||||
for y in start_parts[1]..=end_parts[1] {
|
||||
let offset = (x * 1000) + y;
|
||||
// println!("Setting {}x{}({}) to {}", x, y, offset, target_state);
|
||||
block[offset as usize] = target_state;
|
||||
}
|
||||
}
|
||||
}
|
||||
4 => {
|
||||
// toggle
|
||||
let start_parts: Vec<u32> = parts[1].split(',').map(|x| x.parse().unwrap()).collect();
|
||||
let end_parts: Vec<u32> =parts[3].split(',').map(|x| x.parse().unwrap()).collect();
|
||||
|
||||
// println!("[{}] Toggling from {}x{} to {}x{}", instruction, start_parts[0], start_parts[1], end_parts[0], end_parts[1]);
|
||||
for x in start_parts[0]..=end_parts[0] {
|
||||
for y in start_parts[1]..=end_parts[1] {
|
||||
let offset = ((x * 1000) + y) as usize;
|
||||
let current = block[offset];
|
||||
// println!("Toggling {}x{} from {}", x, y, current);
|
||||
block[offset] = !current;
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => { unreachable!("Invalid number of parts") }
|
||||
}
|
||||
}
|
||||
println!("Tallying lights...");
|
||||
let mut num_lit = 0;
|
||||
for current in block {
|
||||
if current { num_lit += 1; }
|
||||
}
|
||||
println!("Counted {} lights.", num_lit);
|
||||
}
|
||||
// 400410
|
||||
@@ -0,0 +1,72 @@
|
||||
// You just finish implementing your winning light pattern when you realize you mistranslated
|
||||
// Santa's message from Ancient Nordic Elvish.
|
||||
//
|
||||
// The light grid you bought actually has individual brightness controls; each light can have a
|
||||
// brightness of zero or more. The lights all start at zero.
|
||||
//
|
||||
// The phrase turn on actually means that you should increase the brightness of those lights by 1.
|
||||
//
|
||||
// The phrase turn off actually means that you should decrease the brightness of those lights by 1,
|
||||
// to a minimum of zero.
|
||||
//
|
||||
// The phrase toggle actually means that you should increase the brightness of those lights by 2.
|
||||
//
|
||||
// What is the total brightness of all lights combined after following Santa's instructions?
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// turn on 0,0 through 0,0 would increase the total brightness by 1.
|
||||
// toggle 0,0 through 999,999 would increase the total brightness by 2000000.
|
||||
|
||||
use aoc::read_data;
|
||||
|
||||
fn main() {
|
||||
let mut block: Box<[u32; 1000*1000]> = Box::new([0; 1000*1000]);
|
||||
let binding = read_data("2015_06_data.txt");
|
||||
let lines: Vec<&str> = binding.lines().collect();
|
||||
|
||||
for instruction in lines {
|
||||
let parts: Vec<&str> = instruction.split(' ').collect();
|
||||
|
||||
match parts.len() {
|
||||
5 => {
|
||||
let start_parts: Vec<u32> = parts[2].split(',').map(|x| x.parse().unwrap()).collect();
|
||||
let end_parts: Vec<u32> = parts[4].split(',').map(|x| x.parse().unwrap()).collect();
|
||||
|
||||
for x in start_parts[0]..=end_parts[0] {
|
||||
for y in start_parts[1]..=end_parts[1] {
|
||||
let offset = (x * 1000 + y) as usize;
|
||||
if parts[1] == "on" {
|
||||
block[offset] += 1;
|
||||
} else {
|
||||
if block[offset] > 0 {
|
||||
block[offset] -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
4 => {
|
||||
let start_parts: Vec<u32> = parts[1].split(',').map(|x| x.parse().unwrap()).collect();
|
||||
let end_parts: Vec<u32> = parts[3].split(',').map(|x| x.parse().unwrap()).collect();
|
||||
|
||||
for x in start_parts[0]..=end_parts[0] {
|
||||
for y in start_parts[1]..=end_parts[1] {
|
||||
let offset = ((x * 1000) + y) as usize;
|
||||
block[offset] += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
unreachable!("Invalid direction -> [{}]", instruction);
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut working: u64 = 0;
|
||||
|
||||
for current in block.iter() {
|
||||
working += *current as u64;
|
||||
}
|
||||
println!("Total Brightness = {}", working);
|
||||
}
|
||||
// 15343601
|
||||
@@ -0,0 +1,118 @@
|
||||
// Santa's sleigh uses a very high-precision clock to guide its movements, and the clock's
|
||||
// oscillator is regulated by stars. Unfortunately, the stars have been stolen... by the Easter
|
||||
// Bunny. To save Christmas, Santa needs you to retrieve all fifty stars by December 25th.
|
||||
//
|
||||
// Collect stars by solving puzzles. Two puzzles will be made available on each day in the Advent
|
||||
// calendar; the second puzzle is unlocked when you complete the first. Each puzzle grants one
|
||||
// star. Good luck!
|
||||
//
|
||||
// You're airdropped near Easter Bunny Headquarters in a city somewhere. "Near", unfortunately, is
|
||||
// as close as you can get - the instructions on the Easter Bunny Recruiting Document the Elves
|
||||
// intercepted start here, and nobody had time to work them out further.
|
||||
//
|
||||
// The Document indicates that you should start at the given coordinates (where you just landed)
|
||||
// and face North. Then, follow the provided sequence: either turn left (L) or right (R) 90
|
||||
// degrees, then walk forward the given number of blocks, ending at a new intersection.
|
||||
//
|
||||
// There's no time to follow such ridiculous instructions on foot, though, so you take a moment
|
||||
// and work out the destination. Given that you can only walk on the street grid of the city,
|
||||
// how far is the shortest path to the destination?
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// Following R2, L3 leaves you 2 blocks East and 3 blocks North, or 5 blocks away.
|
||||
// R2, R2, R2 leaves you 2 blocks due South of your starting position, which is 2 blocks away.
|
||||
// R5, L5, R5, R3 leaves you 12 blocks away.
|
||||
// How many blocks away is Easter Bunny HQ?
|
||||
//
|
||||
|
||||
use std::{env, fs};
|
||||
use crate::CardinalDirection::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum CardinalDirection {
|
||||
North,
|
||||
South,
|
||||
East,
|
||||
West
|
||||
}
|
||||
|
||||
fn manhattan_distance(directions: &str) -> i32 {
|
||||
let (mut x_distance, mut y_distance, mut x_move, mut y_move) = (0i32,0i32, 0i32, 0i32);
|
||||
let mut current_direction = North;
|
||||
for next_direction in directions.split(", ") {
|
||||
let (direction, vector) = next_direction.split_at(1);
|
||||
let distance = vector.parse().unwrap();
|
||||
// print!("[{}] At {x_distance}x{y_distance}, FACING {current_direction:?}, TURN {} MOVE {} ::::::", next_direction, direction, distance);
|
||||
|
||||
x_move = 0; y_move = 0;
|
||||
|
||||
match direction {
|
||||
"R" => {
|
||||
match current_direction {
|
||||
North => {
|
||||
current_direction = East;
|
||||
x_move = distance;
|
||||
}
|
||||
South => {
|
||||
current_direction = West;
|
||||
x_move = distance * -1 ;
|
||||
}
|
||||
East => {
|
||||
current_direction = South;
|
||||
y_move = distance * -1;
|
||||
}
|
||||
West => {
|
||||
current_direction = North;
|
||||
y_move = distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
"L" => {
|
||||
match current_direction {
|
||||
North => {
|
||||
current_direction = West;
|
||||
x_move = distance * -1;
|
||||
}
|
||||
South => {
|
||||
current_direction = East;
|
||||
x_move = distance;
|
||||
}
|
||||
East => {
|
||||
current_direction = North;
|
||||
y_move = distance;
|
||||
}
|
||||
West => {
|
||||
current_direction = South;
|
||||
y_move = distance * -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
println!("INVALID DIRECTION");
|
||||
}
|
||||
}
|
||||
x_distance += x_move;
|
||||
y_distance += y_move;
|
||||
|
||||
// println!("facing {:?} at {}x{} (moved {}x{})", current_direction, x_distance, y_distance, x_move, y_move);
|
||||
}
|
||||
x_distance.abs() + y_distance.abs()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
||||
let directions = fs::read_to_string(format!("{}/data/01_data.txt", env::var("CARGO_MANIFEST_DIR").unwrap())).unwrap();
|
||||
let directions = directions.as_str();
|
||||
let parmas: Vec<(&str, i32)> = vec![
|
||||
("R2, L3", 5),
|
||||
("R2, R2, R2", 2),
|
||||
("R5, L5, R5, R3", 12),
|
||||
(directions, 252)];
|
||||
|
||||
for (param, expected) in parmas {
|
||||
println!("Manhattan Distance of {} Expected {}", manhattan_distance(param) , expected);
|
||||
}
|
||||
}
|
||||
|
||||
// 252
|
||||
@@ -0,0 +1,127 @@
|
||||
// Santa's sleigh uses a very high-precision clock to guide its movements, and the clock's
|
||||
// oscillator is regulated by stars. Unfortunately, the stars have been stolen... by the Easter
|
||||
// Bunny. To save Christmas, Santa needs you to retrieve all fifty stars by December 25th.
|
||||
//
|
||||
// Collect stars by solving puzzles. Two puzzles will be made available on each day in the Advent
|
||||
// calendar; the second puzzle is unlocked when you complete the first. Each puzzle grants one
|
||||
// star. Good luck!
|
||||
//
|
||||
// You're airdropped near Easter Bunny Headquarters in a city somewhere. "Near", unfortunately, is
|
||||
// as close as you can get - the instructions on the Easter Bunny Recruiting Document the Elves
|
||||
// intercepted start here, and nobody had time to work them out further.
|
||||
//
|
||||
// The Document indicates that you should start at the given coordinates (where you just landed)
|
||||
// and face North. Then, follow the provided sequence: either turn left (L) or right (R) 90
|
||||
// degrees, then walk forward the given number of blocks, ending at a new intersection.
|
||||
//
|
||||
// There's no time to follow such ridiculous instructions on foot, though, so you take a moment
|
||||
// and work out the destination. Given that you can only walk on the street grid of the city,
|
||||
// how far is the shortest path to the destination?
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// Following R2, L3 leaves you 2 blocks East and 3 blocks North, or 5 blocks away.
|
||||
// R2, R2, R2 leaves you 2 blocks due South of your starting position, which is 2 blocks away.
|
||||
// R5, L5, R5, R3 leaves you 12 blocks away.
|
||||
// How many blocks away is Easter Bunny HQ?
|
||||
//
|
||||
|
||||
use std::{env, fs};
|
||||
use std::collections::HashMap;
|
||||
use aoc::read_data;
|
||||
use crate::CardinalDirection::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum CardinalDirection {
|
||||
North,
|
||||
South,
|
||||
East,
|
||||
West
|
||||
}
|
||||
|
||||
fn manhattan_distance(directions: &str) -> i32 {
|
||||
let mut visited_locations: HashMap<String, i32> = HashMap::new();
|
||||
visited_locations.insert("0x0".to_string(), 0);
|
||||
let (mut x_distance, mut y_distance, mut x_move, mut y_move) = (0i32,0i32, 0i32, 0i32);
|
||||
let mut current_direction = North;
|
||||
for next_direction in directions.split(", ") {
|
||||
let (direction, vector) = next_direction.split_at(1);
|
||||
let distance = vector.parse().unwrap();
|
||||
// print!("[{}] At {x_distance}x{y_distance}, FACING {current_direction:?}, TURN {} MOVE {} ::::::", next_direction, direction, distance);
|
||||
|
||||
x_move = 0; y_move = 0;
|
||||
|
||||
match direction {
|
||||
"R" => {
|
||||
match current_direction {
|
||||
North => {
|
||||
current_direction = East;
|
||||
x_move = distance;
|
||||
}
|
||||
South => {
|
||||
current_direction = West;
|
||||
x_move = distance * -1 ;
|
||||
}
|
||||
East => {
|
||||
current_direction = South;
|
||||
y_move = distance * -1;
|
||||
}
|
||||
West => {
|
||||
current_direction = North;
|
||||
y_move = distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
"L" => {
|
||||
match current_direction {
|
||||
North => {
|
||||
current_direction = West;
|
||||
x_move = distance * -1;
|
||||
}
|
||||
South => {
|
||||
current_direction = East;
|
||||
x_move = distance;
|
||||
}
|
||||
East => {
|
||||
current_direction = North;
|
||||
y_move = distance;
|
||||
}
|
||||
West => {
|
||||
current_direction = South;
|
||||
y_move = distance * -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
println!("INVALID DIRECTION");
|
||||
}
|
||||
}
|
||||
x_distance += x_move;
|
||||
y_distance += y_move;
|
||||
|
||||
// have we been here before?
|
||||
let new_index = format!("{}x{}", x_distance, y_distance);
|
||||
for key in visited_locations.keys() {
|
||||
if *key == new_index {
|
||||
panic!("********************************MATCH -> {} == {}x{}", key, x_distance, y_distance);
|
||||
} else {
|
||||
print!("\tNOT MATCH -> {key} {x_distance}x{y_distance}\n");
|
||||
}
|
||||
}
|
||||
println!("Adding {new_index} to visited list");
|
||||
visited_locations.insert(new_index, 0);
|
||||
}
|
||||
x_distance.abs() + y_distance.abs()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let binding = read_data("2016_01_data.txt");
|
||||
let directions = binding.as_str();
|
||||
let params: Vec<&str> = vec![directions];
|
||||
|
||||
for param in params {
|
||||
println!("Manhattan Distance of {}", manhattan_distance(param));
|
||||
}
|
||||
}
|
||||
|
||||
// NOT COMPLETED. CANT FIND THE REPEATED LOCATION
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/// AOC Lib
|
||||
/// Generic methods for loading various data inputs from
|
||||
/// the AOC project.
|
||||
|
||||
pub fn data_path(suffix: &str) -> String {
|
||||
let path = std::env::var("CARGO_MANIFEST_DIR").unwrap();
|
||||
format!("{}/data/{}", path, suffix)
|
||||
}
|
||||
|
||||
pub fn read_data(suffix: &str) -> String {
|
||||
std::fs::read_to_string(
|
||||
data_path(suffix)
|
||||
).unwrap()
|
||||
}
|
||||
|
||||
pub fn string_to_3u32(input: &str) -> Option<(u32, u32, u32)> {
|
||||
let parts: Vec<&str> = input.split('x').collect();
|
||||
if parts.len() == 3 {
|
||||
if let (Ok(a), Ok(b), Ok(c)) = (
|
||||
parts[0].parse::<u32>(),
|
||||
parts[1].parse::<u32>(),
|
||||
parts[2].parse::<u32>(),
|
||||
) {
|
||||
return Some((a, b, c));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
Reference in New Issue
Block a user