moved code around so each year is a package.
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name="aoc2015"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
core = { path = "../core" }
|
||||
md-5 = { workspace = true }
|
||||
@@ -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 core::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,31 @@
|
||||
// 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 core::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,50 @@
|
||||
// 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 core::{read_data, smallest_of_vec, string_to_3u32, sum_of_vec};
|
||||
|
||||
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 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) = string_to_3u32(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,51 @@
|
||||
// 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 core::{read_data, string_to_3u32};
|
||||
|
||||
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 main() {
|
||||
println!("Box sized {} requires {}", "2x3x4", ribbon_for_package(2,3,4));
|
||||
println!("Box sized {} requires {}", "1x1x10", ribbon_for_package(1,1,10));
|
||||
|
||||
let binding = read_data("2015_02_data.txt");
|
||||
let sizes = binding.lines();
|
||||
let mut total_ribbon = 0;
|
||||
|
||||
for size in sizes {
|
||||
let (l, w, h) = string_to_3u32(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,53 @@
|
||||
// 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 core::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());
|
||||
}
|
||||
// 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 core::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,45 @@
|
||||
// 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;
|
||||
|
||||
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;
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 254575
|
||||
@@ -0,0 +1,33 @@
|
||||
// Now find one that starts with six zeroes.
|
||||
|
||||
|
||||
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 need6 = true;
|
||||
|
||||
for number in 0..u32::MAX {
|
||||
let hashed = calculate_hash(number, INPUT);
|
||||
// are the first 6 characters 0?
|
||||
|
||||
if need6 {
|
||||
if hashed.starts_with("000000") {
|
||||
println!("6 zeros -> {}{} / {}", INPUT, number, hashed);
|
||||
need6 = false;
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 1048970
|
||||
@@ -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 core::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,71 @@
|
||||
#![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.
|
||||
|
||||
use core::read_data;
|
||||
|
||||
|
||||
fn appears_twice_without_overlapping(to_check: &str) -> bool {
|
||||
let check_chars: Vec<_> = to_check.chars().collect();
|
||||
for index in 0.. check_chars.len() - 1 {
|
||||
let pair = (check_chars[index], check_chars[index + 1]);
|
||||
for subindex in index + 2 .. check_chars.len() - 1 {
|
||||
if check_chars[subindex] == pair.0 && check_chars[subindex + 1] == pair.1 {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn letter_repeated_seperated_by_1(to_check: &str) -> bool {
|
||||
let chars: Vec<_> = to_check.chars().collect();
|
||||
for index in 0..chars.len() - 2 {
|
||||
if chars[index] == chars[index + 2] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
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"));
|
||||
|
||||
let binding = read_data("2015_05_data.txt");
|
||||
let lines = binding.lines();
|
||||
let mut num_lines = 0;
|
||||
|
||||
for line in lines {
|
||||
if is_nice(line) {
|
||||
num_lines += 1;
|
||||
}
|
||||
}
|
||||
println!("Found {num_lines} good passwords.");
|
||||
|
||||
}
|
||||
@@ -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 core::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 core::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,40 @@
|
||||
use core::read_data;
|
||||
|
||||
fn main() {
|
||||
let binding = read_data("2015_08_data.txt");
|
||||
let lines = binding.lines();
|
||||
let binding = vec![
|
||||
"\"\"",
|
||||
"\"abc\"",
|
||||
"\"abc\\\"abc\"",
|
||||
"\"\\x27\""
|
||||
].join("\n");
|
||||
let lines = binding.lines();
|
||||
|
||||
for line in lines {
|
||||
let mut num_bytes = 0;
|
||||
let mut num_chars = 0;
|
||||
let mut next_char_to_watch = 0;
|
||||
let mut line_chars = line.chars();
|
||||
|
||||
for (current_index, current_char) in line_chars.clone().enumerate() {
|
||||
if current_index > next_char_to_watch {
|
||||
match current_char {
|
||||
'"' => {
|
||||
num_bytes += 1;
|
||||
},
|
||||
'\\' => {
|
||||
println!("Found slash at {current_index}");
|
||||
let x = line_chars.nth(current_index).unwrap();
|
||||
// println!("{}", line_chars.colle
|
||||
}
|
||||
_ => {
|
||||
num_bytes += 1;
|
||||
num_chars += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
println!("[{line}] = B:{num_bytes} C:{num_chars}");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
// Look-and-say sequences are generated iteratively, using the previous value as input for the next
|
||||
// step. For each step, take the previous value, and replace each run of digits (like 111) with the
|
||||
// number of digits (3) followed by the digit itself (1).
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// 1 becomes 11 (1 copy of digit 1).
|
||||
// 11 becomes 21 (2 copies of digit 1).
|
||||
// 21 becomes 1211 (one 2 followed by one 1).
|
||||
// 1211 becomes 111221 (one 1, one 2, and two 1s).
|
||||
// 111221 becomes 312211 (three 1s, two 2s, and one 1).
|
||||
// Starting with the digits in your puzzle input, apply this process 40 times. What is the length
|
||||
// of the result?
|
||||
//
|
||||
// Your puzzle input is 1113122113.
|
||||
// 1: 311311222113
|
||||
// 2: 13211321322113
|
||||
// 3: 1113122113121113222113
|
||||
// 4: 31131122211311133113322113
|
||||
// 5: 1321132132211331232123222113
|
||||
// 6: ...
|
||||
|
||||
fn num_to_change(input: &str) -> usize {
|
||||
let mut return_value = 0;
|
||||
let mut last_char = '\0';
|
||||
|
||||
for (index, current_char) in input.chars().enumerate() {
|
||||
if index != 0 {
|
||||
if last_char != current_char {
|
||||
return_value = index;
|
||||
break
|
||||
}
|
||||
}
|
||||
last_char = current_char
|
||||
}
|
||||
return_value
|
||||
}
|
||||
|
||||
fn look_and_say(input: &str) -> String {
|
||||
let mut working = String::new();
|
||||
|
||||
|
||||
|
||||
working
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let params = vec![
|
||||
("1", "11"),
|
||||
("11", "21"),
|
||||
("21", "1211"),
|
||||
// ("1211", "111221"),
|
||||
// ("111221", "31221")
|
||||
];
|
||||
|
||||
for (input, output) in params {
|
||||
let result = look_and_say(input);
|
||||
println!("**** {input} processed to {result} expecting {output}");
|
||||
assert_eq!(result, output);
|
||||
}
|
||||
|
||||
// // puzzle time
|
||||
// let mut current_input = "1113122113";
|
||||
// for _ in 0..40 {
|
||||
// let next_input = current_input.clone();
|
||||
// let next_output = look_and_say(next_input);
|
||||
// current_input = next_output.as_str();
|
||||
// }
|
||||
// println!("final -> {current_input}");
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// This year is the Reindeer Olympics! Reindeer can fly at high speeds, but must rest occasionally
|
||||
// to recover their energy. Santa would like to know which of his reindeer is fastest, and so he
|
||||
// has them race.
|
||||
//
|
||||
// Reindeer can only either be flying (always at their top speed) or resting (not moving at all),
|
||||
// and always spend whole seconds in either state.
|
||||
//
|
||||
// For example, suppose you have the following Reindeer:
|
||||
//
|
||||
// Comet can fly 14 km/s for 10 seconds, but then must rest for 127 seconds.
|
||||
// Dancer can fly 16 km/s for 11 seconds, but then must rest for 162 seconds.
|
||||
// After one second, Comet has gone 14 km, while Dancer has gone 16 km. After ten seconds, Comet
|
||||
// has gone 140 km, while Dancer has gone 160 km. On the eleventh second, Comet begins resting
|
||||
// (staying at 140 km), and Dancer continues on for a total distance of 176 km. On the 12th second,
|
||||
// both reindeer are resting. They continue to rest until the 138th second, when Comet flies for
|
||||
// another ten seconds. On the 174th second, Dancer flies for another 11 seconds.
|
||||
//
|
||||
// In this example, after the 1000th second, both reindeer are resting, and Comet is in the lead at
|
||||
// 1120 km (poor Dancer has only gotten 1056 km by that point). So, in this situation, Comet would
|
||||
// win (if the race ended at 1000 seconds).
|
||||
//
|
||||
// Given the descriptions of each reindeer (in your puzzle input), after exactly 2503 seconds, what
|
||||
// distance has the winning reindeer traveled?
|
||||
|
||||
fn tick_world() {
|
||||
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user