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
+8
View File
@@ -0,0 +1,8 @@
[package]
name="aoc2015"
version = "0.1.0"
edition = "2024"
[dependencies]
core = { path = "../core" }
md-5 = { workspace = true }
+42
View File
@@ -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
+31
View File
@@ -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
+50
View File
@@ -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
+51
View File
@@ -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
+53
View File
@@ -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 -> {}", &current_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
+83
View File
@@ -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
+45
View File
@@ -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
+33
View File
@@ -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
+89
View File
@@ -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
+71
View File
@@ -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.");
}
+72
View File
@@ -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
+72
View File
@@ -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
+40
View File
@@ -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}");
}
}
+70
View File
@@ -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}");
}
+31
View File
@@ -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() {
}