Solutions for 2022, as well as 2015-2018 and 2019 up to day 11

This commit is contained in:
Chris Alge 2023-03-12 15:20:02 +01:00
commit 1895197c49
722 changed files with 375457 additions and 0 deletions

7
.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
.aocf
day00
**/target
**/Cargo.lock
**/dbg.log
**/2
**/.vimdid

View file

@ -0,0 +1,8 @@
[package]
name = "day01-not_quite_lisp"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

@ -0,0 +1,46 @@
\--- Day 1: Not Quite Lisp ---
----------
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.
Collect stars by helping Santa solve 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!
Here's an easy puzzle to warm you up.
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?
Your puzzle answer was `232`.
\--- Part Two ---
----------
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?
Your puzzle answer was `1783`.
Both parts of this puzzle are complete! They provide two gold stars: \*\*
At this point, all that is left is for you to [admire your Advent calendar](/2015).
If you still want to see it, you can [get your puzzle input](1/input).

View file

@ -0,0 +1,48 @@
use std::fs::read_to_string;
fn read_file(name: &str) -> String {
read_to_string(name).expect(&format!("Unable to read file: {}", name)[..])
}
fn char_to_floor(c: char) -> isize {
match c {
'(' => 1,
')' => -1,
_ => 0,
}
}
pub fn final_floor(input: &str) -> isize {
input.chars().map(char_to_floor).sum()
}
pub fn first_basement_pos(input: &str) -> usize {
let mut floors = input.chars().scan(0, |curr_floor, c| { *curr_floor += char_to_floor(c);Some(*curr_floor) } );
floors.position(|i| i==-1).expect("Never reached Floor -1") + 1
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sample() {
let sample_input = read_file("tests/sample_input");
let expected = [0, 0, 3, 3, 3, -1, -1, -3, -3];
for (line_number, line) in sample_input.lines().enumerate() {
assert_eq!(final_floor(line), expected[line_number]);
}
let samples_2 = [")", "()())"];
let expected_2 = [1, 5];
for (sample_number, sample) in samples_2.iter().enumerate() {
assert_eq!(first_basement_pos(sample), expected_2[sample_number]);
}
}
#[test]
fn test_challenge() {
let challenge_input = read_file("tests/challenge_input");
assert_eq!(final_floor(&challenge_input), 232);
assert_eq!(first_basement_pos(&challenge_input), 1783);
}
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,9 @@
(())
()()
(((
(()(()(
))(((((
())
))(
)))
)())())

View file

@ -0,0 +1,8 @@
[package]
name = "day02-I_was_told_there_would_be_no_math"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

@ -0,0 +1,37 @@
\--- Day 2: I Was Told There Would Be No Math ---
----------
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](https://en.wikipedia.org/wiki/Cuboid#Rectangular_cuboid)), 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?
Your puzzle answer was `1598415`.
\--- Part Two ---
----------
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?
Your puzzle answer was `3812909`.
Both parts of this puzzle are complete! They provide two gold stars: \*\*
At this point, all that is left is for you to [admire your Advent calendar](/2015).
If you still want to see it, you can [get your puzzle input](2/input).

View file

@ -0,0 +1,55 @@
use std::fs::read_to_string;
fn read_file(name: &str) -> String {
read_to_string(name).expect(&format!("Unable to read file: {}", name)[..])
}
fn min_2(a: usize, b: usize, c: usize) -> (usize, usize) {
match a.cmp(&b) {
std::cmp::Ordering::Less => (a, b.min(c)),
std::cmp::Ordering::Equal => (a, b.min(c)),
std::cmp::Ordering::Greater => (b, a.min(c)),
}
}
fn get_dimensions(line: &str) -> (usize, usize, usize) {
let sides: Vec<&str> = line.split('x').collect();
assert_eq!(sides.len(), 3);
(sides[0].parse::<usize>().unwrap(), sides[1].parse::<usize>().unwrap(), sides[2].parse::<usize>().unwrap())
}
fn get_wrapping_paper((l, w, h): (usize, usize, usize)) -> usize {
let (short, mid) = min_2(l, w, h);
2*l*w + 2*w*h + 2*h*l + short*mid
}
fn get_ribbon((l, w, h): (usize, usize, usize)) -> usize {
let (short, mid) = min_2(l, w, h);
2*(short+mid) + l*w*h
}
pub fn run(input: &str) -> (usize, usize ) {
let dimensions: Vec<_> = input.lines().map(get_dimensions).collect();
let first = dimensions.iter().cloned().map(get_wrapping_paper).sum();
let second = dimensions.iter().cloned().map(get_ribbon).sum();
(first, second)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sample() {
let sample_input = read_file("tests/sample_input");
assert_eq!(run(&sample_input), (101, 48));
}
#[test]
fn test_challenge() {
let challenge_input = read_file("tests/challenge_input");
assert_eq!(run(&challenge_input), (1598415, 3812909));
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,2 @@
2x3x4
1x1x10

View file

@ -0,0 +1,8 @@
[package]
name = "day03-perfectly_spherical_houses_in_a_vacuum"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

@ -0,0 +1,39 @@
\--- Day 3: Perfectly Spherical Houses in a Vacuum ---
----------
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.
Your puzzle answer was `2592`.
\--- Part Two ---
----------
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.
Your puzzle answer was `2360`.
Both parts of this puzzle are complete! They provide two gold stars: \*\*
At this point, all that is left is for you to [admire your Advent calendar](/2015).
If you still want to see it, you can [get your puzzle input](3/input).

View file

@ -0,0 +1,55 @@
use std::{fs::read_to_string, collections::HashSet};
fn read_file(name: &str) -> String {
read_to_string(name).expect(&format!("Unable to read file: {}", name)[..])
}
fn movement((x, y): (isize, isize), direction: char) -> (isize, isize) {
match direction {
'^' => (x, y-1),
'v' => (x, y+1),
'<' => (x-1, y),
'>' => (x+1, y),
_ => (x, y),
}
}
pub fn run(input: &str) -> (usize, usize) {
let mut first: HashSet<(isize, isize)> = input.chars().scan((0, 0), |curr, c| {
*curr = movement(*curr, c);
Some(*curr)
}).collect();
first.insert((0, 0));
let mut second: HashSet<(isize, isize)> = input.chars().enumerate().scan(((0,0), (0,0)), |(santa, robo), (idx, c)| {
match idx % 2 {
0 => { *santa = movement(*santa, c); Some(*santa) },
1 => { *robo = movement(*robo, c); Some(*robo) },
_ => unreachable!(),
}
}).collect();
second.insert((0, 0));
(first.len(), second.len())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sample() {
let sample_input = read_file("tests/sample_input");
let sample_input: Vec<&str> = sample_input.lines().collect();
let expected = [(2,2), (4,3), (2,11)];
for (index, input) in sample_input.iter().enumerate() {
assert_eq!(run(input), expected[index]);
}
}
#[test]
fn test_challenge() {
let challenge_input = read_file("tests/challenge_input");
assert_eq!(run(&challenge_input), (2592, 2360));
}
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,3 @@
>
^>v<
^v^v^v^v^v

View file

@ -0,0 +1,9 @@
[package]
name = "day04-ideal_stocking_suffer"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
md-5 = "0.10.5"

View file

@ -0,0 +1,26 @@
\--- Day 4: The Ideal Stocking Stuffer ---
----------
Santa needs help [mining](https://en.wikipedia.org/wiki/Bitcoin#Mining) some AdventCoins (very similar to [bitcoins](https://en.wikipedia.org/wiki/Bitcoin)) to use as gifts for all the economically forward-thinking little girls and boys.
To do this, he needs to find [MD5](https://en.wikipedia.org/wiki/MD5) hashes which, in [hexadecimal](https://en.wikipedia.org/wiki/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...`.
Your puzzle answer was `254575`.
\--- Part Two ---
----------
Now find one that starts with *six zeroes*.
Your puzzle answer was `1038736`.
Both parts of this puzzle are complete! They provide two gold stars: \*\*
At this point, all that is left is for you to [admire your Advent calendar](/2015).
Your puzzle input was `bgvyzdsv`.

View file

@ -0,0 +1,51 @@
use md5::{Md5, Digest};
fn hash_has_leading_zeroes(input: &str, counter: usize, zeroes: usize) -> bool {
let mut hasher = Md5::new();
hasher.update(input.to_owned() + &(counter.to_string())[..]);
let hash = hasher.finalize();
for i in 0..zeroes/2 {
if hash[i] != 0 {
return false;
}
if zeroes % 2 == 1 && hash[zeroes/2] >= 16 {
return false;
}
}
true
}
pub fn run(input: &str) -> (usize, usize) {
let first = (0..).find(|i| hash_has_leading_zeroes(input, *i, 5)).unwrap();
let second = (first..).find(|i| hash_has_leading_zeroes(input, *i, 6)).unwrap();
(first, second)
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::read_to_string;
fn read_file(name: &str) -> String {
read_to_string(name).expect(&format!("Unable to read file: {}", name)[..])
}
#[test]
fn test_sample() {
let sample_input = read_file("tests/sample_input");
let expected = [(609043, 6742839), (1048970, 5714438)];
for (idx, input) in sample_input.lines().enumerate() {
assert_eq!(run(input), expected[idx]);
}
}
#[test]
fn test_challenge() {
let challenge_input = read_file("tests/challenge_input");
for input in challenge_input.lines() {
assert_eq!(run(input), (254575, 1038736));
}
}
}

View file

@ -0,0 +1 @@
bgvyzdsv

View file

@ -0,0 +1,2 @@
abcdef
pqrstuv

View file

@ -0,0 +1,8 @@
[package]
name = "day05-doesnt_he_have_intern-elves_for_this"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

@ -0,0 +1,49 @@
\--- Day 5: Doesn't He Have Intern-Elves For This? ---
----------
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?
Your puzzle answer was `255`.
\--- Part Two ---
----------
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.
How many strings are nice under these new rules?
Your puzzle answer was `55`.
Both parts of this puzzle are complete! They provide two gold stars: \*\*
At this point, all that is left is for you to [admire your Advent calendar](/2015).
If you still want to see it, you can [get your puzzle input](5/input).

View file

@ -0,0 +1,65 @@
use std::fs::read_to_string;
fn read_file(name: &str) -> String {
read_to_string(name).expect(&format!("Unable to read file: {}", name)[..])
}
fn is_vowel(c: char) -> bool {
['a', 'e', 'i', 'o', 'u'].contains(&c)
}
fn is_nice_v2(line: &str) -> bool {
let mut pair = false;
for j in 0..line.len()-3 {
let this_pair = &line[j..=j+1];
if line[j+2..].contains(this_pair) {
pair = true;
break;
}
}
let mut repeat = false;
for i in 0..line.len()-2 {
if line.chars().nth(i) == line.chars().nth(i+2) {
repeat = true;
break;
}
}
pair && repeat
}
fn is_nice_v1(line: &str) -> bool {
let mut repeat = false;
for i in 0..line.len()-1 {
if line.chars().nth(i) == line.chars().nth(i+1) {
repeat = true;
break;
}
}
line.chars().filter(|c| is_vowel(*c)).count() > 2 &&
repeat &&
!line.contains("ab") && !line.contains("cd") && !line.contains("pq") && !line.contains("xy")
}
pub fn run(input: &str) -> (usize, usize) {
let first = input.lines().filter(|l| is_nice_v1(l)).count();
let second = input.lines().filter(|l| is_nice_v2(l)).count();
(first, second)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sample() {
let sample_input = read_file("tests/sample_input");
assert_eq!(run(&sample_input), (2, 2));
}
#[test]
fn test_challenge() {
let challenge_input = read_file("tests/challenge_input");
assert_eq!(run(&challenge_input), (255, 55));
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,9 @@
ugknbfddgicrmopn
aaa
jchzalrnumimnmhp
haegwjzuvuyypxyu
dvszwmarrgswjxmb
qjhvhtzxzqqjkmpb
xxyxx
uurcxstgmygtbstg
ieodomkazucvgmuy

View file

@ -0,0 +1,8 @@
[package]
name = "day06-probably_a_fire_hazard"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

@ -0,0 +1,48 @@
\--- Day 6: Probably a Fire Hazard ---
----------
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*?
Your puzzle answer was `543903`.
\--- Part Two ---
----------
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`.
Your puzzle answer was `14687245`.
Both parts of this puzzle are complete! They provide two gold stars: \*\*
At this point, all that is left is for you to [admire your Advent calendar](/2015).
If you still want to see it, you can [get your puzzle input](6/input).

View file

@ -0,0 +1,78 @@
use std::fs::read_to_string;
enum Command { On, Off, Toggle }
fn read_file(name: &str) -> String {
read_to_string(name).expect(&format!("Unable to read file: {}", name)[..])
}
fn perform(instruction: &str, target: &mut [Vec<u32>], op_mode: u8) {
let components: Vec<&str> = instruction.split(' ').collect();
let (command, tl, br) = match components.len() {
4 => (Command::Toggle, components[1], components[3]),
5 if components[1] == "on" => (Command::On, components[2], components[4]),
5 if components[1] == "off" => (Command::Off, components[2], components[4]),
_ => panic!("Unable to parse {instruction}"),
};
let (x_min, y_min) = tl.split_once(',').unwrap();
let (x_max, y_max) = br.split_once(',').unwrap();
let x_min = x_min.parse::<usize>().unwrap();
let x_max = x_max.parse::<usize>().unwrap();
let y_min = y_min.parse::<usize>().unwrap();
let y_max = y_max.parse::<usize>().unwrap();
target.iter_mut()
.take(x_max+1)
.skip(x_min)
.for_each(|row| { row.iter_mut()
.take(y_max+1)
.skip(y_min)
.for_each(|cell| {
let old_val = *cell;
if op_mode == 1 {
*cell = match command {
Command::On => 1,
Command::Off => 0,
Command::Toggle => 1-old_val,
};
} else {
*cell = match command {
Command::On => old_val + 1,
Command::Off => old_val.saturating_sub(1),
Command::Toggle => old_val + 2,
};
}
});
});
}
pub fn run(input: &str) -> (u32, u32) {
let mut lights_1 = vec![vec![0_u32; 1000]; 1000];
let mut lights_2 = vec![vec![0_u32; 1000]; 1000];
for instruction in input.lines() {
perform(instruction, &mut lights_1, 1);
perform(instruction, &mut lights_2, 2);
}
let first = lights_1.iter().flatten().sum();
let second = lights_2.iter().flatten().sum();
(first, second)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sample() {
let sample_input = read_file("tests/sample_input");
assert_eq!(run(&sample_input), (998996, 1_001_996));
}
#[test]
fn test_challenge() {
let challenge_input = read_file("tests/challenge_input");
assert_eq!(run(&challenge_input), (543903, 14687245));
}
}

View file

@ -0,0 +1,300 @@
toggle 461,550 through 564,900
turn off 370,39 through 425,839
turn off 464,858 through 833,915
turn off 812,389 through 865,874
turn on 599,989 through 806,993
turn on 376,415 through 768,548
turn on 606,361 through 892,600
turn off 448,208 through 645,684
toggle 50,472 through 452,788
toggle 205,417 through 703,826
toggle 533,331 through 906,873
toggle 857,493 through 989,970
turn off 631,950 through 894,975
turn off 387,19 through 720,700
turn off 511,843 through 581,945
toggle 514,557 through 662,883
turn off 269,809 through 876,847
turn off 149,517 through 716,777
turn off 994,939 through 998,988
toggle 467,662 through 555,957
turn on 952,417 through 954,845
turn on 565,226 through 944,880
turn on 214,319 through 805,722
toggle 532,276 through 636,847
toggle 619,80 through 689,507
turn on 390,706 through 884,722
toggle 17,634 through 537,766
toggle 706,440 through 834,441
toggle 318,207 through 499,530
toggle 698,185 through 830,343
toggle 566,679 through 744,716
toggle 347,482 through 959,482
toggle 39,799 through 981,872
turn on 583,543 through 846,710
turn off 367,664 through 595,872
turn on 805,439 through 964,995
toggle 209,584 through 513,802
turn off 106,497 through 266,770
turn on 975,2 through 984,623
turn off 316,684 through 369,876
turn off 30,309 through 259,554
turn off 399,680 through 861,942
toggle 227,740 through 850,829
turn on 386,603 through 552,879
turn off 703,795 through 791,963
turn off 573,803 through 996,878
turn off 993,939 through 997,951
turn on 809,221 through 869,723
turn off 38,720 through 682,751
turn off 318,732 through 720,976
toggle 88,459 through 392,654
turn off 865,654 through 911,956
toggle 264,284 through 857,956
turn off 281,776 through 610,797
toggle 492,660 through 647,910
turn off 879,703 through 925,981
turn off 772,414 through 974,518
turn on 694,41 through 755,96
turn on 452,406 through 885,881
turn off 107,905 through 497,910
turn off 647,222 through 910,532
turn on 679,40 through 845,358
turn off 144,205 through 556,362
turn on 871,804 through 962,878
turn on 545,676 through 545,929
turn off 316,716 through 413,941
toggle 488,826 through 755,971
toggle 957,832 through 976,992
toggle 857,770 through 905,964
toggle 319,198 through 787,673
turn on 832,813 through 863,844
turn on 818,296 through 818,681
turn on 71,699 through 91,960
turn off 838,578 through 967,928
toggle 440,856 through 507,942
toggle 121,970 through 151,974
toggle 391,192 through 659,751
turn on 78,210 through 681,419
turn on 324,591 through 593,939
toggle 159,366 through 249,760
turn off 617,167 through 954,601
toggle 484,607 through 733,657
turn on 587,96 through 888,819
turn off 680,984 through 941,991
turn on 800,512 through 968,691
turn off 123,588 through 853,603
turn on 1,862 through 507,912
turn on 699,839 through 973,878
turn off 848,89 through 887,893
toggle 344,353 through 462,403
turn on 780,731 through 841,760
toggle 693,973 through 847,984
toggle 989,936 through 996,958
toggle 168,475 through 206,963
turn on 742,683 through 769,845
toggle 768,116 through 987,396
turn on 190,364 through 617,526
turn off 470,266 through 530,839
toggle 122,497 through 969,645
turn off 492,432 through 827,790
turn on 505,636 through 957,820
turn on 295,476 through 698,958
toggle 63,298 through 202,396
turn on 157,315 through 412,939
turn off 69,789 through 134,837
turn off 678,335 through 896,541
toggle 140,516 through 842,668
turn off 697,585 through 712,668
toggle 507,832 through 578,949
turn on 678,279 through 886,621
toggle 449,744 through 826,910
turn off 835,354 through 921,741
toggle 924,878 through 985,952
turn on 666,503 through 922,905
turn on 947,453 through 961,587
toggle 525,190 through 795,654
turn off 62,320 through 896,362
turn on 21,458 through 972,536
turn on 446,429 through 821,970
toggle 376,423 through 805,455
toggle 494,896 through 715,937
turn on 583,270 through 667,482
turn off 183,468 through 280,548
toggle 623,289 through 750,524
turn on 836,706 through 967,768
turn on 419,569 through 912,908
turn on 428,260 through 660,433
turn off 683,627 through 916,816
turn on 447,973 through 866,980
turn on 688,607 through 938,990
turn on 245,187 through 597,405
turn off 558,843 through 841,942
turn off 325,666 through 713,834
toggle 672,606 through 814,935
turn off 161,812 through 490,954
turn on 950,362 through 985,898
turn on 143,22 through 205,821
turn on 89,762 through 607,790
toggle 234,245 through 827,303
turn on 65,599 through 764,997
turn on 232,466 through 965,695
turn on 739,122 through 975,590
turn off 206,112 through 940,558
toggle 690,365 through 988,552
turn on 907,438 through 977,691
turn off 838,809 through 944,869
turn on 222,12 through 541,832
toggle 337,66 through 669,812
turn on 732,821 through 897,912
toggle 182,862 through 638,996
turn on 955,808 through 983,847
toggle 346,227 through 841,696
turn on 983,270 through 989,756
turn off 874,849 through 876,905
turn off 7,760 through 678,795
toggle 973,977 through 995,983
turn off 911,961 through 914,976
turn on 913,557 through 952,722
turn off 607,933 through 939,999
turn on 226,604 through 517,622
turn off 3,564 through 344,842
toggle 340,578 through 428,610
turn on 248,916 through 687,925
toggle 650,185 through 955,965
toggle 831,359 through 933,536
turn off 544,614 through 896,953
toggle 648,939 through 975,997
turn on 464,269 through 710,521
turn off 643,149 through 791,320
turn off 875,549 through 972,643
turn off 953,969 through 971,972
turn off 236,474 through 772,591
toggle 313,212 through 489,723
toggle 896,829 through 897,837
toggle 544,449 through 995,905
turn off 278,645 through 977,876
turn off 887,947 through 946,977
turn on 342,861 through 725,935
turn on 636,316 through 692,513
toggle 857,470 through 950,528
turn off 736,196 through 826,889
turn on 17,878 through 850,987
turn on 142,968 through 169,987
turn on 46,470 through 912,853
turn on 182,252 through 279,941
toggle 261,143 through 969,657
turn off 69,600 through 518,710
turn on 372,379 through 779,386
toggle 867,391 through 911,601
turn off 174,287 through 900,536
toggle 951,842 through 993,963
turn off 626,733 through 985,827
toggle 622,70 through 666,291
turn off 980,671 through 985,835
turn off 477,63 through 910,72
turn off 779,39 through 940,142
turn on 986,570 through 997,638
toggle 842,805 through 943,985
turn off 890,886 through 976,927
turn off 893,172 through 897,619
turn off 198,780 through 835,826
toggle 202,209 through 219,291
turn off 193,52 through 833,283
toggle 414,427 through 987,972
turn on 375,231 through 668,236
turn off 646,598 through 869,663
toggle 271,462 through 414,650
turn off 679,121 through 845,467
toggle 76,847 through 504,904
turn off 15,617 through 509,810
toggle 248,105 through 312,451
turn off 126,546 through 922,879
turn on 531,831 through 903,872
toggle 602,431 through 892,792
turn off 795,223 through 892,623
toggle 167,721 through 533,929
toggle 813,251 through 998,484
toggle 64,640 through 752,942
turn on 155,955 through 892,985
turn on 251,329 through 996,497
turn off 341,716 through 462,994
toggle 760,127 through 829,189
turn on 86,413 through 408,518
toggle 340,102 through 918,558
turn off 441,642 through 751,889
turn on 785,292 through 845,325
turn off 123,389 through 725,828
turn on 905,73 through 983,270
turn off 807,86 through 879,276
toggle 500,866 through 864,916
turn on 809,366 through 828,534
toggle 219,356 through 720,617
turn off 320,964 through 769,990
turn off 903,167 through 936,631
toggle 300,137 through 333,693
toggle 5,675 through 755,848
turn off 852,235 through 946,783
toggle 355,556 through 941,664
turn on 810,830 through 867,891
turn off 509,869 through 667,903
toggle 769,400 through 873,892
turn on 553,614 through 810,729
turn on 179,873 through 589,962
turn off 466,866 through 768,926
toggle 143,943 through 465,984
toggle 182,380 through 569,552
turn off 735,808 through 917,910
turn on 731,802 through 910,847
turn off 522,74 through 731,485
turn on 444,127 through 566,996
turn off 232,962 through 893,979
turn off 231,492 through 790,976
turn on 874,567 through 943,684
toggle 911,840 through 990,932
toggle 547,895 through 667,935
turn off 93,294 through 648,636
turn off 190,902 through 532,970
turn off 451,530 through 704,613
toggle 936,774 through 937,775
turn off 116,843 through 533,934
turn on 950,906 through 986,993
turn on 910,51 through 945,989
turn on 986,498 through 994,945
turn off 125,324 through 433,704
turn off 60,313 through 75,728
turn on 899,494 through 940,947
toggle 832,316 through 971,817
toggle 994,983 through 998,984
toggle 23,353 through 917,845
toggle 174,799 through 658,859
turn off 490,878 through 534,887
turn off 623,963 through 917,975
toggle 721,333 through 816,975
toggle 589,687 through 890,921
turn on 936,388 through 948,560
turn off 485,17 through 655,610
turn on 435,158 through 689,495
turn on 192,934 through 734,936
turn off 299,723 through 622,847
toggle 484,160 through 812,942
turn off 245,754 through 818,851
turn on 298,419 through 824,634
toggle 868,687 through 969,760
toggle 131,250 through 685,426
turn off 201,954 through 997,983
turn on 353,910 through 832,961
turn off 518,781 through 645,875
turn off 866,97 through 924,784
toggle 836,599 through 857,767
turn on 80,957 through 776,968
toggle 277,130 through 513,244
turn off 62,266 through 854,434
turn on 792,764 through 872,842
turn off 160,949 through 273,989
turn off 664,203 through 694,754
toggle 491,615 through 998,836
turn off 210,146 through 221,482
turn off 209,780 through 572,894
turn on 766,112 through 792,868
turn on 222,12 through 856,241

View file

@ -0,0 +1,3 @@
turn on 0,0 through 999,999
toggle 0,0 through 999,0
turn off 499,499 through 500,500

View file

@ -0,0 +1,8 @@
[package]
name = "day07-some_assembly_required"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

@ -0,0 +1,62 @@
\--- Day 7: Some Assembly Required ---
----------
This year, Santa brought little Bobby Tables a set of wires and [bitwise logic gates](https://en.wikipedia.org/wiki/Bitwise_operation)! Unfortunately, little Bobby is a little under the recommended age range, and he needs help assembling the circuit.
Each wire has an identifier (some lowercase letters) and can carry a [16-bit](https://en.wikipedia.org/wiki/16-bit) signal (a number from `0` to `65535`). A signal is provided to each wire by a gate, another wire, or some specific value. Each wire can only get a signal from one source, but can provide its signal to multiple destinations. A gate provides no signal until all of its inputs have a signal.
The included instructions booklet describes how to connect the parts together: `x AND y -> z` means to connect wires `x` and `y` to an AND gate, and then connect its output to wire `z`.
For example:
* `123 -> x` means that the signal `123` is provided to wire `x`.
* `x AND y -> z` means that the [bitwise AND](https://en.wikipedia.org/wiki/Bitwise_operation#AND) of wire `x` and wire `y` is provided to wire `z`.
* `p LSHIFT 2 -> q` means that the value from wire `p` is [left-shifted](https://en.wikipedia.org/wiki/Logical_shift) by `2` and then provided to wire `q`.
* `NOT e -> f` means that the [bitwise complement](https://en.wikipedia.org/wiki/Bitwise_operation#NOT) of the value from wire `e` is provided to wire `f`.
Other possible gates include `OR` ([bitwise OR](https://en.wikipedia.org/wiki/Bitwise_operation#OR)) and `RSHIFT` ([right-shift](https://en.wikipedia.org/wiki/Logical_shift)). If, for some reason, you'd like to *emulate* the circuit instead, almost all programming languages (for example, [C](https://en.wikipedia.org/wiki/Bitwise_operations_in_C), [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators), or [Python](https://wiki.python.org/moin/BitwiseOperators)) provide operators for these gates.
For example, here is a simple circuit:
```
123 -> x
456 -> y
x AND y -> d
x OR y -> e
x LSHIFT 2 -> f
y RSHIFT 2 -> g
NOT x -> h
NOT y -> i
```
After it is run, these are the signals on the wires:
```
d: 72
e: 507
f: 492
g: 114
h: 65412
i: 65079
x: 123
y: 456
```
In little Bobby's kit's instructions booklet (provided as your puzzle input), what signal is ultimately provided to *wire `a`*?
Your puzzle answer was `46065`.
\--- Part Two ---
----------
Now, take the signal you got on wire `a`, override wire `b` to that signal, and reset the other wires (including wire `a`). What new signal is ultimately provided to wire `a`?
Your puzzle answer was `14134`.
Both parts of this puzzle are complete! They provide two gold stars: \*\*
At this point, all that is left is for you to [admire your Advent calendar](/2015).
If you still want to see it, you can [get your puzzle input](7/input).

View file

@ -0,0 +1,87 @@
use std::collections::HashMap;
#[derive(Clone)]
pub enum Instruction {
And(String, String),
Or(String, String),
Not(String),
Lshift(String, u8),
Rshift(String, u8),
Equal(String),
}
impl Instruction {
fn parse(line: &str) -> (String, Instruction) {
let components: Vec<&str> = line.split(' ').collect();
match components[1] {
"->" => (components[2].to_string(), Instruction::Equal(components[0].to_string())),
"AND" => (components[4].to_string(), Instruction::And(components[0].to_string(), components[2].to_string())),
"OR" => (components[4].to_string(), Instruction::Or(components[0].to_string(), components[2].to_string())),
"LSHIFT" => (components[4].to_string(), Instruction::Lshift(components[0].to_string(), components[2].parse().unwrap())),
"RSHIFT" => (components[4].to_string(), Instruction::Rshift(components[0].to_string(), components[2].parse().unwrap())),
_ => (components[3].to_string(), Instruction::Not(components[1].to_string())),
}
}
}
pub fn eval_for(wire: String, circuit: &mut HashMap<String, Instruction>) -> u16 {
if let Ok(num) = wire.parse::<u16>() {
return num;
}
let instruction = Instruction::clone(circuit.get(&wire).unwrap_or_else(|| panic!("Wire not found: {wire}")));
let result = match instruction {
Instruction::Equal(val) => eval_for(val, circuit),
Instruction::Not(val) => !(eval_for(val, circuit)),
Instruction::And(l, r) => (eval_for(l, circuit)) & (eval_for(r, circuit)),
Instruction::Or(l, r) => (eval_for(l, circuit)) | (eval_for(r, circuit)),
Instruction::Lshift(val, bits) => eval_for(val, circuit) << bits,
Instruction::Rshift(val, bits) => eval_for(val, circuit) >> bits,
};
circuit.insert(wire, Instruction::Equal(result.to_string()));
result
}
pub fn assemble(input: &str) -> HashMap<String, Instruction> {
input.lines()
.map(Instruction::parse)
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::read_to_string;
fn read_file(name: &str) -> String {
read_to_string(name).expect(&format!("Unable to read file: {}", name)[..])
}
#[test]
fn test_sample() {
let sample_input = read_file("tests/sample_input");
let mut circuit = assemble(&sample_input);
let expected = [
("d", 72),
("e", 507),
("f", 492),
("g", 114),
("h", 65412),
("i", 65079),
("x", 123),
("y", 456),
];
for (wire, output) in expected {
assert_eq!(eval_for(wire.to_string(), &mut circuit), output);
}
}
#[test]
fn test_challenge() {
let challenge_input = read_file("tests/challenge_input");
let mut circuit = assemble(&challenge_input);
let first_a = eval_for(String::from("a"), &mut circuit.clone());
assert_eq!(first_a, 46065);
circuit.insert(String::from("b"), Instruction::Equal(first_a.to_string()));
assert_eq!(eval_for(String::from("a"), &mut circuit), 14134);
}
}

View file

@ -0,0 +1,339 @@
bn RSHIFT 2 -> bo
lf RSHIFT 1 -> ly
fo RSHIFT 3 -> fq
cj OR cp -> cq
fo OR fz -> ga
t OR s -> u
lx -> a
NOT ax -> ay
he RSHIFT 2 -> hf
lf OR lq -> lr
lr AND lt -> lu
dy OR ej -> ek
1 AND cx -> cy
hb LSHIFT 1 -> hv
1 AND bh -> bi
ih AND ij -> ik
c LSHIFT 1 -> t
ea AND eb -> ed
km OR kn -> ko
NOT bw -> bx
ci OR ct -> cu
NOT p -> q
lw OR lv -> lx
NOT lo -> lp
fp OR fv -> fw
o AND q -> r
dh AND dj -> dk
ap LSHIFT 1 -> bj
bk LSHIFT 1 -> ce
NOT ii -> ij
gh OR gi -> gj
kk RSHIFT 1 -> ld
lc LSHIFT 1 -> lw
lb OR la -> lc
1 AND am -> an
gn AND gp -> gq
lf RSHIFT 3 -> lh
e OR f -> g
lg AND lm -> lo
ci RSHIFT 1 -> db
cf LSHIFT 1 -> cz
bn RSHIFT 1 -> cg
et AND fe -> fg
is OR it -> iu
kw AND ky -> kz
ck AND cl -> cn
bj OR bi -> bk
gj RSHIFT 1 -> hc
iu AND jf -> jh
NOT bs -> bt
kk OR kv -> kw
ks AND ku -> kv
hz OR ik -> il
b RSHIFT 1 -> v
iu RSHIFT 1 -> jn
fo RSHIFT 5 -> fr
be AND bg -> bh
ga AND gc -> gd
hf OR hl -> hm
ld OR le -> lf
as RSHIFT 5 -> av
fm OR fn -> fo
hm AND ho -> hp
lg OR lm -> ln
NOT kx -> ky
kk RSHIFT 3 -> km
ek AND em -> en
NOT ft -> fu
NOT jh -> ji
jn OR jo -> jp
gj AND gu -> gw
d AND j -> l
et RSHIFT 1 -> fm
jq OR jw -> jx
ep OR eo -> eq
lv LSHIFT 15 -> lz
NOT ey -> ez
jp RSHIFT 2 -> jq
eg AND ei -> ej
NOT dm -> dn
jp AND ka -> kc
as AND bd -> bf
fk OR fj -> fl
dw OR dx -> dy
lj AND ll -> lm
ec AND ee -> ef
fq AND fr -> ft
NOT kp -> kq
ki OR kj -> kk
cz OR cy -> da
as RSHIFT 3 -> au
an LSHIFT 15 -> ar
fj LSHIFT 15 -> fn
1 AND fi -> fj
he RSHIFT 1 -> hx
lf RSHIFT 2 -> lg
kf LSHIFT 15 -> kj
dz AND ef -> eh
ib OR ic -> id
lf RSHIFT 5 -> li
bp OR bq -> br
NOT gs -> gt
fo RSHIFT 1 -> gh
bz AND cb -> cc
ea OR eb -> ec
lf AND lq -> ls
NOT l -> m
hz RSHIFT 3 -> ib
NOT di -> dj
NOT lk -> ll
jp RSHIFT 3 -> jr
jp RSHIFT 5 -> js
NOT bf -> bg
s LSHIFT 15 -> w
eq LSHIFT 1 -> fk
jl OR jk -> jm
hz AND ik -> im
dz OR ef -> eg
1 AND gy -> gz
la LSHIFT 15 -> le
br AND bt -> bu
NOT cn -> co
v OR w -> x
d OR j -> k
1 AND gd -> ge
ia OR ig -> ih
NOT go -> gp
NOT ed -> ee
jq AND jw -> jy
et OR fe -> ff
aw AND ay -> az
ff AND fh -> fi
ir LSHIFT 1 -> jl
gg LSHIFT 1 -> ha
x RSHIFT 2 -> y
db OR dc -> dd
bl OR bm -> bn
ib AND ic -> ie
x RSHIFT 3 -> z
lh AND li -> lk
ce OR cd -> cf
NOT bb -> bc
hi AND hk -> hl
NOT gb -> gc
1 AND r -> s
fw AND fy -> fz
fb AND fd -> fe
1 AND en -> eo
z OR aa -> ab
bi LSHIFT 15 -> bm
hg OR hh -> hi
kh LSHIFT 1 -> lb
cg OR ch -> ci
1 AND kz -> la
gf OR ge -> gg
gj RSHIFT 2 -> gk
dd RSHIFT 2 -> de
NOT ls -> lt
lh OR li -> lj
jr OR js -> jt
au AND av -> ax
0 -> c
he AND hp -> hr
id AND if -> ig
et RSHIFT 5 -> ew
bp AND bq -> bs
e AND f -> h
ly OR lz -> ma
1 AND lu -> lv
NOT jd -> je
ha OR gz -> hb
dy RSHIFT 1 -> er
iu RSHIFT 2 -> iv
NOT hr -> hs
as RSHIFT 1 -> bl
kk RSHIFT 2 -> kl
b AND n -> p
ln AND lp -> lq
cj AND cp -> cr
dl AND dn -> do
ci RSHIFT 2 -> cj
as OR bd -> be
ge LSHIFT 15 -> gi
hz RSHIFT 5 -> ic
dv LSHIFT 1 -> ep
kl OR kr -> ks
gj OR gu -> gv
he RSHIFT 5 -> hh
NOT fg -> fh
hg AND hh -> hj
b OR n -> o
jk LSHIFT 15 -> jo
gz LSHIFT 15 -> hd
cy LSHIFT 15 -> dc
kk RSHIFT 5 -> kn
ci RSHIFT 3 -> ck
at OR az -> ba
iu RSHIFT 3 -> iw
ko AND kq -> kr
NOT eh -> ei
aq OR ar -> as
iy AND ja -> jb
dd RSHIFT 3 -> df
bn RSHIFT 3 -> bp
1 AND cc -> cd
at AND az -> bb
x OR ai -> aj
kk AND kv -> kx
ao OR an -> ap
dy RSHIFT 3 -> ea
x RSHIFT 1 -> aq
eu AND fa -> fc
kl AND kr -> kt
ia AND ig -> ii
df AND dg -> di
NOT fx -> fy
k AND m -> n
bn RSHIFT 5 -> bq
km AND kn -> kp
dt LSHIFT 15 -> dx
hz RSHIFT 2 -> ia
aj AND al -> am
cd LSHIFT 15 -> ch
hc OR hd -> he
he RSHIFT 3 -> hg
bn OR by -> bz
NOT kt -> ku
z AND aa -> ac
NOT ak -> al
cu AND cw -> cx
NOT ie -> if
dy RSHIFT 2 -> dz
ip LSHIFT 15 -> it
de OR dk -> dl
au OR av -> aw
jg AND ji -> jj
ci AND ct -> cv
dy RSHIFT 5 -> eb
hx OR hy -> hz
eu OR fa -> fb
gj RSHIFT 3 -> gl
fo AND fz -> gb
1 AND jj -> jk
jp OR ka -> kb
de AND dk -> dm
ex AND ez -> fa
df OR dg -> dh
iv OR jb -> jc
x RSHIFT 5 -> aa
NOT hj -> hk
NOT im -> in
fl LSHIFT 1 -> gf
hu LSHIFT 15 -> hy
iq OR ip -> ir
iu RSHIFT 5 -> ix
NOT fc -> fd
NOT el -> em
ck OR cl -> cm
et RSHIFT 3 -> ev
hw LSHIFT 1 -> iq
ci RSHIFT 5 -> cl
iv AND jb -> jd
dd RSHIFT 5 -> dg
as RSHIFT 2 -> at
NOT jy -> jz
af AND ah -> ai
1 AND ds -> dt
jx AND jz -> ka
da LSHIFT 1 -> du
fs AND fu -> fv
jp RSHIFT 1 -> ki
iw AND ix -> iz
iw OR ix -> iy
eo LSHIFT 15 -> es
ev AND ew -> ey
ba AND bc -> bd
fp AND fv -> fx
jc AND je -> jf
et RSHIFT 2 -> eu
kg OR kf -> kh
iu OR jf -> jg
er OR es -> et
fo RSHIFT 2 -> fp
NOT ca -> cb
bv AND bx -> by
u LSHIFT 1 -> ao
cm AND co -> cp
y OR ae -> af
bn AND by -> ca
1 AND ke -> kf
jt AND jv -> jw
fq OR fr -> fs
dy AND ej -> el
NOT kc -> kd
ev OR ew -> ex
dd OR do -> dp
NOT cv -> cw
gr AND gt -> gu
dd RSHIFT 1 -> dw
NOT gw -> gx
NOT iz -> ja
1 AND io -> ip
NOT ag -> ah
b RSHIFT 5 -> f
NOT cr -> cs
kb AND kd -> ke
jr AND js -> ju
cq AND cs -> ct
il AND in -> io
NOT ju -> jv
du OR dt -> dv
dd AND do -> dq
b RSHIFT 2 -> d
jm LSHIFT 1 -> kg
NOT dq -> dr
bo OR bu -> bv
gk OR gq -> gr
he OR hp -> hq
NOT h -> i
hf AND hl -> hn
gv AND gx -> gy
x AND ai -> ak
bo AND bu -> bw
hq AND hs -> ht
hz RSHIFT 1 -> is
gj RSHIFT 5 -> gm
g AND i -> j
gk AND gq -> gs
dp AND dr -> ds
b RSHIFT 3 -> e
gl AND gm -> go
gl OR gm -> gn
y AND ae -> ag
hv OR hu -> hw
1674 -> b
ab AND ad -> ae
NOT ac -> ad
1 AND ht -> hu
NOT hn -> ho

View file

@ -0,0 +1,8 @@
123 -> x
456 -> y
x AND y -> d
x OR y -> e
x LSHIFT 2 -> f
y RSHIFT 2 -> g
NOT x -> h
NOT y -> i

View file

@ -0,0 +1,8 @@
[package]
name = "day08-matchsticks"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

@ -0,0 +1,45 @@
\--- Day 8: Matchsticks ---
----------
Space on the sleigh is limited this year, and so Santa will be bringing his list as a digital copy. He needs to know how much space it will take up when stored.
It is common in many programming languages to provide a way to escape special characters in strings. For example, [C](https://en.wikipedia.org/wiki/Escape_sequences_in_C), [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String), [Perl](http://perldoc.perl.org/perlop.html#Quote-and-Quote-like-Operators), [Python](https://docs.python.org/2.0/ref/strings.html), and even [PHP](http://php.net/manual/en/language.types.string.php#language.types.string.syntax.double) handle special characters in very similar ways.
However, it is important to realize the difference between the number of characters *in the code representation of the string literal* and the number of characters *in the in-memory string itself*.
For example:
* `""` is `2` characters of code (the two double quotes), but the string contains zero characters.
* `"abc"` is `5` characters of code, but `3` characters in the string data.
* `"aaa\"aaa"` is `10` characters of code, but the string itself contains six "a" characters and a single, escaped quote character, for a total of `7` characters in the string data.
* `"\x27"` is `6` characters of code, but the string itself contains just one - an apostrophe (`'`), escaped using hexadecimal notation.
Santa's list is a file that contains many double-quoted string literals, one on each line. The only escape sequences used are `\\` (which represents a single backslash), `\"` (which represents a lone double-quote character), and `\x` plus two hexadecimal characters (which represents a single character with that ASCII code).
Disregarding the whitespace in the file, what is *the number of characters of code for string literals* minus *the number of characters in memory for the values of the strings* in total for the entire file?
For example, given the four strings above, the total number of characters of string code (`2 + 5 + 10 + 6 = 23`) minus the total number of characters in memory for string values (`0 + 3 + 7 + 1 = 11`) is `23 - 11 = 12`.
Your puzzle answer was `1333`.
\--- Part Two ---
----------
Now, let's go the other way. In addition to finding the number of characters of code, you should now *encode each code representation as a new string* and find the number of characters of the new encoded representation, including the surrounding double quotes.
For example:
* `""` encodes to `"\"\""`, an increase from `2` characters to `6`.
* `"abc"` encodes to `"\"abc\""`, an increase from `5` characters to `9`.
* `"aaa\"aaa"` encodes to `"\"aaa\\\"aaa\""`, an increase from `10` characters to `16`.
* `"\x27"` encodes to `"\"\\x27\""`, an increase from `6` characters to `11`.
Your task is to find *the total number of characters to represent the newly encoded strings* minus *the number of characters of code in each original string literal*. For example, for the strings above, the total encoded length (`6 + 9 + 16 + 11 = 42`) minus the characters in the original code representation (`23`, just like in the first part of this puzzle) is `42 - 23 = 19`.
Your puzzle answer was `2046`.
Both parts of this puzzle are complete! They provide two gold stars: \*\*
At this point, all that is left is for you to [admire your Advent calendar](/2015).
If you still want to see it, you can [get your puzzle input](8/input).

View file

@ -0,0 +1,62 @@
pub fn run(input: &str) -> (usize, usize) {
let first = input.lines().map(get_decoding_overhead).sum();
let second = input.lines().map(get_encoding_overhead).sum();
(first, second)
}
fn get_decoding_overhead(line: &str) -> usize {
let mut rendered_len = 0;
let mut literal = true;
for c in line.chars() {
match c {
'"' => {
if !literal {
rendered_len += 1;
literal = true;
}
},
'\\' => {
if !literal {
rendered_len += 1;
}
literal = !literal;
},
'x' => {
if literal {
rendered_len += 1;
} else {
rendered_len -= 1;
literal = true;
}
},
_ => rendered_len += 1
};
}
line.chars().count() - rendered_len as usize
}
fn get_encoding_overhead(line: &str) -> usize {
2 + line.matches('"').count() + line.matches('\\').count()
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::read_to_string;
fn read_file(name: &str) -> String {
read_to_string(name).expect(&format!("Unable to read file: {}", name)[..])
}
#[test]
fn test_sample() {
let sample_input = read_file("tests/sample_input");
assert_eq!(run(&sample_input), (12, 19));
}
#[test]
fn test_challenge() {
let challenge_input = read_file("tests/challenge_input");
assert_eq!(run(&challenge_input), (1333, 2046));
}
}

View file

@ -0,0 +1,300 @@
"sjdivfriyaaqa\xd2v\"k\"mpcu\"yyu\"en"
"vcqc"
"zbcwgmbpijcxu\"yins\"sfxn"
"yumngprx"
"bbdj"
"czbggabkzo\"wsnw\"voklp\"s"
"acwt"
"aqttwnsohbzian\"evtllfxwkog\"cunzw"
"ugvsgfv"
"xlnillibxg"
"kexh\"pmi"
"syvugow"
"m\"ktqnw"
"yrbajyndte\\rm"
"f\"kak\x70sn\xc4kjri"
"yxthr"
"alvumfsjni\"kohg"
"trajs\x5brom\xf1yoijaumkem\"\"tahlzs"
"\"oedr\"pwdbnnrc"
"qsmzhnx\""
"\"msoytqimx\\tbklqz"
"mjdfcgwdshrehgs"
"\"rivyxahf\""
"ciagc\x04bp"
"xkfc"
"xrgcripdu\x4c\xc4gszjhrvumvz\"mngbirb"
"gvmae\"yiiujoqvr\"mkxmgbbut\"u"
"ih"
"ncrqlejehs"
"mkno\x43pcfdukmemycp"
"uanzoqxkpsksbvdnkji\"feamp"
"axoufpnbx\\ao\x61pfj\"b"
"dz\\ztawzdjy"
"ihne\"enumvswypgf"
"\"dgazthrphbshdo\\vuqoiy\""
"dlnmptzt\\zahwpylc\\b\"gmslrqysk"
"mhxznyzcp"
"rebr\"amvxw\x5fmbnfpkkeghlntavj"
"lades\x47ncgdof\"\"jmbbk"
"dwxuis\xa5wdkx\\z\"admgnoddpgkt\\zs"
"g\\k\x27qsl\x34hwfglcdxqbeclt\xca\\"
"lhyjky\\m\"pvnm\\xmynpxnlhndmahjl"
"c\"uxabbgorrpprw\"xas\\vefkxioqpt"
"rfrvjxpevcmma\x71gtfipo"
"fgh\"kcwoqwfnjgdlzfclprg\"q"
"onxnwykrba"
"hkkg\x60f\"tjzsanpvarzgkfipl"
"\"aintes\"ofq\"juiaqlqxmvpe\\a"
"wiyczzs\"ciwk"
"mfqeu"
"v\xe1z\x7ftzalmvdmncfivrax\\rjwq"
"k\"vtg"
"exhrtdugeml\xf0"
"behnchkpld"
"mhgxy\"mfcrg\xc5gnp\"\"osqhj"
"rlvjy"
"awe"
"ctwy"
"vt"
"\x54t"
"zugfmmfomz"
"cv\"cvcvfaada\x04fsuqjinbfh\xa9cq\xd2c\"d"
"oj"
"xazanf\"wbmcrn"
"\\\\zkisyjpbzandqikqjqvee"
"dpsnbzdwnxk\\v"
"sj\"tuupr\\oyoh"
"myvkgnw\x81q\xaaokt\\emgejbsyvxcl\\\xee"
"ejeuqvunjcirdkkpt\"nlns"
"twmlvwxyvfyqqzu"
"\"xwtzdp\x98qkcis\"dm\\\"ep\"xyykq"
"vvcq\\expok"
"wgukjfanjgpdjb"
"\"mjcjajnxy\\dcpc"
"wdvgnecw\\ab\x44klceduzgsvu"
"dqtqkukr\"iacngufbqkdpxlwjjt"
"\"xj\"\x66qofsqzkoah"
"nptiwwsqdep"
"gsnlxql\x30mjl"
"yeezwokjwrhelny\""
"bjauamn\\izpmzqqasid"
"tvjdbkn\"tiziw\x82r"
"w"
"xwoakbbnjnypnaa\xa9wft\"slrmoqkl"
"vwxtnlvaaasyruykgygrvpiopzygf\"vq"
"qdancvnvmhlmpj\\isdxs"
"xzc\\elw"
"b\"wxeqvy\"qf\"g\xcaoklsucwicyw\"dovr"
"yomlvvjdbngz\"rly\"afr"
"bfb\"x\"aweuwbwmoa\x13\"t\"zhr"
"\"dmfoxb\"qvpjzzhykt\xd2\"\"ryhxi"
"psqef\"yu\\qiflie\"\x79w"
"arzewkej\"lqmh\\sayyusxxo\\"
"vuvvp"
"hc\"lg\x6bcpupsewzklai\"l"
"cjdfygc\"auorqybnuqghsh\x10"
"j"
"wqjexk\"eyq\\lbroqhk\\dqzsqk"
"dws\"ru\"dvxfiwapif\"oqwzmle"
"agcykg\\jt\\vzklqjvknoe"
"kksd\"jmslja\\z\"y\\b\xaagpyojct"
"nnpipxufvbfpoz\"jno"
"dtw"
"xlolvtahvgqkx\\dgnhj\\spsclpcxv\\"
"mxea\\mbjpi"
"lgbotkk\"zmxh\\\\qji\"jszulnjsxkqf"
"lwckmhwhx\"gmftlb\x91am"
"xxdxqyxth"
"\"lmqhwkjxmvayxy"
"tf"
"qy"
"wdqmwxdztax\"m\"\x09\x11xdxmfwxmtqgwvf"
"\xcbnazlf\"ghziknszmsrahaf"
"e\x6aupmzhxlvwympgjjpdvo\"kylfa"
"\x81vhtlillb\xactgoatva"
"dvnlgr"
"f"
"xg\xfacwizsadgeclm"
"vnnrzbtw\"\\prod\\djbyppngwayy\""
"lrt\xf4jahwvfz"
"aqpnjtom\"ymkak\\dadfybqrso\\fwv"
"gz\"aac\"mrbk\"ktommrojraqh"
"wycamwoecsftepfnlcdkm"
"nrhddblbuzlqsl\x9cben"
"vckxhyqkmqmdseazcykrbysm"
"sil\xbbtevmt\"gvrvybui\"faw\"j"
"cjex\\tp\x45pzf"
"asjobvtxszfodgf\"ibftg"
"gkyjyjdrxdcllnh\"sjcibenrdnxv"
"oswsdpjyxpbwnqbcpl\"yrdvs\\zq"
"\"\"tyowzc\\fycbp\"jbwrbvgui"
"cbpcabqkdgzmpgcwjtrchxp"
"iyrzfh\x45gw\"fdlfpiaap\x31xqq"
"evgksznidz"
"b\\w\\"
"loufizbiy\x57aim\"bgk"
"qjfyk"
"g\"anmloghvgr\x07zwqougqhdz"
"usbbmwcxd\\bdgg"
"htitqcpczml"
"eke\\cqvpexqqk\"to\"tqmljrpn\xe6lji\""
"g\xd2ifdsej"
"h\"sk\"haajajpagtcqnzrfqn\xe6btzo"
"wfkuffdxlvm\\cvlyzlbyunclhmpp"
"myaavh\"spue"
"hqvez\x68d\"eo\"eaioh"
"s\"qd\"oyxxcglcdnuhk"
"ilqvar"
"srh"
"puuifxrfmpc\"bvalwi\x2blu\\"
"yywlbutufzysbncw\\nqsfbhpz\"mngjq"
"zbl\\jfcuop"
"hjdouiragzvxsqkreup\\"
"qi"
"ckx\\funlj\xa7ahi"
"k"
"ufrcnh\"ajteit"
"cqv\"bgjozjj\x60x\xa8yhvmdvutchjotyuz"
"hkuiet\"oku\x8cfhumfpasl"
"\"\\sbe\x4d"
"vhknazqt"
"eyyizvzcahgflvmoowvs\\jhvygci"
"kki\x3ewcefkgtjap\"xtpxh\"lzepoqj"
"wvtk"
"\"ynet"
"zh\\obk\"otagx\x59txfzf"
"ocowhxlx\xe6zqg\x63wx\\tclkhq\\vmaze"
"w\"cf"
"qpniprnrzrnvykghqnalr"
"jctcqra\"\x05dhlydpqamorqjsijt\\xjdgt"
"sig"
"qhlbidbflwxe\"xljbwls\x20vht"
"irmrebfla\xefsg\"j"
"nep"
"hjuvsqlizeqobepf"
"guzbcdp\"obyh"
"\"mjagins\xf9tqykaxy\""
"knvsdnmtr\"zervsb"
"hzuy"
"zza\"k\"buapb\\elm\xfeya"
"lrqar\"dfqwkaaqifig\"uixjsz"
"\"azuo\x40rmnlhhluwsbbdb\x32pk\\yu\"pbcf"
"dplkdyty"
"rfoyciebwlwphcycmguc"
"ivnmmiemhgytmlprq\\eh"
"lhkyzaaothfdhmbpsqd\\yyw"
"tnlzifupcjcaj"
"\\qiyirsdrfpmu\\\x15xusifaag"
"\\lcomf\\s"
"uramjivcirjhqcqcg"
"kkbaklbxfxikffnuhtu\xc6t\"d"
"n\xefai"
"\"toy\"bnbpevuzoc\"muywq\"gz\"grbm"
"\"muu\\wt"
"\\srby\"ee"
"erf\"gvw\"swfppf"
"pbqcgtn\"iuianhcdazfvmidn\\nslhxdf"
"uxbp"
"up\\mgrcyaegiwmjufn"
"nulscgcewj\\dvoyvhetdegzhs\""
"masv\"k\\rzrb"
"qtx\x79d\"xdxmbxrvhj"
"fid\\otpkgjlh\"qgsvexrckqtn\xf4"
"tagzu"
"bvl\\\"noseec"
"\\xgicuuh"
"w\"a\"npemf"
"sxp"
"nsmpktic\x8awxftscdcvijjobnq\"gjd"
"uks\"\"jxvyvfezz\"aynxoev\"cuoav"
"m"
"lkvokj"
"vkfam\"yllr\"q\x92o\x4ebecnvhshhqe\\"
"efdxcjkjverw"
"lmqzadwhfdgmep\x02tzfcbgrbfekhat"
"cpbk\x9azqegbpluczssouop\x36ztpuoxsw"
"cqwoczxdd\"erdjka"
"cwvqnjgbw\\fxdlby"
"mvtm"
"lt\"bbqzpumplkg"
"ntd\xeeuwweucnuuslqfzfq"
"y\xabl\"dbebxjrlbmuoo\\\x1au"
"qjoqx\\a"
"pu\"ekdnfpmly\xbago\""
"fjhhdy"
"arl"
"xcywisim\"bwuwf\"\"raepeawwjub"
"pbe"
"dbnqfpzyaumxtqnd\xc5dcqrkwyop"
"ojv\x40vtkwgkqepm\x8bzft\\vedrry"
"wggqkfbwqumsgajqwphjec\"mstxpwz"
"zjkbem"
"icpfqxbelxazlls"
"pvpqs\\abcmtyielugfgcv\"tjxapxqxnx"
"oqddwlvmtv\"\x39lyybylfb\"jmngnpjrdw"
"gisgbve"
"\"aglg"
"y\"\"ss\xafvhxlrjv"
"qbgqjsra"
"ihshbjgqpdcljpmdwdprwloy"
"djja\\wcdn\"svkrgpqn\"uz\"hc\x43hj"
"cbjm"
"pnn"
"pqvh\"noh"
"\"\\fdktlp"
"ncea"
"pqgzphiyy"
"\xbedovhxuipaohlcvkwtxwmpz\"ckaif\"r"
"arjuzbjowqciunfwgxtph\"vlhy\"n"
"c"
"nrpdxunulgudqzlhtae"
"iefheu\"uru\""
"aqijysxuijud\"np\\opbichhudil\xbesum"
"pfpevmtstl\"lde\"bzr\"vspdxs"
"vparfbdjwvzsocpnzhp"
"g\x4ffxaarafrsjthq\\\xc1rw"
"ng\\rqx\\gwpzucbh\xafl"
"rw\"nf\\dna"
"jkkeahxurxla\\g\xb3czrlsyimmwcwthr"
"twaailoypu\"oas\"kpuuyedlaw\\\xb0vzt"
"hznex\\gdiqvtugi"
"imdibsunjeswhk"
"ta\\icileuzpxro\"cfmv\"mzp"
"coykr\x57luiysucfaflmilhlehmvzeiepo"
"u\x3dfh\xd4yt"
"piw\x1bz\"eowy\"vfk\"wqiekw"
"gan\"y"
"p\"bevidoazcznr\"hddxuuq\""
"bwzucczznutbxe"
"z\"viqgyqjisior\\iecosmjbknol"
"dmlpcglcfkfsctxydjvayhymv\x3c\\gp"
"bfvkqrintbbvgfv"
"xlzntrgdck\"cprc\xadczyarbznqmuhxyuh"
"uqdxnuwioc\"kdytxq\\ig"
"xrafmucpmfi"
"vr\"hltmfrge"
"eonf\"nt\\wtcnsocs"
"j\xb7xoslyjeyjksplkqixncgkylkw"
"njw\"pefgfbez\x9axshdmplxzquqe"
"di\x58bvptfsafirpc"
"l\x1fkco"
"x"
"mprndo\"n"
"psegit"
"svbdnkkuuqs\"sqxu\"oqcyz\"aizashk"
"cwkljukxer\\\"\\nff\"esjwiyaoy"
"ilxrkgbjjxpvhdtq\"cpiuoofdnkpp"
"hlngi\"ulxep\\qohtmqnqjb\"rkgerho"
"gxws\"bcgm\"p"
"bv\"mds\\zhfusiepgrz\\b\x32fscdzz"
"l\xfampwtme\x69qvxnx\"\"\xc4jruuymjxrpsv"
"qqmxhrn"
"xziq\\\x18ybyv\x9am\"neacoqjzytertisysza"
"aqcbvlvcrzceeyx\\j\"\"x"
"yjuhhb"
"\x5em\"squulpy"
"dpbntplgmwb"
"utsgfkm\\vbftjknlktpthoeo"
"ccxjgiocmuhf\"ycnh"
"lltj\"kbbxi"

View file

@ -0,0 +1,4 @@
""
"abc"
"aaa\"aaa"
"\x27"

View file

@ -0,0 +1,8 @@
[package]
name = "day09-all_in_a_single_night"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

@ -0,0 +1,52 @@
\--- Day 9: All in a Single Night ---
----------
Every year, Santa manages to deliver all of his presents in a single night.
This year, however, he has some new locations to visit; his elves have provided him the distances between every pair of locations. He can start and end at any two (different) locations he wants, but he must visit each location exactly once. What is the *shortest distance* he can travel to achieve this?
For example, given the following distances:
```
London to Dublin = 464
London to Belfast = 518
Dublin to Belfast = 141
```
The possible routes are therefore:
```
Dublin -> London -> Belfast = 982
London -> Dublin -> Belfast = 605
London -> Belfast -> Dublin = 659
Dublin -> Belfast -> London = 659
Belfast -> Dublin -> London = 605
Belfast -> London -> Dublin = 982
```
The shortest of these is `London -> Dublin -> Belfast = 605`, and so the answer is `605` in this example.
What is the distance of the shortest route?
Your puzzle answer was `117`.
\--- Part Two ---
----------
The next year, just to show off, Santa decides to take the route with the *longest distance* instead.
He can still start and end at any two (different) locations he wants, and he still must visit each location exactly once.
For example, given the distances above, the longest route would be `982` via (for example) `Dublin -> London -> Belfast`.
What is the distance of the longest route?
Your puzzle answer was `909`.
Both parts of this puzzle are complete! They provide two gold stars: \*\*
At this point, all that is left is for you to [admire your Advent calendar](/2015).
If you still want to see it, you can [get your puzzle input](9/input).

View file

@ -0,0 +1,72 @@
use std::collections::{HashMap, HashSet};
pub fn run(input: &str) -> (usize, usize) {
let distances = get_distances(input);
let first = try_all(&distances, &{|a, b| b.cmp(a)});
let second = try_all(&distances, &{|a, b| a.cmp(b)});
(first, second)
}
fn get_distances(input: &str) -> HashMap<(u16, u16), usize> {
let mut cities = HashMap::new();
let mut map = HashMap::new();
input.lines().for_each(|line| {
let components: Vec<&str> = line.split(' ').collect();
assert_eq!(components.len(), 5);
let next = 2_u16.pow(cities.len() as u32);
let from = *cities.entry(components[0]).or_insert(next);
let next = 2_u16.pow(cities.len() as u32);
let to = *cities.entry(components[2]).or_insert(next);
let distance = components[4].parse().unwrap();
map.insert((from, to), distance);
map.insert((to, from), distance);
});
map
}
fn try_all<F>(distances: &HashMap<(u16, u16), usize>, comparison: &F) -> usize
where F: Fn(&usize, &usize) -> std::cmp::Ordering
{
let starting_points: HashSet<u16> = distances.keys().map(|(from, _)| *from).collect();
starting_points.iter()
.map(|&from| try_all_from(from, distances, from, comparison))
.max_by(comparison)
.unwrap()
}
fn try_all_from<F>(current: u16, distances: &HashMap<(u16, u16), usize>, visited: u16, comparison: &F) -> usize
where F: Fn(&usize, &usize) -> std::cmp::Ordering
{
distances.keys()
.filter(|(from, to)| *from == current && *to & visited == 0)
.map(|(_, to)| distances.get(&(current, *to)).unwrap() + try_all_from(*to, distances, visited | to, comparison))
.max_by(comparison)
.unwrap_or(0)
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::read_to_string;
fn read_file(name: &str) -> String {
read_to_string(name).expect(&format!("Unable to read file: {}", name)[..])
}
#[test]
fn test_sample() {
let sample_input = read_file("tests/sample_input");
assert_eq!(run(&sample_input), (605, 982));
}
#[test]
fn test_challenge() {
let challenge_input = read_file("tests/challenge_input");
assert_eq!(run(&challenge_input), (117, 909));
}
}

View file

@ -0,0 +1,28 @@
Faerun to Tristram = 65
Faerun to Tambi = 129
Faerun to Norrath = 144
Faerun to Snowdin = 71
Faerun to Straylight = 137
Faerun to AlphaCentauri = 3
Faerun to Arbre = 149
Tristram to Tambi = 63
Tristram to Norrath = 4
Tristram to Snowdin = 105
Tristram to Straylight = 125
Tristram to AlphaCentauri = 55
Tristram to Arbre = 14
Tambi to Norrath = 68
Tambi to Snowdin = 52
Tambi to Straylight = 65
Tambi to AlphaCentauri = 22
Tambi to Arbre = 143
Norrath to Snowdin = 8
Norrath to Straylight = 23
Norrath to AlphaCentauri = 136
Norrath to Arbre = 115
Snowdin to Straylight = 101
Snowdin to AlphaCentauri = 84
Snowdin to Arbre = 96
Straylight to AlphaCentauri = 107
Straylight to Arbre = 14
AlphaCentauri to Arbre = 46

View file

@ -0,0 +1,3 @@
London to Dublin = 464
London to Belfast = 518
Dublin to Belfast = 141

View file

@ -0,0 +1,8 @@
[package]
name = "day10-elves_look_elves_say"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

@ -0,0 +1,50 @@
pub fn run(input: &str, count: u8) -> String {
let mut look = String::from(input);
for _ in 0..count {
look = look_and_say(&look);
}
look
}
fn look_and_say(number: &str) -> String {
let mut say = String::new();
let mut last_digit = ' ';
let mut count = 0;
for digit in number.chars() {
if digit == last_digit {
count += 1;
} else {
say += &(count.to_string() + &last_digit.to_string());
count = 1;
last_digit = digit;
}
}
say += &(count.to_string() + &last_digit.to_string());
say[2..].to_string()
}
#[cfg(test)]
mod tests {
use super::*;
/*use std::fs::read_to_string;
fn read_file(name: &str) -> String {
read_to_string(name).expect(&format!("Unable to read file: {}", name)[..])
}*/
#[test]
fn test_sample() {
let sample_input = "1";
assert_eq!(run(sample_input, 5), "312211".to_string());
}
#[test]
fn test_challenge() {
let challenge_input = "1113122113";
let after_40 = run(challenge_input, 40);
assert_eq!(after_40.len(), 360154);
assert_eq!(run(&after_40, 10).len(), 5103798);
}
}

View file

@ -0,0 +1,8 @@
[package]
name = "day11-corporate_policy"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

@ -0,0 +1,39 @@
\--- Day 11: Corporate Policy ---
----------
Santa's previous password expired, and he needs help choosing a new one.
To help him remember his new password after the old one expires, Santa has devised a method of coming up with a password based on the previous one. Corporate policy dictates that passwords must be exactly eight lowercase letters (for security reasons), so he finds his new password by *incrementing* his old password string repeatedly until it is valid.
Incrementing is just like counting with numbers: `xx`, `xy`, `xz`, `ya`, `yb`, and so on. Increase the rightmost letter one step; if it was `z`, it wraps around to `a`, and repeat with the next letter to the left until one doesn't wrap around.
Unfortunately for Santa, a new Security-Elf recently started, and he has imposed some additional password requirements:
* Passwords must include one increasing straight of at least three letters, like `abc`, `bcd`, `cde`, and so on, up to `xyz`. They cannot skip letters; `abd` doesn't count.
* Passwords may not contain the letters `i`, `o`, or `l`, as these letters can be mistaken for other characters and are therefore confusing.
* Passwords must contain at least two different, non-overlapping pairs of letters, like `aa`, `bb`, or `zz`.
For example:
* `hijklmmn` meets the first requirement (because it contains the straight `hij`) but fails the second requirement requirement (because it contains `i` and `l`).
* `abbceffg` meets the third requirement (because it repeats `bb` and `ff`) but fails the first requirement.
* `abbcegjk` fails the third requirement, because it only has one double letter (`bb`).
* The next password after `abcdefgh` is `abcdffaa`.
* The next password after `ghijklmn` is `ghjaabcc`, because you eventually skip all the passwords that start with `ghi...`, since `i` is not allowed.
Given Santa's current password (your puzzle input), what should his *next password* be?
Your puzzle answer was `cqjxxyzz`.
\--- Part Two ---
----------
Santa's password expired again. What's the next one?
Your puzzle answer was `cqkaabcc`.
Both parts of this puzzle are complete! They provide two gold stars: \*\*
At this point, all that is left is for you to [admire your Advent calendar](/2015).
Your puzzle input was `cqjxjnds`.

View file

@ -0,0 +1,80 @@
pub fn run(input: &str) -> String {
let mut next_password = increment(input);
while !meets_requirements(&next_password) {
next_password = increment(&next_password);
}
next_password
}
fn to_number(password: &str) -> usize {
password.bytes().map(|b| (b - b'a') as usize).fold(0, |acc, b| 26*acc+b)
}
fn to_password(number: usize) -> String {
let mut password = String::new();
let mut number = number;
while number > 0 {
password += &char::from(b'a' + (number % 26) as u8).to_string();
number /= 26;
}
password += &("a".repeat(8-password.len()));
password.chars().rev().collect()
}
fn increment(password: &str) -> String {
to_password(to_number(password) + 1)
}
fn meets_requirements(password: &str) -> bool {
let mut includes_straight = false;
for idx in 0..password.bytes().len()-2 {
if *password.as_bytes().get(idx+2).unwrap() == password.as_bytes().get(idx).unwrap() + 2 &&
*password.as_bytes().get(idx+1).unwrap() == password.as_bytes().get(idx).unwrap() + 1 {
includes_straight = true;
}
}
let includes_confusing = password.chars().any(|c| ['i', 'o', 'l'].contains(&c));
let mut pairs = 0;
let mut iter = 0..password.chars().count()-1;
while let Some(idx) = iter.next() {
if password.chars().nth(idx+1) == password.chars().nth(idx) {
pairs += 1;
iter.next();
}
}
includes_straight && !includes_confusing && pairs > 1
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn requirements_tests() {
let samples = [ "hijklmmn", "abbceffg", "abbcegjk" ];
for s in samples {
assert_eq!(to_password(to_number(s)), s.to_string());
assert!(!meets_requirements(s));
}
}
#[test]
fn test_sample() {
let sample_input = ["abcdefgh", "ghjaaaaa" /*"ghijklmn"*/ ];
let expected = ["abcdffaa", "ghjaabcc"];
for (idx, s) in sample_input.iter().enumerate() {
assert_eq!(run(s), expected[idx].to_string());
}
}
#[test]
fn test_challenge() {
let challenge_input = "cqjxjnds";
let next_password = run(challenge_input);
assert_eq!(next_password, "cqjxxyzz".to_string());
assert_eq!(run(&next_password), "cqkaabcc".to_string());
}
}

View file

@ -0,0 +1,8 @@
[package]
name = "day12-jsabacusframework_io"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,39 @@
\--- Day 12: JSAbacusFramework.io ---
----------
Santa's Accounting-Elves need help balancing the books after a recent order. Unfortunately, their accounting software uses a peculiar storage format. That's where you come in.
They have a [JSON](http://json.org/) document which contains a variety of things: arrays (`[1,2,3]`), objects (`{"a":1, "b":2}`), numbers, and strings. Your first job is to simply find all of the *numbers* throughout the document and add them together.
For example:
* `[1,2,3]` and `{"a":2,"b":4}` both have a sum of `6`.
* `[[[3]]]` and `{"a":{"b":4},"c":-1}` both have a sum of `3`.
* `{"a":[-1,1]}` and `[-1,{"a":1}]` both have a sum of `0`.
* `[]` and `{}` both have a sum of `0`.
You will not encounter any strings containing numbers.
What is the *sum of all numbers* in the document?
Your puzzle answer was `119433`.
\--- Part Two ---
----------
Uh oh - the Accounting-Elves have realized that they double-counted everything *red*.
Ignore any object (and all of its children) which has any property with the value `"red"`. Do this only for objects (`{...}`), not arrays (`[...]`).
* `[1,2,3]` still has a sum of `6`.
* `[1,{"c":"red","b":2},3]` now has a sum of `4`, because the middle object is ignored.
* `{"d":"red","e":[1,2,3,4],"f":5}` now has a sum of `0`, because the entire structure is ignored.
* `[1,"red",5]` has a sum of `6`, because `"red"` in an array has no effect.
Your puzzle answer was `68466`.
Both parts of this puzzle are complete! They provide two gold stars: \*\*
At this point, all that is left is for you to [admire your Advent calendar](/2015).
If you still want to see it, you can [get your puzzle input](12/input).

View file

@ -0,0 +1,85 @@
pub fn run(input: &str) -> (i32, i32) {
let first = input.lines().map(sumup_numbers).sum();
let second = input.lines().map(|line| sumup_numbers(&filter_red(line))).sum();
(first, second)
}
fn sumup_numbers(line: &str) -> i32 {
let mut sum = 0;
let mut sign = 1_i32;
let mut this_number = 0_u32;
for c in line.chars() {
if c == '-' {
sign *= -1;
} else if let Some(d) = c.to_digit(10) {
this_number *= 10;
this_number += d;
} else {
sum += this_number as i32 * sign;
this_number = 0;
sign = 1
}
}
// dbg!(sum)
sum
}
fn filter_red(line: &str) -> String {
let left_square: Vec<_> = line.match_indices('[').map(|(idx, _)| idx).collect();
let right_square: Vec<_> = line.match_indices(']').map(|(idx, _)| idx).collect();
let left_curly: Vec<_> = line.match_indices('{').map(|(idx, _)| idx).collect();
let right_curly: Vec<_> = line.match_indices('}').map(|(idx, _)| idx).collect();
let reds: Vec<_> = line.match_indices("red").map(|(idx, _)| idx).collect();
let mut filtered = String::from(line);
for red in &reds {
let left_count = left_curly.partition_point(|lc| lc < red);
let right_count = right_curly.partition_point(|rc| rc < red);
let curly_level = left_count - right_count;
let start = *left_curly.iter().take(left_count).rev().find(|lc| left_curly.partition_point(|left| left <= lc) - right_curly.partition_point(|right| right <= lc) == curly_level).unwrap();
// skip reds that are in an array, unless they are part of an object inside the array
let left_square_count = left_square.partition_point(|ls| ls < red);
let square_level = left_square_count - right_square.partition_point(|rs| rs < red);
if square_level > 0 {
let opening_square = *left_square.iter().take(left_square_count).rev().find(|ls| left_square.partition_point(|left| left <= ls) - right_square.partition_point(|right| right <= ls) == square_level).unwrap();
if opening_square > start {
continue;
}
}
let end = *right_curly.iter()
.enumerate()
.skip(right_count)
.find(|(idx, end)| left_curly.partition_point(|lc| lc < end) - idx == curly_level)
.unwrap_or_else(|| panic!("Unable to find a right brace after {red} in {line}"))
.1 + 1;
filtered.replace_range(start..end, &"x".repeat(end-start));
}
filtered
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::read_to_string;
fn read_file(name: &str) -> String {
read_to_string(name).expect(&format!("Unable to read file: {}", name)[..])
}
#[test]
fn test_sample() {
let sample_input = read_file("tests/sample_input");
assert_eq!(run(&sample_input), (39, 22));
}
#[test]
fn test_challenge() {
let challenge_input = read_file("tests/challenge_input");
assert_eq!(run(&challenge_input), (119433, 68466));
}
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,10 @@
[1,2,3]
[1,{"c":"red","b":2},3]
[[[3]]]
{"a":{"b":4},"c":-1}
{"a":[-1,1]}
[-1,{"a":1}]
[]
{}
{"d":"red","e":[1,2,3,4],"f":5}
{[1,"red",5]}

View file

@ -0,0 +1,8 @@
[package]
name = "day13-knights_of_the_dinner_table"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

@ -0,0 +1,60 @@
\--- Day 13: Knights of the Dinner Table ---
----------
In years past, the holiday feast with your family hasn't gone so well. Not everyone gets along! This year, you resolve, will be different. You're going to find the *optimal seating arrangement* and avoid all those awkward conversations.
You start by writing up a list of everyone invited and the amount their happiness would increase or decrease if they were to find themselves sitting next to each other person. You have a circular table that will be just big enough to fit everyone comfortably, and so each person will have exactly two neighbors.
For example, suppose you have only four attendees planned, and you calculate their potential happiness as follows:
```
Alice would gain 54 happiness units by sitting next to Bob.
Alice would lose 79 happiness units by sitting next to Carol.
Alice would lose 2 happiness units by sitting next to David.
Bob would gain 83 happiness units by sitting next to Alice.
Bob would lose 7 happiness units by sitting next to Carol.
Bob would lose 63 happiness units by sitting next to David.
Carol would lose 62 happiness units by sitting next to Alice.
Carol would gain 60 happiness units by sitting next to Bob.
Carol would gain 55 happiness units by sitting next to David.
David would gain 46 happiness units by sitting next to Alice.
David would lose 7 happiness units by sitting next to Bob.
David would gain 41 happiness units by sitting next to Carol.
```
Then, if you seat Alice next to David, Alice would lose `2` happiness units (because David talks so much), but David would gain `46` happiness units (because Alice is such a good listener), for a total change of `44`.
If you continue around the table, you could then seat Bob next to Alice (Bob gains `83`, Alice gains `54`). Finally, seat Carol, who sits next to Bob (Carol gains `60`, Bob loses `7`) and David (Carol gains `55`, David gains `41`). The arrangement looks like this:
```
+41 +46
+55 David -2
Carol Alice
+60 Bob +54
-7 +83
```
After trying every other seating arrangement in this hypothetical scenario, you find that this one is the most optimal, with a total change in happiness of `330`.
What is the *total change in happiness* for the optimal seating arrangement of the actual guest list?
Your puzzle answer was `618`.
\--- Part Two ---
----------
In all the commotion, you realize that you forgot to seat yourself. At this point, you're pretty apathetic toward the whole thing, and your happiness wouldn't really go up or down regardless of who you sit next to. You assume everyone else would be just as ambivalent about sitting next to you, too.
So, add yourself to the list, and give all happiness relationships that involve you a score of `0`.
What is the *total change in happiness* for the optimal seating arrangement that actually includes yourself?
Your puzzle answer was `601`.
Both parts of this puzzle are complete! They provide two gold stars: \*\*
At this point, all that is left is for you to [admire your Advent calendar](/2015).
If you still want to see it, you can [get your puzzle input](13/input).

View file

@ -0,0 +1,88 @@
use std::collections::HashMap;
pub fn run(input: &str) -> (isize, isize) {
let mut happiness_table = get_happiness_table(input);
let first = get_max_happiness(&happiness_table);
append_ambivalent(&mut happiness_table);
let second = get_max_happiness(&happiness_table);
(first, second)
}
fn append_ambivalent(table: &mut HashMap<(u16, u16), isize>) {
let new = table.keys().map(|k| k.0).max().unwrap() * 2;
let mut this = 1;
while this < new {
table.insert((this, new), 0);
table.insert((new, this), 0);
this *= 2;
}
}
fn get_max_happiness(table: &HashMap<(u16, u16), isize>) -> isize {
// since the table is round, the first placement ist arbitrary. Place attendee 1 there, since
// they are guaranteed to exist.
let current = 1;
try_all(table, current, current)
}
fn try_all(table: &HashMap<(u16, u16), isize>, current: u16, seated: u16) -> isize {
let to_place: Vec<_> = table.keys().filter(|(s, o)| *s == current && *o & seated == 0).map(|(_s, o)| *o).collect();
if to_place.len() > 1 {
to_place.iter()
.map(|next| table.get(&(current, *next)).unwrap() +
table.get(&(*next, current)).unwrap() +
try_all(table, *next, seated | *next))
.max()
.unwrap()
} else {
let next = to_place[0];
table.get(&(current, next)).unwrap() +
table.get(&(next, current)).unwrap() +
table.get(&(next, 1)).unwrap() +
table.get(&(1, next)).unwrap()
}
}
fn get_happiness_table(input: &str) -> HashMap<(u16, u16), isize> {
let mut attendees = HashMap::new();
let mut table = HashMap::new();
for line in input.lines() {
let components: Vec<_> = line.split(' ').collect();
assert_eq!(components.len(), 11);
let next = 2_u16.pow(attendees.len() as u32);
let subject = *attendees.entry(components[0]).or_insert(next);
let next = 2_u16.pow(attendees.len() as u32);
let object = *attendees.entry(&components[10][..components[10].len()-1]).or_insert(next);
let sign = match components[2] {
"gain" => 1,
"lose" => -1,
_ => panic!("unexpected token {} in line {}", components[2], input),
};
let amount: isize = components[3].parse().unwrap();
table.insert((subject, object), sign*amount);
}
table
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::read_to_string;
fn read_file(name: &str) -> String {
read_to_string(name).expect(&format!("Unable to read file: {}", name)[..])
}
#[test]
fn test_sample() {
let sample_input = read_file("tests/sample_input");
assert_eq!(run(&sample_input), (330, 286));
}
#[test]
fn test_challenge() {
let challenge_input = read_file("tests/challenge_input");
assert_eq!(run(&challenge_input), (618, 601));
}
}

View file

@ -0,0 +1,56 @@
Alice would lose 57 happiness units by sitting next to Bob.
Alice would lose 62 happiness units by sitting next to Carol.
Alice would lose 75 happiness units by sitting next to David.
Alice would gain 71 happiness units by sitting next to Eric.
Alice would lose 22 happiness units by sitting next to Frank.
Alice would lose 23 happiness units by sitting next to George.
Alice would lose 76 happiness units by sitting next to Mallory.
Bob would lose 14 happiness units by sitting next to Alice.
Bob would gain 48 happiness units by sitting next to Carol.
Bob would gain 89 happiness units by sitting next to David.
Bob would gain 86 happiness units by sitting next to Eric.
Bob would lose 2 happiness units by sitting next to Frank.
Bob would gain 27 happiness units by sitting next to George.
Bob would gain 19 happiness units by sitting next to Mallory.
Carol would gain 37 happiness units by sitting next to Alice.
Carol would gain 45 happiness units by sitting next to Bob.
Carol would gain 24 happiness units by sitting next to David.
Carol would gain 5 happiness units by sitting next to Eric.
Carol would lose 68 happiness units by sitting next to Frank.
Carol would lose 25 happiness units by sitting next to George.
Carol would gain 30 happiness units by sitting next to Mallory.
David would lose 51 happiness units by sitting next to Alice.
David would gain 34 happiness units by sitting next to Bob.
David would gain 99 happiness units by sitting next to Carol.
David would gain 91 happiness units by sitting next to Eric.
David would lose 38 happiness units by sitting next to Frank.
David would gain 60 happiness units by sitting next to George.
David would lose 63 happiness units by sitting next to Mallory.
Eric would gain 23 happiness units by sitting next to Alice.
Eric would lose 69 happiness units by sitting next to Bob.
Eric would lose 33 happiness units by sitting next to Carol.
Eric would lose 47 happiness units by sitting next to David.
Eric would gain 75 happiness units by sitting next to Frank.
Eric would gain 82 happiness units by sitting next to George.
Eric would gain 13 happiness units by sitting next to Mallory.
Frank would gain 77 happiness units by sitting next to Alice.
Frank would gain 27 happiness units by sitting next to Bob.
Frank would lose 87 happiness units by sitting next to Carol.
Frank would gain 74 happiness units by sitting next to David.
Frank would lose 41 happiness units by sitting next to Eric.
Frank would lose 99 happiness units by sitting next to George.
Frank would gain 26 happiness units by sitting next to Mallory.
George would lose 63 happiness units by sitting next to Alice.
George would lose 51 happiness units by sitting next to Bob.
George would lose 60 happiness units by sitting next to Carol.
George would gain 30 happiness units by sitting next to David.
George would lose 100 happiness units by sitting next to Eric.
George would lose 63 happiness units by sitting next to Frank.
George would gain 57 happiness units by sitting next to Mallory.
Mallory would lose 71 happiness units by sitting next to Alice.
Mallory would lose 28 happiness units by sitting next to Bob.
Mallory would lose 10 happiness units by sitting next to Carol.
Mallory would gain 44 happiness units by sitting next to David.
Mallory would gain 22 happiness units by sitting next to Eric.
Mallory would gain 79 happiness units by sitting next to Frank.
Mallory would lose 16 happiness units by sitting next to George.

View file

@ -0,0 +1,12 @@
Alice would gain 54 happiness units by sitting next to Bob.
Alice would lose 79 happiness units by sitting next to Carol.
Alice would lose 2 happiness units by sitting next to David.
Bob would gain 83 happiness units by sitting next to Alice.
Bob would lose 7 happiness units by sitting next to Carol.
Bob would lose 63 happiness units by sitting next to David.
Carol would lose 62 happiness units by sitting next to Alice.
Carol would gain 60 happiness units by sitting next to Bob.
Carol would gain 55 happiness units by sitting next to David.
David would gain 46 happiness units by sitting next to Alice.
David would lose 7 happiness units by sitting next to Bob.
David would gain 41 happiness units by sitting next to Carol.

View file

@ -0,0 +1,8 @@
[package]
name = "day14-reindeer_olympics"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

@ -0,0 +1,40 @@
\--- Day 14: Reindeer Olympics ---
----------
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*?
Your puzzle answer was `2660`.
\--- Part Two ---
----------
Seeing how reindeer move in bursts, Santa decides he's not pleased with the old scoring system.
Instead, at the end of each second, he awards one point to the reindeer currently in the lead. (If there are multiple reindeer tied for the lead, they each get one point.) He keeps the traditional 2503 second time limit, of course, as doing otherwise would be entirely ridiculous.
Given the example reindeer from above, after the first second, Dancer is in the lead and gets one point. He stays in the lead until several seconds into Comet's second burst: after the 140th second, Comet pulls into the lead and gets his first point. Of course, since Dancer had been in the lead for the 139 seconds before that, he has accumulated 139 points by the 140th second.
After the 1000th second, Dancer has accumulated *`689`* points, while poor Comet, our old champion, only has `312`. So, with the new scoring system, Dancer would win (if the race ended at 1000 seconds).
Again given the descriptions of each reindeer (in your puzzle input), after exactly `2503` seconds, *how many points does the winning reindeer have*?
Your puzzle answer was `1256`.
Both parts of this puzzle are complete! They provide two gold stars: \*\*
At this point, all that is left is for you to [admire your Advent calendar](/2015).
If you still want to see it, you can [get your puzzle input](14/input).

View file

@ -0,0 +1,49 @@
pub fn run(input: &str, finish_time: usize) -> (usize, usize) {
let reindeers: Vec<_> = input.lines().map(get_speeds).collect();
let first = reindeers.iter().map(|r| distance_at(*r, finish_time)).max().unwrap();
let mut points = vec![0; reindeers.len()];
for t in 1..=finish_time {
let max = reindeers.iter().map(|r| distance_at(*r, t)).max().unwrap();
reindeers.iter().enumerate().filter(|&(_idx, r)| distance_at(*r, t) == max).for_each(|(idx, _r)| points[idx] += 1);
}
let second = *points.iter().max().unwrap();
(first, second)
}
fn distance_at((speed, travel_time, rest_time): (usize, usize, usize), finish_time: usize) -> usize {
let full_sorties = finish_time / (travel_time + rest_time);
let last_partial = finish_time % (travel_time + rest_time);
full_sorties * travel_time * speed + last_partial.min(travel_time) * speed
}
fn get_speeds(line: &str) -> (usize, usize, usize) {
let components: Vec<_> = line.split(' ').collect();
assert_eq!(components.len(), 15);
(
components[3].parse().unwrap(),
components[6].parse().unwrap(),
components[13].parse().unwrap(),
)
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::read_to_string;
fn read_file(name: &str) -> String {
read_to_string(name).expect(&format!("Unable to read file: {}", name)[..])
}
#[test]
fn test_sample() {
let sample_input = read_file("tests/sample_input");
assert_eq!(run(&sample_input, 1000), (1120, 689));
}
#[test]
fn test_challenge() {
let challenge_input = read_file("tests/challenge_input");
assert_eq!(run(&challenge_input, 2503), (2660, 1256));
}
}

View file

@ -0,0 +1,9 @@
Vixen can fly 19 km/s for 7 seconds, but then must rest for 124 seconds.
Rudolph can fly 3 km/s for 15 seconds, but then must rest for 28 seconds.
Donner can fly 19 km/s for 9 seconds, but then must rest for 164 seconds.
Blitzen can fly 19 km/s for 9 seconds, but then must rest for 158 seconds.
Comet can fly 13 km/s for 7 seconds, but then must rest for 82 seconds.
Cupid can fly 25 km/s for 6 seconds, but then must rest for 145 seconds.
Dasher can fly 14 km/s for 3 seconds, but then must rest for 38 seconds.
Dancer can fly 3 km/s for 16 seconds, but then must rest for 37 seconds.
Prancer can fly 25 km/s for 6 seconds, but then must rest for 143 seconds.

View file

@ -0,0 +1,2 @@
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.

View file

@ -0,0 +1,8 @@
[package]
name = "day15-science_for_hungry_people"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

@ -0,0 +1,52 @@
\--- Day 15: Science for Hungry People ---
----------
Today, you set out on the task of perfecting your milk-dunking cookie recipe. All you have to do is find the right balance of ingredients.
Your recipe leaves room for exactly `100` teaspoons of ingredients. You make a list of the *remaining ingredients you could use to finish the recipe* (your puzzle input) and their *properties per teaspoon*:
* `capacity` (how well it helps the cookie absorb milk)
* `durability` (how well it keeps the cookie intact when full of milk)
* `flavor` (how tasty it makes the cookie)
* `texture` (how it improves the feel of the cookie)
* `calories` (how many calories it adds to the cookie)
You can only measure ingredients in whole-teaspoon amounts accurately, and you have to be accurate so you can reproduce your results in the future. The *total score* of a cookie can be found by adding up each of the properties (negative totals become `0`) and then multiplying together everything except calories.
For instance, suppose you have these two ingredients:
```
Butterscotch: capacity -1, durability -2, flavor 6, texture 3, calories 8
Cinnamon: capacity 2, durability 3, flavor -2, texture -1, calories 3
```
Then, choosing to use `44` teaspoons of butterscotch and `56` teaspoons of cinnamon (because the amounts of each ingredient must add up to `100`) would result in a cookie with the following properties:
* A `capacity` of `44*-1 + 56*2 = 68`
* A `durability` of `44*-2 + 56*3 = 80`
* A `flavor` of `44*6 + 56*-2 = 152`
* A `texture` of `44*3 + 56*-1 = 76`
Multiplying these together (`68 * 80 * 152 * 76`, ignoring `calories` for now) results in a total score of `62842880`, which happens to be the best score possible given these ingredients. If any properties had produced a negative total, it would have instead become zero, causing the whole score to multiply to zero.
Given the ingredients in your kitchen and their properties, what is the *total score* of the highest-scoring cookie you can make?
Your puzzle answer was `222870`.
\--- Part Two ---
----------
Your cookie recipe becomes wildly popular! Someone asks if you can make another recipe that has exactly `500` calories per cookie (so they can use it as a meal replacement). Keep the rest of your award-winning process the same (100 teaspoons, same ingredients, same scoring system).
For example, given the ingredients above, if you had instead selected `40` teaspoons of butterscotch and `60` teaspoons of cinnamon (which still adds to `100`), the total calorie count would be `40*8 + 60*3 = 500`. The total score would go down, though: only `57600000`, the best you can do in such trying circumstances.
Given the ingredients in your kitchen and their properties, what is the *total score* of the highest-scoring cookie you can make with a calorie total of `500`?
Your puzzle answer was `117936`.
Both parts of this puzzle are complete! They provide two gold stars: \*\*
At this point, all that is left is for you to [admire your Advent calendar](/2015).
If you still want to see it, you can [get your puzzle input](15/input).

View file

@ -0,0 +1,95 @@
struct Ingredient {
capacity: isize,
durability: isize,
flavour: isize,
texture: isize,
calories: usize,
}
impl Ingredient {
fn parse(line: &str) -> Self {
let components: Vec<_> = line.split(' ').collect();
assert_eq!(components.len(), 11);
Self {
capacity: strip_last_char(components[2]).parse().unwrap(),
durability: strip_last_char(components[4]).parse().unwrap(),
flavour: strip_last_char(components[6]).parse().unwrap(),
texture: strip_last_char(components[8]).parse().unwrap(),
calories: components[10].parse().unwrap(),
}
}
}
fn strip_last_char(string: &str) -> &str {
&string[..string.len()-1]
}
pub fn run(input: &str) -> (usize, usize) {
let ingredients: Vec<_> = input.lines().map(Ingredient::parse).collect();
let first = try_combinations(&ingredients, None);
let second = try_combinations(&ingredients, Some(500));
(first, second)
}
fn try_combinations(ingredients: &Vec<Ingredient>, cal_requirement: Option<usize>) -> usize {
let ingredient_count = ingredients.len();
let amounts = vec![0; ingredient_count];
stars_and_bars(100, ingredient_count, &amounts, ingredients, cal_requirement)
}
fn stars_and_bars(stars: u8, bars: usize, amounts: &[u8], ingredients: &[Ingredient], cal_requirement: Option<usize>) -> usize {
match bars {
0 => get_score(amounts, ingredients, cal_requirement),
1 => {
let mut new_amounts = amounts.to_vec();
new_amounts[0] = stars;
stars_and_bars(0, 0, &new_amounts, ingredients, cal_requirement)
},
_ => {
(0..=stars).map(|i| {
let mut new_amounts = amounts.to_vec();
new_amounts[bars-1] = i;
stars_and_bars(stars-i, bars-1, &new_amounts, ingredients, cal_requirement)
}).max().unwrap_or(0)
},
}
}
fn get_score(amounts: &[u8], ingredients: &[Ingredient], cal_requirement: Option<usize>) -> usize {
let calories = amounts.iter().enumerate().map(|(idx, &a)| a as usize * ingredients.get(idx).unwrap().calories).sum::<usize>();
if cal_requirement.is_some() && Some(calories) != cal_requirement {
return 0;
}
let capacity = amounts.iter().enumerate().map(|(idx, &a)| a as isize * ingredients.get(idx).unwrap().capacity).sum::<isize>().max(0);
let durability = amounts.iter().enumerate().map(|(idx, &a)| a as isize * ingredients.get(idx).unwrap().durability).sum::<isize>().max(0);
let flavour = amounts.iter().enumerate().map(|(idx, &a)| a as isize * ingredients.get(idx).unwrap().flavour).sum::<isize>().max(0);
let texture = amounts.iter().enumerate().map(|(idx, &a)| a as isize * ingredients.get(idx).unwrap().texture).sum::<isize>().max(0);
(capacity * durability * texture * flavour) as usize
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::read_to_string;
fn read_file(name: &str) -> String {
read_to_string(name).expect(&format!("Unable to read file: {}", name)[..])
}
#[test]
fn test_sample() {
let sample_input = read_file("tests/sample_input");
assert_eq!(run(&sample_input), (62842880, 57600000));
}
#[test]
fn test_challenge() {
let challenge_input = read_file("tests/challenge_input");
assert_eq!(run(&challenge_input), (222870, 117936));
}
}

View file

@ -0,0 +1,4 @@
Sugar: capacity 3, durability 0, flavor 0, texture -3, calories 2
Sprinkles: capacity -3, durability 3, flavor 0, texture 0, calories 9
Candy: capacity -1, durability 0, flavor 4, texture 0, calories 1
Chocolate: capacity 0, durability 0, flavor -2, texture 2, calories 8

View file

@ -0,0 +1,2 @@
Butterscotch: capacity -1, durability -2, flavor 6, texture 3, calories 8
Cinnamon: capacity 2, durability 3, flavor -2, texture -1, calories 3

View file

@ -0,0 +1,8 @@
[package]
name = "day16-aunt_sue"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

@ -0,0 +1,57 @@
\--- Day 16: Aunt Sue ---
----------
Your Aunt Sue has given you a wonderful gift, and you'd like to send her a thank you card. However, there's a small problem: she signed it "From, Aunt Sue".
You have 500 Aunts named "Sue".
So, to avoid sending the card to the wrong person, you need to figure out which Aunt Sue (which you conveniently number 1 to 500, for sanity) gave you the gift. You open the present and, as luck would have it, good ol' Aunt Sue got you a My First Crime Scene Analysis Machine! Just what you wanted. Or needed, as the case may be.
The My First Crime Scene Analysis Machine (MFCSAM for short) can detect a few specific compounds in a given sample, as well as how many distinct kinds of those compounds there are. According to the instructions, these are what the MFCSAM can detect:
* `children`, by human DNA age analysis.
* `cats`. It doesn't differentiate individual breeds.
* Several seemingly random breeds of dog: `[samoyeds](https://en.wikipedia.org/wiki/Samoyed_%28dog%29)`, `[pomeranians](https://en.wikipedia.org/wiki/Pomeranian_%28dog%29)`, `[akitas](https://en.wikipedia.org/wiki/Akita_%28dog%29)`, and `[vizslas](https://en.wikipedia.org/wiki/Vizsla)`.
* `goldfish`. No other kinds of fish.
* `trees`, all in one group.
* `cars`, presumably by exhaust or gasoline or something.
* `perfumes`, which is handy, since many of your Aunts Sue wear a few kinds.
In fact, many of your Aunts Sue have many of these. You put the wrapping from the gift into the MFCSAM. It beeps inquisitively at you a few times and then prints out a message on [ticker tape](https://en.wikipedia.org/wiki/Ticker_tape):
```
children: 3
cats: 7
samoyeds: 2
pomeranians: 3
akitas: 0
vizslas: 0
goldfish: 5
trees: 3
cars: 2
perfumes: 1
```
You make a list of the things you can remember about each Aunt Sue. Things missing from your list aren't zero - you simply don't remember the value.
What is the *number* of the Sue that got you the gift?
Your puzzle answer was `103`.
\--- Part Two ---
----------
As you're about to send the thank you note, something in the MFCSAM's instructions catches your eye. Apparently, it has an outdated [retroencabulator](https://www.youtube.com/watch?v=RXJKdh1KZ0w), and so the output from the machine isn't exact values - some of them indicate ranges.
In particular, the `cats` and `trees` readings indicates that there are *greater than* that many (due to the unpredictable nuclear decay of cat dander and tree pollen), while the `pomeranians` and `goldfish` readings indicate that there are *fewer than* that many (due to the modial interaction of magnetoreluctance).
What is the *number* of the real Aunt Sue?
Your puzzle answer was `405`.
Both parts of this puzzle are complete! They provide two gold stars: \*\*
At this point, all that is left is for you to [admire your Advent calendar](/2015).
If you still want to see it, you can [get your puzzle input](16/input).

View file

@ -0,0 +1,121 @@
#[derive(Debug)]
struct Aunt {
children: Option<u8>,
cats: Option<u8>,
samoyeds: Option<u8>,
pomeranians: Option<u8>,
akitas: Option<u8>,
vizslas: Option<u8>,
goldfish: Option<u8>,
trees: Option<u8>,
cars: Option<u8>,
perfumes: Option<u8>,
}
impl Aunt{
fn new(line: &str) -> Self {
let components: Vec<_> = line.split(' ').collect();
assert_eq!(components.len(), 8);
let (mut children, mut cats, mut samoyeds, mut pomeranians, mut akitas,
mut vizslas, mut goldfish, mut trees, mut cars, mut perfumes) = (None, None, None, None, None, None, None, None, None, None);
for i in 0..2 {
match components[2*i+2] {
"children:" => children = Some(strip_last_char(components[2*i+3]).parse().unwrap()),
"cats:" => cats = Some(strip_last_char(components[2*i+3]).parse().unwrap()),
"samoyeds:" => samoyeds = Some(strip_last_char(components[2*i+3]).parse().unwrap()),
"pomeranians:" => pomeranians = Some(strip_last_char(components[2*i+3]).parse().unwrap()),
"akitas:" => akitas = Some(strip_last_char(components[2*i+3]).parse().unwrap()),
"vizslas:" => vizslas = Some(strip_last_char(components[2*i+3]).parse().unwrap()),
"goldfish:" => goldfish = Some(strip_last_char(components[2*i+3]).parse().unwrap()),
"trees:" => trees = Some(strip_last_char(components[2*i+3]).parse().unwrap()),
"cars:" => cars = Some(strip_last_char(components[2*i+3]).parse().unwrap()),
"perfumes:" => perfumes = Some(strip_last_char(components[2*i+3]).parse().unwrap()),
_ => panic!("Unknown component: {}", components[2*i+2]),
}
}
match components[6] {
"children:" => children = Some(components[7].parse().unwrap()),
"cats:" => cats = Some(components[7].parse().unwrap()),
"samoyeds:" => samoyeds = Some(components[7].parse().unwrap()),
"pomeranians:" => pomeranians = Some(components[7].parse().unwrap()),
"akitas:" => akitas = Some(components[7].parse().unwrap()),
"vizslas:" => vizslas = Some(components[7].parse().unwrap()),
"goldfish:" => goldfish = Some(components[7].parse().unwrap()),
"trees:" => trees = Some(components[7].parse().unwrap()),
"cars:" => cars = Some(components[7].parse().unwrap()),
"perfumes:" => perfumes = Some(components[7].parse().unwrap()),
_ => panic!("Unknown component: {}", components[6]),
}
Self {
children,
cats,
samoyeds,
pomeranians,
akitas,
vizslas,
goldfish,
trees,
cars,
perfumes,
}
}
}
pub fn run(input: &str) -> (usize, usize) {
let detected = Aunt {
children: Some(3),
cats: Some(7),
samoyeds: Some(2),
pomeranians: Some(3),
akitas: Some(0),
vizslas: Some(0),
goldfish: Some(5),
trees: Some(3),
cars: Some(2),
perfumes: Some(1)
};
let first = input.lines().map(Aunt::new).position(|a|
(a.children.is_none() || a.children == detected.children) &&
(a.cats.is_none() || a.cats == detected.cats) &&
(a.samoyeds.is_none() || a.samoyeds == detected.samoyeds) &&
(a.pomeranians.is_none() || a.pomeranians == detected.pomeranians) &&
(a.akitas.is_none() || a.akitas == detected.akitas) &&
(a.vizslas.is_none() || a.vizslas == detected.vizslas) &&
(a.goldfish.is_none() || a.goldfish == detected.goldfish) &&
(a.trees.is_none() || a.trees == detected.trees) &&
(a.cars.is_none() || a.cars == detected.cars) &&
(a.perfumes.is_none() || a.perfumes == detected.perfumes) ).unwrap() + 1;
let second = input.lines().map(Aunt::new).position(|a|
(a.children.is_none() || a.children == detected.children) &&
(a.cats.is_none() || a.cats > detected.cats) &&
(a.samoyeds.is_none() || a.samoyeds == detected.samoyeds) &&
(a.pomeranians.is_none() || a.pomeranians < detected.pomeranians) &&
(a.akitas.is_none() || a.akitas == detected.akitas) &&
(a.vizslas.is_none() || a.vizslas == detected.vizslas) &&
(a.goldfish.is_none() || a.goldfish < detected.goldfish) &&
(a.trees.is_none() || a.trees > detected.trees) &&
(a.cars.is_none() || a.cars == detected.cars) &&
(a.perfumes.is_none() || a.perfumes == detected.perfumes) ).unwrap() + 1;
(first, second)
}
fn strip_last_char(string: &str) -> &str {
&string[..string.len()-1]
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::read_to_string;
fn read_file(name: &str) -> String {
read_to_string(name).expect(&format!("Unable to read file: {}", name)[..])
}
#[test]
fn test_challenge() {
let challenge_input = read_file("tests/challenge_input");
assert_eq!(run(&challenge_input), (103, 405));
}
}

View file

@ -0,0 +1,500 @@
Sue 1: goldfish: 6, trees: 9, akitas: 0
Sue 2: goldfish: 7, trees: 1, akitas: 0
Sue 3: cars: 10, akitas: 6, perfumes: 7
Sue 4: perfumes: 2, vizslas: 0, cars: 6
Sue 5: goldfish: 1, trees: 3, perfumes: 10
Sue 6: children: 9, vizslas: 7, cars: 9
Sue 7: cars: 6, vizslas: 5, cats: 3
Sue 8: akitas: 10, vizslas: 9, children: 3
Sue 9: vizslas: 8, cats: 2, trees: 1
Sue 10: perfumes: 10, trees: 6, cars: 4
Sue 11: cars: 9, children: 1, cats: 1
Sue 12: pomeranians: 4, akitas: 6, goldfish: 8
Sue 13: cats: 10, children: 5, trees: 9
Sue 14: perfumes: 8, vizslas: 3, samoyeds: 1
Sue 15: vizslas: 2, perfumes: 8, trees: 3
Sue 16: pomeranians: 10, trees: 9, samoyeds: 4
Sue 17: akitas: 7, vizslas: 0, goldfish: 6
Sue 18: trees: 5, vizslas: 9, cars: 0
Sue 19: akitas: 3, goldfish: 9, trees: 10
Sue 20: perfumes: 7, samoyeds: 3, vizslas: 10
Sue 21: perfumes: 7, pomeranians: 10, akitas: 8
Sue 22: vizslas: 6, trees: 8, akitas: 10
Sue 23: goldfish: 0, trees: 4, children: 9
Sue 24: goldfish: 7, pomeranians: 9, akitas: 4
Sue 25: cars: 7, trees: 4, pomeranians: 4
Sue 26: trees: 9, akitas: 9, pomeranians: 7
Sue 27: samoyeds: 0, perfumes: 9, goldfish: 10
Sue 28: cars: 5, trees: 7, vizslas: 1
Sue 29: perfumes: 9, trees: 1, children: 6
Sue 30: goldfish: 10, trees: 0, cars: 4
Sue 31: akitas: 2, perfumes: 5, goldfish: 5
Sue 32: goldfish: 0, akitas: 5, trees: 0
Sue 33: vizslas: 2, akitas: 2, samoyeds: 3
Sue 34: goldfish: 8, perfumes: 5, cars: 3
Sue 35: akitas: 1, cats: 4, trees: 9
Sue 36: cars: 4, vizslas: 4, goldfish: 7
Sue 37: akitas: 5, perfumes: 7, trees: 3
Sue 38: goldfish: 10, trees: 2, vizslas: 9
Sue 39: goldfish: 4, pomeranians: 5, vizslas: 5
Sue 40: perfumes: 5, samoyeds: 4, akitas: 6
Sue 41: goldfish: 9, cars: 4, perfumes: 5
Sue 42: trees: 6, pomeranians: 9, goldfish: 8
Sue 43: perfumes: 7, pomeranians: 1, akitas: 2
Sue 44: vizslas: 9, cars: 5, cats: 0
Sue 45: akitas: 1, goldfish: 6, trees: 0
Sue 46: akitas: 5, vizslas: 8, trees: 2
Sue 47: trees: 9, akitas: 2, vizslas: 9
Sue 48: goldfish: 10, trees: 5, akitas: 2
Sue 49: cars: 7, vizslas: 2, perfumes: 6
Sue 50: akitas: 5, goldfish: 6, perfumes: 0
Sue 51: cars: 9, cats: 7, trees: 5
Sue 52: akitas: 7, goldfish: 10, cars: 0
Sue 53: cars: 10, cats: 4, perfumes: 2
Sue 54: goldfish: 2, pomeranians: 5, perfumes: 10
Sue 55: vizslas: 5, akitas: 4, cars: 8
Sue 56: goldfish: 9, vizslas: 4, akitas: 5
Sue 57: perfumes: 8, samoyeds: 7, cars: 9
Sue 58: cars: 5, akitas: 7, perfumes: 8
Sue 59: samoyeds: 8, cars: 10, vizslas: 10
Sue 60: akitas: 6, samoyeds: 0, goldfish: 3
Sue 61: trees: 8, pomeranians: 0, akitas: 2
Sue 62: trees: 1, perfumes: 3, vizslas: 4
Sue 63: vizslas: 6, samoyeds: 9, goldfish: 8
Sue 64: goldfish: 7, trees: 6, vizslas: 3
Sue 65: cars: 1, vizslas: 0, akitas: 6
Sue 66: cats: 6, pomeranians: 4, cars: 9
Sue 67: trees: 10, pomeranians: 7, samoyeds: 3
Sue 68: pomeranians: 5, goldfish: 9, akitas: 1
Sue 69: akitas: 1, vizslas: 0, trees: 9
Sue 70: cats: 4, goldfish: 4, vizslas: 10
Sue 71: vizslas: 7, perfumes: 7, trees: 8
Sue 72: children: 2, vizslas: 9, cats: 3
Sue 73: cars: 8, pomeranians: 0, perfumes: 6
Sue 74: akitas: 1, pomeranians: 8, vizslas: 10
Sue 75: vizslas: 5, perfumes: 5, cars: 7
Sue 76: cars: 3, vizslas: 3, goldfish: 0
Sue 77: akitas: 9, samoyeds: 1, pomeranians: 3
Sue 78: trees: 0, vizslas: 0, akitas: 6
Sue 79: pomeranians: 9, cars: 1, perfumes: 0
Sue 80: perfumes: 10, trees: 1, cats: 0
Sue 81: goldfish: 5, akitas: 9, trees: 0
Sue 82: vizslas: 1, akitas: 6, children: 4
Sue 83: samoyeds: 7, perfumes: 8, pomeranians: 4
Sue 84: perfumes: 3, children: 3, cats: 7
Sue 85: goldfish: 9, trees: 3, cars: 9
Sue 86: cars: 0, perfumes: 9, vizslas: 0
Sue 87: children: 3, trees: 4, akitas: 3
Sue 88: trees: 1, samoyeds: 1, goldfish: 0
Sue 89: akitas: 8, cars: 3, vizslas: 9
Sue 90: pomeranians: 9, trees: 9, goldfish: 8
Sue 91: goldfish: 7, trees: 10, children: 0
Sue 92: cats: 9, cars: 7, perfumes: 7
Sue 93: vizslas: 2, goldfish: 7, cats: 9
Sue 94: akitas: 5, cars: 8, vizslas: 4
Sue 95: goldfish: 7, vizslas: 1, perfumes: 2
Sue 96: goldfish: 5, trees: 6, perfumes: 10
Sue 97: trees: 0, perfumes: 7, cars: 0
Sue 98: cars: 2, perfumes: 6, trees: 8
Sue 99: trees: 10, children: 7, cats: 9
Sue 100: samoyeds: 5, goldfish: 6, vizslas: 6
Sue 101: cars: 10, perfumes: 9, vizslas: 3
Sue 102: pomeranians: 6, trees: 1, samoyeds: 4
Sue 103: cars: 2, perfumes: 1, goldfish: 5
Sue 104: goldfish: 2, cars: 8, pomeranians: 2
Sue 105: goldfish: 6, vizslas: 0, trees: 10
Sue 106: trees: 10, akitas: 10, pomeranians: 0
Sue 107: vizslas: 2, pomeranians: 10, trees: 3
Sue 108: children: 3, vizslas: 8, akitas: 7
Sue 109: perfumes: 2, akitas: 2, samoyeds: 3
Sue 110: goldfish: 7, trees: 1, perfumes: 1
Sue 111: akitas: 2, cars: 9, perfumes: 2
Sue 112: children: 10, cars: 0, akitas: 3
Sue 113: akitas: 9, vizslas: 4, children: 3
Sue 114: pomeranians: 3, trees: 2, goldfish: 5
Sue 115: perfumes: 8, cars: 6, trees: 0
Sue 116: samoyeds: 6, children: 3, pomeranians: 1
Sue 117: goldfish: 1, trees: 2, akitas: 1
Sue 118: goldfish: 10, akitas: 10, samoyeds: 0
Sue 119: vizslas: 10, perfumes: 6, cars: 0
Sue 120: cars: 2, perfumes: 9, goldfish: 5
Sue 121: vizslas: 2, trees: 2, cars: 6
Sue 122: vizslas: 3, trees: 0, akitas: 2
Sue 123: akitas: 5, samoyeds: 7, goldfish: 1
Sue 124: goldfish: 8, samoyeds: 7, trees: 8
Sue 125: trees: 3, goldfish: 8, perfumes: 5
Sue 126: cats: 3, vizslas: 9, goldfish: 0
Sue 127: pomeranians: 9, goldfish: 3, perfumes: 6
Sue 128: vizslas: 4, cars: 8, goldfish: 5
Sue 129: vizslas: 8, children: 5, perfumes: 8
Sue 130: cars: 7, children: 7, cats: 3
Sue 131: perfumes: 1, akitas: 8, vizslas: 9
Sue 132: perfumes: 7, samoyeds: 10, pomeranians: 6
Sue 133: cars: 5, perfumes: 3, goldfish: 7
Sue 134: perfumes: 9, akitas: 2, cats: 3
Sue 135: perfumes: 1, trees: 9, vizslas: 9
Sue 136: akitas: 7, cars: 3, perfumes: 7
Sue 137: vizslas: 9, goldfish: 8, cars: 5
Sue 138: trees: 0, samoyeds: 1, cars: 3
Sue 139: cars: 0, perfumes: 6, trees: 0
Sue 140: pomeranians: 4, cars: 1, perfumes: 7
Sue 141: vizslas: 10, akitas: 8, cats: 3
Sue 142: trees: 1, cats: 6, vizslas: 5
Sue 143: pomeranians: 9, cars: 7, perfumes: 9
Sue 144: cars: 0, perfumes: 2, pomeranians: 1
Sue 145: trees: 1, goldfish: 9, perfumes: 8
Sue 146: cars: 8, children: 5, vizslas: 2
Sue 147: perfumes: 2, goldfish: 5, cars: 0
Sue 148: akitas: 2, perfumes: 7, pomeranians: 6
Sue 149: goldfish: 8, cars: 0, trees: 1
Sue 150: akitas: 6, perfumes: 5, trees: 0
Sue 151: vizslas: 6, samoyeds: 8, akitas: 10
Sue 152: trees: 7, akitas: 7, perfumes: 6
Sue 153: goldfish: 9, cats: 9, cars: 3
Sue 154: vizslas: 10, trees: 0, cars: 9
Sue 155: perfumes: 3, children: 2, goldfish: 1
Sue 156: goldfish: 7, perfumes: 5, akitas: 6
Sue 157: cats: 10, trees: 1, goldfish: 0
Sue 158: cats: 7, children: 7, vizslas: 6
Sue 159: perfumes: 9, akitas: 0, cars: 0
Sue 160: akitas: 3, goldfish: 10, pomeranians: 2
Sue 161: goldfish: 10, cars: 6, perfumes: 3
Sue 162: trees: 0, cars: 9, goldfish: 1
Sue 163: cars: 8, perfumes: 9, vizslas: 5
Sue 164: goldfish: 1, trees: 10, children: 6
Sue 165: goldfish: 0, vizslas: 6, cars: 0
Sue 166: akitas: 5, vizslas: 1, cars: 5
Sue 167: vizslas: 1, samoyeds: 1, children: 4
Sue 168: samoyeds: 7, vizslas: 7, akitas: 3
Sue 169: goldfish: 3, cats: 9, trees: 2
Sue 170: cars: 5, perfumes: 9, vizslas: 5
Sue 171: goldfish: 7, cars: 6, perfumes: 10
Sue 172: cats: 6, akitas: 1, children: 6
Sue 173: cats: 4, goldfish: 1, children: 3
Sue 174: cars: 2, pomeranians: 2, vizslas: 7
Sue 175: trees: 0, children: 4, goldfish: 7
Sue 176: children: 8, cars: 5, cats: 9
Sue 177: pomeranians: 4, vizslas: 7, trees: 3
Sue 178: vizslas: 6, perfumes: 10, akitas: 6
Sue 179: cars: 4, akitas: 4, trees: 4
Sue 180: akitas: 8, goldfish: 6, trees: 9
Sue 181: perfumes: 3, vizslas: 10, cars: 3
Sue 182: vizslas: 3, samoyeds: 3, goldfish: 7
Sue 183: goldfish: 10, perfumes: 2, cats: 1
Sue 184: goldfish: 5, trees: 1, perfumes: 1
Sue 185: vizslas: 10, trees: 9, perfumes: 2
Sue 186: goldfish: 6, perfumes: 9, trees: 1
Sue 187: cars: 0, trees: 9, goldfish: 6
Sue 188: cars: 0, trees: 1, vizslas: 9
Sue 189: akitas: 7, vizslas: 2, trees: 0
Sue 190: pomeranians: 5, perfumes: 8, akitas: 10
Sue 191: vizslas: 5, akitas: 3, cats: 0
Sue 192: children: 1, trees: 1, cars: 2
Sue 193: cars: 3, goldfish: 9, trees: 2
Sue 194: samoyeds: 3, akitas: 4, perfumes: 8
Sue 195: trees: 1, vizslas: 8, akitas: 10
Sue 196: akitas: 6, cars: 5, pomeranians: 0
Sue 197: akitas: 5, vizslas: 5, cats: 1
Sue 198: trees: 4, cars: 6, goldfish: 6
Sue 199: cats: 7, cars: 5, goldfish: 6
Sue 200: vizslas: 4, cats: 0, akitas: 9
Sue 201: pomeranians: 1, perfumes: 4, children: 2
Sue 202: cats: 1, perfumes: 4, vizslas: 3
Sue 203: vizslas: 1, akitas: 9, children: 5
Sue 204: perfumes: 8, cars: 7, trees: 4
Sue 205: perfumes: 7, pomeranians: 5, cats: 9
Sue 206: vizslas: 8, trees: 2, akitas: 2
Sue 207: akitas: 6, vizslas: 2, perfumes: 10
Sue 208: vizslas: 1, children: 7, akitas: 4
Sue 209: perfumes: 4, trees: 2, children: 1
Sue 210: goldfish: 0, vizslas: 2, samoyeds: 10
Sue 211: cars: 8, perfumes: 3, trees: 1
Sue 212: cars: 8, samoyeds: 5, pomeranians: 8
Sue 213: akitas: 2, goldfish: 8, pomeranians: 2
Sue 214: akitas: 6, pomeranians: 2, cars: 0
Sue 215: trees: 10, pomeranians: 4, vizslas: 0
Sue 216: perfumes: 0, cars: 8, trees: 0
Sue 217: samoyeds: 8, akitas: 7, children: 10
Sue 218: perfumes: 1, vizslas: 6, children: 0
Sue 219: children: 1, goldfish: 4, trees: 1
Sue 220: akitas: 10, goldfish: 10, trees: 5
Sue 221: cars: 7, pomeranians: 6, perfumes: 3
Sue 222: vizslas: 6, children: 0, akitas: 5
Sue 223: perfumes: 9, cars: 1, trees: 6
Sue 224: pomeranians: 1, trees: 0, vizslas: 0
Sue 225: goldfish: 8, akitas: 4, perfumes: 10
Sue 226: pomeranians: 7, cats: 7, children: 4
Sue 227: trees: 0, akitas: 2, perfumes: 1
Sue 228: vizslas: 6, cars: 10, perfumes: 9
Sue 229: cars: 0, perfumes: 6, trees: 4
Sue 230: pomeranians: 7, perfumes: 5, trees: 2
Sue 231: goldfish: 9, cars: 6, trees: 7
Sue 232: akitas: 1, vizslas: 5, cars: 3
Sue 233: akitas: 7, samoyeds: 2, vizslas: 5
Sue 234: akitas: 6, cats: 8, pomeranians: 0
Sue 235: pomeranians: 5, akitas: 5, vizslas: 3
Sue 236: goldfish: 5, trees: 6, akitas: 5
Sue 237: goldfish: 9, perfumes: 5, cats: 5
Sue 238: cats: 8, goldfish: 4, perfumes: 0
Sue 239: samoyeds: 8, children: 6, pomeranians: 6
Sue 240: akitas: 4, samoyeds: 10, trees: 8
Sue 241: trees: 2, goldfish: 8, cars: 1
Sue 242: perfumes: 2, cars: 0, akitas: 10
Sue 243: pomeranians: 1, cars: 7, trees: 2
Sue 244: trees: 9, vizslas: 2, akitas: 10
Sue 245: cars: 9, pomeranians: 4, trees: 0
Sue 246: cars: 9, pomeranians: 7, perfumes: 1
Sue 247: trees: 0, goldfish: 1, akitas: 8
Sue 248: vizslas: 1, cats: 4, akitas: 4
Sue 249: cats: 6, children: 4, goldfish: 9
Sue 250: vizslas: 1, cars: 10, samoyeds: 5
Sue 251: cars: 0, goldfish: 1, vizslas: 7
Sue 252: cars: 7, akitas: 9, vizslas: 10
Sue 253: akitas: 7, vizslas: 2, perfumes: 5
Sue 254: vizslas: 10, akitas: 5, samoyeds: 0
Sue 255: pomeranians: 8, goldfish: 0, cats: 6
Sue 256: cars: 10, goldfish: 8, vizslas: 9
Sue 257: goldfish: 3, perfumes: 9, cats: 3
Sue 258: trees: 6, goldfish: 6, cars: 6
Sue 259: trees: 0, goldfish: 2, perfumes: 8
Sue 260: trees: 5, akitas: 0, cars: 0
Sue 261: pomeranians: 9, goldfish: 7, perfumes: 8
Sue 262: perfumes: 8, vizslas: 6, goldfish: 2
Sue 263: vizslas: 6, trees: 5, goldfish: 9
Sue 264: vizslas: 4, perfumes: 7, cars: 9
Sue 265: goldfish: 10, trees: 3, perfumes: 1
Sue 266: trees: 10, akitas: 8, goldfish: 8
Sue 267: goldfish: 4, trees: 0, samoyeds: 9
Sue 268: vizslas: 1, trees: 0, goldfish: 8
Sue 269: cars: 2, perfumes: 10, goldfish: 5
Sue 270: perfumes: 7, cars: 2, vizslas: 1
Sue 271: cars: 6, perfumes: 10, goldfish: 6
Sue 272: samoyeds: 4, goldfish: 2, vizslas: 9
Sue 273: perfumes: 4, goldfish: 4, vizslas: 1
Sue 274: children: 4, cars: 4, perfumes: 3
Sue 275: children: 8, vizslas: 3, trees: 2
Sue 276: vizslas: 5, children: 7, perfumes: 3
Sue 277: perfumes: 3, cats: 4, vizslas: 5
Sue 278: cars: 1, samoyeds: 10, akitas: 2
Sue 279: trees: 9, perfumes: 9, cars: 10
Sue 280: vizslas: 5, trees: 0, perfumes: 6
Sue 281: vizslas: 3, akitas: 10, pomeranians: 7
Sue 282: trees: 1, children: 2, akitas: 8
Sue 283: akitas: 9, goldfish: 6, cats: 5
Sue 284: cars: 9, children: 10, pomeranians: 2
Sue 285: pomeranians: 0, perfumes: 4, cars: 7
Sue 286: perfumes: 0, vizslas: 10, akitas: 10
Sue 287: cats: 2, perfumes: 3, trees: 5
Sue 288: akitas: 9, vizslas: 8, samoyeds: 9
Sue 289: perfumes: 6, children: 2, cars: 7
Sue 290: akitas: 0, children: 5, cars: 5
Sue 291: cars: 4, perfumes: 0, trees: 1
Sue 292: cats: 0, cars: 8, perfumes: 6
Sue 293: akitas: 9, cats: 5, children: 5
Sue 294: akitas: 4, cars: 9, goldfish: 3
Sue 295: cars: 2, akitas: 3, perfumes: 7
Sue 296: perfumes: 4, cars: 7, goldfish: 10
Sue 297: trees: 5, akitas: 8, vizslas: 1
Sue 298: perfumes: 0, goldfish: 6, trees: 9
Sue 299: perfumes: 6, samoyeds: 8, cars: 1
Sue 300: goldfish: 10, perfumes: 4, akitas: 2
Sue 301: cars: 3, trees: 0, goldfish: 8
Sue 302: perfumes: 7, samoyeds: 2, vizslas: 7
Sue 303: children: 10, goldfish: 7, perfumes: 2
Sue 304: samoyeds: 8, vizslas: 2, cars: 1
Sue 305: trees: 1, cats: 0, goldfish: 10
Sue 306: trees: 4, perfumes: 2, cars: 7
Sue 307: cars: 6, vizslas: 2, children: 6
Sue 308: vizslas: 2, cars: 0, akitas: 7
Sue 309: cars: 3, vizslas: 8, perfumes: 6
Sue 310: goldfish: 7, perfumes: 7, vizslas: 3
Sue 311: pomeranians: 10, trees: 2, cars: 0
Sue 312: samoyeds: 2, vizslas: 9, akitas: 1
Sue 313: cars: 4, pomeranians: 7, goldfish: 7
Sue 314: akitas: 2, pomeranians: 9, samoyeds: 10
Sue 315: akitas: 3, vizslas: 2, trees: 0
Sue 316: cars: 0, perfumes: 4, pomeranians: 6
Sue 317: akitas: 10, goldfish: 3, pomeranians: 7
Sue 318: cars: 9, trees: 0, pomeranians: 9
Sue 319: akitas: 3, vizslas: 7, children: 10
Sue 320: vizslas: 0, akitas: 8, pomeranians: 4
Sue 321: cars: 10, akitas: 9, vizslas: 3
Sue 322: perfumes: 0, akitas: 8, vizslas: 6
Sue 323: vizslas: 10, perfumes: 5, cars: 3
Sue 324: akitas: 0, goldfish: 6, vizslas: 7
Sue 325: perfumes: 9, vizslas: 5, pomeranians: 2
Sue 326: vizslas: 6, goldfish: 10, pomeranians: 8
Sue 327: vizslas: 10, cars: 1, akitas: 7
Sue 328: trees: 1, perfumes: 10, cars: 10
Sue 329: pomeranians: 5, samoyeds: 3, cars: 10
Sue 330: akitas: 6, cars: 1, pomeranians: 4
Sue 331: cars: 5, children: 2, trees: 0
Sue 332: vizslas: 6, pomeranians: 1, perfumes: 0
Sue 333: akitas: 7, trees: 1, cats: 9
Sue 334: vizslas: 6, goldfish: 9, akitas: 7
Sue 335: akitas: 3, samoyeds: 3, cars: 3
Sue 336: samoyeds: 10, perfumes: 9, trees: 6
Sue 337: vizslas: 2, cars: 9, akitas: 0
Sue 338: akitas: 6, perfumes: 9, vizslas: 3
Sue 339: cars: 3, samoyeds: 8, trees: 2
Sue 340: cats: 7, perfumes: 8, cars: 9
Sue 341: goldfish: 9, perfumes: 5, cars: 10
Sue 342: trees: 0, akitas: 3, perfumes: 5
Sue 343: perfumes: 2, children: 0, cars: 6
Sue 344: goldfish: 8, trees: 8, perfumes: 0
Sue 345: perfumes: 6, cars: 6, goldfish: 5
Sue 346: vizslas: 8, trees: 1, cars: 6
Sue 347: cars: 0, cats: 3, perfumes: 7
Sue 348: children: 7, perfumes: 10, cars: 7
Sue 349: pomeranians: 8, akitas: 5, children: 2
Sue 350: perfumes: 9, pomeranians: 4, goldfish: 3
Sue 351: perfumes: 8, pomeranians: 7, trees: 4
Sue 352: samoyeds: 1, goldfish: 9, akitas: 8
Sue 353: akitas: 6, goldfish: 10, vizslas: 8
Sue 354: akitas: 7, cars: 2, goldfish: 6
Sue 355: cars: 3, goldfish: 6, akitas: 5
Sue 356: akitas: 2, goldfish: 9, pomeranians: 1
Sue 357: goldfish: 10, cars: 6, pomeranians: 9
Sue 358: trees: 0, children: 2, goldfish: 6
Sue 359: samoyeds: 3, cars: 2, akitas: 4
Sue 360: trees: 1, goldfish: 8, cars: 5
Sue 361: akitas: 5, vizslas: 7, perfumes: 1
Sue 362: cats: 5, vizslas: 9, children: 4
Sue 363: goldfish: 9, perfumes: 3, vizslas: 9
Sue 364: children: 7, samoyeds: 2, pomeranians: 10
Sue 365: perfumes: 9, akitas: 10, pomeranians: 4
Sue 366: cars: 10, trees: 3, cats: 4
Sue 367: vizslas: 6, akitas: 10, perfumes: 5
Sue 368: akitas: 9, vizslas: 9, children: 4
Sue 369: goldfish: 8, trees: 2, perfumes: 5
Sue 370: trees: 0, children: 4, cars: 8
Sue 371: cats: 6, perfumes: 0, vizslas: 2
Sue 372: akitas: 7, cars: 5, perfumes: 3
Sue 373: cars: 0, perfumes: 4, pomeranians: 10
Sue 374: akitas: 5, perfumes: 5, vizslas: 2
Sue 375: goldfish: 7, trees: 10, pomeranians: 7
Sue 376: cars: 8, trees: 1, pomeranians: 8
Sue 377: cars: 0, akitas: 9, vizslas: 1
Sue 378: akitas: 5, perfumes: 3, vizslas: 7
Sue 379: trees: 2, goldfish: 8, pomeranians: 8
Sue 380: akitas: 5, cars: 9, perfumes: 9
Sue 381: cars: 2, perfumes: 6, trees: 3
Sue 382: perfumes: 6, vizslas: 2, goldfish: 9
Sue 383: akitas: 8, vizslas: 7, cats: 1
Sue 384: akitas: 9, trees: 10, vizslas: 7
Sue 385: cars: 0, perfumes: 7, vizslas: 2
Sue 386: vizslas: 10, akitas: 4, perfumes: 9
Sue 387: perfumes: 6, pomeranians: 5, samoyeds: 8
Sue 388: vizslas: 10, trees: 9, goldfish: 9
Sue 389: goldfish: 8, akitas: 4, perfumes: 10
Sue 390: goldfish: 6, trees: 8, akitas: 1
Sue 391: vizslas: 4, akitas: 10, goldfish: 7
Sue 392: akitas: 1, vizslas: 6, samoyeds: 5
Sue 393: trees: 6, cars: 3, akitas: 5
Sue 394: goldfish: 9, trees: 3, cars: 5
Sue 395: akitas: 6, samoyeds: 4, goldfish: 4
Sue 396: akitas: 2, trees: 1, cats: 5
Sue 397: cars: 0, children: 9, trees: 10
Sue 398: pomeranians: 3, samoyeds: 9, goldfish: 10
Sue 399: cars: 7, akitas: 4, goldfish: 8
Sue 400: cars: 4, akitas: 5, vizslas: 4
Sue 401: pomeranians: 5, akitas: 8, vizslas: 5
Sue 402: cats: 7, cars: 6, goldfish: 6
Sue 403: samoyeds: 8, perfumes: 4, cars: 5
Sue 404: akitas: 10, goldfish: 4, trees: 2
Sue 405: trees: 8, perfumes: 1, cars: 2
Sue 406: trees: 0, perfumes: 9, pomeranians: 10
Sue 407: perfumes: 4, trees: 7, goldfish: 3
Sue 408: akitas: 1, perfumes: 3, cars: 5
Sue 409: trees: 6, samoyeds: 3, cars: 9
Sue 410: vizslas: 3, goldfish: 5, akitas: 7
Sue 411: goldfish: 10, trees: 1, vizslas: 9
Sue 412: cars: 0, akitas: 6, trees: 6
Sue 413: goldfish: 7, trees: 0, cars: 3
Sue 414: pomeranians: 10, samoyeds: 3, cars: 10
Sue 415: perfumes: 6, trees: 9, cars: 4
Sue 416: trees: 2, cars: 4, goldfish: 8
Sue 417: goldfish: 2, cars: 9, cats: 5
Sue 418: vizslas: 1, cars: 9, akitas: 0
Sue 419: perfumes: 6, cats: 3, children: 9
Sue 420: cats: 5, goldfish: 7, akitas: 9
Sue 421: trees: 1, samoyeds: 6, pomeranians: 1
Sue 422: trees: 10, goldfish: 6, children: 7
Sue 423: cars: 8, goldfish: 7, vizslas: 3
Sue 424: samoyeds: 9, akitas: 7, trees: 5
Sue 425: akitas: 5, children: 4, perfumes: 9
Sue 426: goldfish: 1, children: 9, cats: 2
Sue 427: vizslas: 9, akitas: 7, goldfish: 9
Sue 428: pomeranians: 7, akitas: 5, vizslas: 1
Sue 429: vizslas: 7, goldfish: 7, cars: 9
Sue 430: trees: 7, perfumes: 0, pomeranians: 5
Sue 431: children: 9, perfumes: 5, vizslas: 7
Sue 432: trees: 6, samoyeds: 7, cats: 1
Sue 433: goldfish: 5, trees: 5, children: 6
Sue 434: goldfish: 9, akitas: 7, cars: 3
Sue 435: samoyeds: 10, perfumes: 2, cars: 0
Sue 436: akitas: 5, pomeranians: 4, perfumes: 7
Sue 437: vizslas: 5, cats: 6, perfumes: 5
Sue 438: trees: 2, goldfish: 6, vizslas: 7
Sue 439: samoyeds: 8, pomeranians: 10, goldfish: 1
Sue 440: akitas: 6, children: 9, perfumes: 4
Sue 441: cars: 2, goldfish: 9, children: 0
Sue 442: goldfish: 7, cars: 2, vizslas: 8
Sue 443: goldfish: 6, samoyeds: 3, perfumes: 2
Sue 444: trees: 2, goldfish: 7, cars: 8
Sue 445: trees: 2, pomeranians: 0, children: 0
Sue 446: perfumes: 4, akitas: 4, goldfish: 6
Sue 447: vizslas: 7, akitas: 9, cars: 3
Sue 448: goldfish: 6, trees: 9, cars: 0
Sue 449: samoyeds: 7, perfumes: 4, vizslas: 10
Sue 450: akitas: 7, cars: 10, goldfish: 7
Sue 451: goldfish: 4, children: 7, pomeranians: 4
Sue 452: cats: 4, vizslas: 6, trees: 7
Sue 453: cars: 1, trees: 10, goldfish: 9
Sue 454: trees: 2, goldfish: 3, vizslas: 10
Sue 455: pomeranians: 9, vizslas: 3, akitas: 2
Sue 456: vizslas: 10, akitas: 2, goldfish: 1
Sue 457: trees: 5, cats: 5, children: 8
Sue 458: cars: 6, goldfish: 3, akitas: 9
Sue 459: goldfish: 7, akitas: 2, cats: 7
Sue 460: akitas: 1, cars: 5, children: 8
Sue 461: cars: 8, perfumes: 0, goldfish: 6
Sue 462: pomeranians: 6, cats: 2, perfumes: 6
Sue 463: vizslas: 7, perfumes: 3, goldfish: 3
Sue 464: akitas: 10, goldfish: 10, trees: 1
Sue 465: vizslas: 0, akitas: 2, trees: 2
Sue 466: perfumes: 6, akitas: 8, cars: 2
Sue 467: goldfish: 1, cars: 10, perfumes: 3
Sue 468: goldfish: 4, trees: 2, cars: 9
Sue 469: perfumes: 6, pomeranians: 0, vizslas: 10
Sue 470: samoyeds: 8, children: 0, akitas: 7
Sue 471: children: 3, goldfish: 9, cats: 9
Sue 472: samoyeds: 0, goldfish: 0, trees: 0
Sue 473: trees: 3, goldfish: 4, vizslas: 1
Sue 474: perfumes: 10, cars: 3, trees: 7
Sue 475: akitas: 5, vizslas: 4, goldfish: 5
Sue 476: children: 2, akitas: 7, vizslas: 3
Sue 477: vizslas: 6, pomeranians: 9, trees: 6
Sue 478: vizslas: 7, pomeranians: 6, akitas: 7
Sue 479: trees: 2, perfumes: 2, children: 2
Sue 480: cars: 8, cats: 5, vizslas: 0
Sue 481: trees: 5, goldfish: 0, akitas: 3
Sue 482: cars: 8, perfumes: 6, goldfish: 10
Sue 483: goldfish: 0, cars: 3, perfumes: 10
Sue 484: pomeranians: 1, samoyeds: 1, perfumes: 3
Sue 485: trees: 0, akitas: 2, vizslas: 4
Sue 486: cars: 3, vizslas: 8, goldfish: 1
Sue 487: pomeranians: 9, vizslas: 2, children: 10
Sue 488: akitas: 6, vizslas: 10, perfumes: 9
Sue 489: goldfish: 6, vizslas: 4, cars: 2
Sue 490: vizslas: 10, cats: 8, samoyeds: 1
Sue 491: cats: 9, cars: 1, perfumes: 10
Sue 492: goldfish: 6, cars: 9, pomeranians: 9
Sue 493: children: 10, goldfish: 10, vizslas: 0
Sue 494: pomeranians: 5, cars: 0, vizslas: 0
Sue 495: vizslas: 7, perfumes: 6, samoyeds: 3
Sue 496: trees: 1, cats: 4, cars: 10
Sue 497: cats: 1, perfumes: 0, cars: 7
Sue 498: perfumes: 7, vizslas: 6, cats: 9
Sue 499: vizslas: 8, perfumes: 1, akitas: 3
Sue 500: perfumes: 4, cars: 9, trees: 4

View file

@ -0,0 +1,8 @@
[package]
name = "day17-no_such_thing_as_too_much"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

@ -0,0 +1,32 @@
\--- Day 17: No Such Thing as Too Much ---
----------
The elves bought too much eggnog again - `150` liters this time. To fit it all into your refrigerator, you'll need to move it into smaller containers. You take an inventory of the capacities of the available containers.
For example, suppose you have containers of size `20`, `15`, `10`, `5`, and `5` liters. If you need to store `25` liters, there are four ways to do it:
* `15` and `10`
* `20` and `5` (the first `5`)
* `20` and `5` (the second `5`)
* `15`, `5`, and `5`
Filling all containers entirely, how many different *combinations of containers* can exactly fit all `150` liters of eggnog?
Your puzzle answer was `654`.
\--- Part Two ---
----------
While playing with all the containers in the kitchen, another load of eggnog arrives! The shipping and receiving department is requesting as many containers as you can spare.
Find the minimum number of containers that can exactly fit all `150` liters of eggnog. *How many different ways* can you fill that number of containers and still hold exactly `150` litres?
In the example above, the minimum number of containers was two. There were three ways to use that many containers, and so the answer there would be `3`.
Your puzzle answer was `57`.
Both parts of this puzzle are complete! They provide two gold stars: \*\*
At this point, all that is left is for you to [admire your Advent calendar](/2015).
If you still want to see it, you can [get your puzzle input](17/input).

View file

@ -0,0 +1,50 @@
pub fn run(input: &str, amount: usize) -> (usize, usize) {
let containers: Vec<_> = input.lines().map(|i| i.parse::<usize>().unwrap()).collect();
let first = get_combinations_for_containers(&containers, amount, usize::MAX);
let mut second = 0;
let mut i = 1;
while second == 0 {
second = get_combinations_for_containers(&containers, amount, i);
i += 1;
}
(first, second)
}
fn get_combinations_for_containers(containers: &[usize], amount: usize, containers_remaining: usize) -> usize {
if containers.is_empty() || containers_remaining == 0 {
match amount {
0 => 1,
_ => 0,
}
} else {
let first = containers[0];
if first > amount {
get_combinations_for_containers(&containers[1..], amount, containers_remaining)
} else {
get_combinations_for_containers(&containers[1..], amount, containers_remaining) +
get_combinations_for_containers(&containers[1..], amount - first, containers_remaining-1)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::read_to_string;
fn read_file(name: &str) -> String {
read_to_string(name).expect(&format!("Unable to read file: {}", name)[..])
}
#[test]
fn test_sample() {
let sample_input = read_file("tests/sample_input");
assert_eq!(run(&sample_input, 25), (4, 3));
}
#[test]
fn test_challenge() {
let challenge_input = read_file("tests/challenge_input");
assert_eq!(run(&challenge_input, 150), (654, 57));
}
}

View file

@ -0,0 +1,20 @@
50
44
11
49
42
46
18
32
26
40
21
7
18
43
10
47
36
24
22
40

View file

@ -0,0 +1,5 @@
20
15
10
5
5

View file

@ -0,0 +1,8 @@
[package]
name = "day18-like_a_gif_for_your_yard"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

@ -0,0 +1,148 @@
\--- Day 18: Like a GIF For Your Yard ---
----------
After the [million lights incident](6), the fire code has gotten stricter: now, at most ten thousand lights are allowed. You arrange them in a 100x100 grid.
Never one to let you down, Santa again mails you instructions on the ideal lighting configuration. With so few lights, he says, you'll have to resort to *animation*.
Start by setting your lights to the included initial configuration (your puzzle input). A `#` means "on", and a `.` means "off".
Then, animate your grid in steps, where each step decides the next configuration based on the current one. Each light's next state (either on or off) depends on its current state and the current states of the eight lights adjacent to it (including diagonals). Lights on the edge of the grid might have fewer than eight neighbors; the missing ones always count as "off".
For example, in a simplified 6x6 grid, the light marked `A` has the neighbors numbered `1` through `8`, and the light marked `B`, which is on an edge, only has the neighbors marked `1` through `5`:
```
1B5...
234...
......
..123.
..8A4.
..765.
```
The state a light should have next is based on its current state (on or off) plus the *number of neighbors that are on*:
* A light which is *on* stays on when `2` or `3` neighbors are on, and turns off otherwise.
* A light which is *off* turns on if exactly `3` neighbors are on, and stays off otherwise.
All of the lights update simultaneously; they all consider the same current state before moving to the next.
Here's a few steps from an example configuration of another 6x6 grid:
```
Initial state:
.#.#.#
...##.
#....#
..#...
#.#..#
####..
After 1 step:
..##..
..##.#
...##.
......
#.....
#.##..
After 2 steps:
..###.
......
..###.
......
.#....
.#....
After 3 steps:
...#..
......
...#..
..##..
......
......
After 4 steps:
......
......
..##..
..##..
......
......
```
After `4` steps, this example has four lights on.
In your grid of 100x100 lights, given your initial configuration, *how many lights are on after 100 steps*?
Your puzzle answer was `1061`.
\--- Part Two ---
----------
You flip the instructions over; Santa goes on to point out that this is all just an implementation of [Conway's Game of Life](https://en.wikipedia.org/wiki/Conway's_Game_of_Life). At least, it was, until you notice that something's wrong with the grid of lights you bought: four lights, one in each corner, are *stuck on* and can't be turned off. The example above will actually run like this:
```
Initial state:
##.#.#
...##.
#....#
..#...
#.#..#
####.#
After 1 step:
#.##.#
####.#
...##.
......
#...#.
#.####
After 2 steps:
#..#.#
#....#
.#.##.
...##.
.#..##
##.###
After 3 steps:
#...##
####.#
..##.#
......
##....
####.#
After 4 steps:
#.####
#....#
...#..
.##...
#.....
#.#..#
After 5 steps:
##.###
.##..#
.##...
.##...
#.#...
##...#
```
After `5` steps, this example now has `17` lights on.
In your grid of 100x100 lights, given your initial configuration, but with the four corners always in the *on* state, *how many lights are on after 100 steps*?
Your puzzle answer was `1006`.
Both parts of this puzzle are complete! They provide two gold stars: \*\*
At this point, all that is left is for you to [admire your Advent calendar](/2015).
If you still want to see it, you can [get your puzzle input](18/input).

View file

@ -0,0 +1,108 @@
#[derive(Clone)]
struct Light {
state: bool,
}
#[derive(Clone)]
struct Grid {
lights: Vec<Vec<Light>>,
}
impl Grid {
fn from(input: &str) -> Self {
Self {
lights: input.lines()
.map(|line| line.chars()
.map(|c| Light { state: c == '#' })
.collect())
.collect()
}
}
fn get_neighbours(&self, x: usize, y: usize) -> Vec<(usize, usize)> {
let x_min = x.saturating_sub(1);
let x_max = (x+1).min(self.lights[0].len()-1);
let y_min = y.saturating_sub(1);
let y_max = (y+1).min(self.lights.len()-1);
let mut out = Vec::new();
for c in x_min..=x_max {
for r in y_min..=y_max {
if c != x || r != y {
out.push((c, r));
}
}
}
out
}
fn step(&mut self, broken: bool) {
let old_grid = self.clone();
for (row_idx, row) in self.lights.iter_mut().enumerate() {
for (col_idx, light) in row.iter_mut().enumerate() {
let this_state = light.state;
let neighbours_on = old_grid.get_neighbours(col_idx, row_idx).iter().filter(|n| old_grid.lights[n.1][n.0].state).count();
light.state = match (this_state, neighbours_on) {
(true, n) if (2..=3).contains(&n) => true,
(true, _) => false,
(false, 3) => true,
(false, _) => false,
};
}
}
if broken {
self.broken_on();
}
}
fn broken_on(&mut self) {
for c in [0, self.lights[0].len()-1] {
for r in [0, self.lights.len()-1] {
self.lights[r][c].state = true;
}
}
}
fn count_on(&self) -> usize {
self.lights.iter().map(|r| r.iter().filter(|l| l.state).count()).sum()
}
}
pub fn run(input: &str, steps: usize) -> (usize, usize) {
let mut grid = Grid::from(input);
let mut grid2 = grid.clone();
grid2.broken_on();
for _ in 0..steps {
grid.step(false);
grid2.step(true);
}
let first = grid.count_on();
let second = grid2.count_on();
(first, second)
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::read_to_string;
fn read_file(name: &str) -> String {
read_to_string(name).expect(&format!("Unable to read file: {}", name)[..])
}
#[test]
fn test_sample() {
let sample_input = read_file("tests/sample_input");
let expected = [ (15, 17), (11, 18), (8, 18), (4, 18), (4, 14), (4, 17) ];
for (idx, lights) in expected.into_iter().enumerate() {
assert_eq!(run(&sample_input, idx), lights);
}
}
#[test]
fn test_challenge() {
let challenge_input = read_file("tests/challenge_input");
assert_eq!(run(&challenge_input, 100), (1061, 1006));
}
}

View file

@ -0,0 +1,100 @@
#..####.##..#...#..#...#...###.#.#.#..#....#.##..#...##...#..#.....##..#####....#.##..##....##.#....
.#..#..#..#.###...##..#.##.....#...#..##....#####.##............####.#..######..#.#.##.#...#..#...##
#.....##.##.##.#..##.#..###...#.#.#..##..###.####.####.#.####.#...##.#..###.........#.###...#....###
#.###..#######..##..#.....##.#.#.###.#.##..#.##..##.##.#.##...###.#...#.#####.#.##..#.#####..#.#####
#.##.##.###.##..###.#.##.##...##.#.#..##..###.########.#.####..####...#####...#..#...##....##.##.##.
..#.#.#.#..#.#.###....###...#...#.##..####.###.....#.####.###.###.#......#.#.###..#..#.#....#.#####.
...#.###.#....#.###...#.#.#...#...#.#####....#....#...#####..#..#.#..######..#.##.#.##.#..###.#...##
.###...#...#.#..#.#.####.#...#.....##...###.#....#..##.###....#.##....###..#.#####...###.#.##.####..
#.#....##.#.....#####.#.##..#######.#.####..###.##.#####.##.#...###...#.#...###..#...#.#.###.###.###
...##.##.....##..#.##...#.#...#...#.#####.#...#.#.#.#####.##.#...#.#..##.##..#...#....####..###.###.
#..#....######...#...###.#....#####....#.#.#....#....#.#######.#####..#....#....#.##..#.##.###..#...
#####.#.######.#.#####.#..##..##..####..#....#...#######....##..##.#..###..###.###..###...#...######
#...##..##...###....##..##.##..#.#.#.#....##.#.......###..###..###...###..##.##.##.#.#.#..#.#..#..#.
..###....##.###..#.#..########...###...##..#######....##..###..#####.##.#....###..##.##.##.#...##.#.
###..#.#..#.#.##.##...##.....#..###.#..##.##.#....##.#.######..##..#.#.##.###...#..####...#.#..#.###
.######....#..##..#.####.##..#.#..#.#..#....#..##.#..#.#...####..#....#.####.#.###.#...####.#...#.#.
#.######.##..###.###..#..###.#...#..#...#...###.##....#.#......#...#.##.#.###..#.#####.#.#..###..#.#
...#..#...####..###.########.....###.###.#..##.##....######..#..#.....#.##.##.#..##..#..##...#..#..#
#..#..##..#.#.########.##.#.####..#.#####.#.###.##....###..##..#.#.###..#.##..##.##.####...######.##
.######.###....#...##...#..#....##..#.#...###.######.##...#....##.##.#.#.##..#...###.###.#....#..##.
####.#.##..##.##.###...#.###.##..##....###..####.##..#.#.##..###.#..##...####...#..####.#.#..##...#.
.#.#..#.....##...#..#...#.#...#.#.##..#....#..#......#####.#######....#.#..#..###..##.#.########..##
.##.#..#..##..#..####.#...####...#...#..##.#..###.#..######..#.#...###.##...#..#####..##.#..##.#.##.
.###..##.##.##....###.###..#.#...##.#.#...#.#######.####..#..###.#######.#...#.#...#.##...#..####..#
##.########..#..#....#.###..##.##.#.##.#..#......####..##.##.#..####..#####..#.....#####.###..#.#.#.
.#..####..##.#.#..#####.##..#..#.#....#.#####.#####...######........##.##..##.#.#.###..#.#.#.#..##.#
.##..##..#.######..###....#.#.###.#........#..###..#.########.....#.##...#.....#..#...##...#..#.###.
##.##.#..####....####.#######.....#.#.#...#.######.#.....####.####...###..####.##.##....###..#..#...
#.#..####...#......#...###...##....##.#######..#.###.#...###.##.##...####..#.####..#......##..#####.
.#.#...##...#....#.####.##.....#....#.#.#######..###.#.....#.....####...##...#.#.##.####..##.###.#.#
####.#.#.####...#...####.#.....#.#######.#.......####......###..###.#...######..#.##.#.##..#..##..##
..##.###..#..####..####.......######.##..#.....##.##...##.##......#.###..###...#.##.#####.#.######.#
.###..####.###..#..#.......#.##...##...##.######.....#..####.#......#.#...#...#...###...#.#.##..####
.####....##.##.#.....##.###.####.#.......#.......#.#..#.#.#.....###.#.#####.#..#.#.#####.#####.###.#
.##.#.###.#####..#..#....###.#.#.#..#..###..##..####..##.###....#..####.####.#..###.#..######.######
####.#.....##..###....#.....#.##.#.##..##..########.#####..###.####....##.....######.#.#.##.......#.
#.#.##.....#.....##.###.#..#.##.##....#..##....##.#.###.##.#..#..##.##.###.#..##.###...##..###.#####
#.###.#.#.#.#.#.#.#...#..#.###..####.##...#..####.###....#..#..##.#....####..##.##....#.#.##.##....#
...######....#..####...#.#..#.#.#..#.##.#.#.......#..#......##..#...#..#..##...##.#...#.#.#...##.##.
.#####..#...####....#..###..##....#####..###.#.#...###..###.###..##...#......#...#...#.#.#...#.##..#
......#####.#...#.#.#.##..#.###..##..#.#...###..###....##..#####..#######.#..#.###....###...##.#..#.
..##.########.##..#....##.#...##.##.#.#..#.##..#.#.#.##....#.#.#.#.##....##....#....#####.##..#.##.#
####...#....##.#.###......##.##.#..##...#..#####..#.#....##..#####...#.#.##...#.####.####..##.######
.##.###.##.#...#.#....###.#######...##...##..#..##.###.#.####..#..###......#.#.##.#.#....#..##...#..
.#.###.#.###.###.#.##.#..#......####.##...#..##.#..####.....#...#.###.##.##.#..#.##..#.###......#..#
...##.####......#.#.#..###..#....###....#.##.#####..#..#..#...#.#.###...#.#.#.##....###.####..###.#.
##..#.#.#.#....####...#.##.###..####....#..#####.######..#.##.##..#####.#.....#.#...##.#.##.##.#.#..
#..##.#.#.#.###.#.#.###...#.#...##..#..#.#.#.##..###...#..##.#..#.#.#..#.....#.######.#.###..###.#..
....#.#.##.###.##...#.##.#....#..##.#..##...#...#.##.####...##..####.#.........#..##..#...#...##.#..
.##.......##...###.##.#.##.###.##.#..#..#..####...#...#....#####...###..##..#..#..##...#....#..#####
..####..#...#...#..###....##.#.#####..#..#.....#......#...#.......##....####...##....##.##.#.#####.#
##.#.#.#..##..##..#.####.##.##.###.#...###.#....#.....#.###...#######..###.####.###.####.##...##.#..
..#.#...##.#....#..#..##.####.....#.#.#...#..#..###.#..###.#####.#.#####.#.#.#.#.###.##.###..#....##
.###.#...#....###..#...####....####..#.##..#..##.###..#.#.#.#..#...###.#.#...#......#...#.##.##.#...
..####.####.##.#.##....#...##....#..#....#..###..#...#..###.#####.....#####..##.#.#.#.#.#.##.####...
...##.#.##.####..##.###..#.#.#.#.#.#.#..###...#.##..#.####.##...#.#.##......###..#...###....#.#.###.
##...##..#.#.##..#.#.#....#.####.......#.#.#######.#..#....#.###.#...###.##....###.#.#..#.#.##.####.
...##.......######.....##....#...#..#.##.###.#..#.##.###.#.###.#.#.#...#.#...##.##.##..#.##########.
###..#....#.#.....#....###.#...##.......##.#.#..#.#...########......###..##.#..#..####.##..####...#.
......##.###.#.###.....#..#...#.#......##....#....#........#..#...##.##.....#...##.##.........##....
.##.##.#.#...#....######..##....##..##.#.#.##.#.##..##...#..###......##......#.#....#.#.#.......###.
.......#.##..##.#...#.##..#..#####.#..#.######.........###.#####.####.#...##...........##...##..####
#......#.#..#...#...##..#.#.###.##.##.#.#..#.###.##.#..###..#.###..#...###.##..###..#...#..###...#..
####.##..#####..####.#...#..#..###..##.#.#...#...#...#.##.####.##.###....###...#.#.#..####.######.##
.....#..####...#.#.#.####..####..##.###......#.....########.#...#.#..#..#...#.###..##.#####..###.###
.#######.#.##..###.#...###.#####............##.###...#.##.#.##..##.#.#..#.######..######..#..#..####
...##..#.####...#..#.#.##.#....#.####..#..###.###..#.#...#....##.##.#......##..##..#.#.#.###..#..#..
........#...#.##.#.#..#....####....#.##...###..####...###.#.#..######..###..##.#####.###.###.#.#...#
##......##.#..###.####.##.#.###.#.......#.##..####..#.###.##..##..##...##...#.###...#.#..#..#.#####.
##..#.#.....##.####.#..##.#.##.#.#...#...#.#...####.#.#.##...##....##.###..###.####.#...#.###..#####
.#####.####.####.####.#.##.##......###....###.####...###...#...#..#.##.#.#####.###..##.#..###...##..
.#...#..##...##...#....#.#.#..##..#.##..#.###.#.###..###.#.#.###.#....#######.####.##..#..#...####..
..##.##..#.##..#.#.###..#.##.########...####.#.###.##..#..###.###...##..##.#..#.######.##.#....###.#
##.#####.###.##.#.##.##.##.###..##..##..#.#.#.#.####..#......#.#.#.#.#.#.##...#####.####...#.#...#.#
.#..###..##.#####.#.##.#..##...##..##...#####.#.####..#...##.....######.#.#...##.#..#######.###.###.
#.#..##.#.#####.#.#.....###.###.#..##.#####....#.###.##.##.#.#..##..#.#....#######.###.#.#.....#.###
....###...#.###.####....###.....##....#####.##.###.###.##.##.##.#..###..######...####.#.#..####..#..
###.....#..####..#.####..#..#...##.##..##.######.####.....#...##....#..#.##.#####..###.##.#.####...#
.##.##.#...#..####...##.##.###...#...#..#.#.#####.....####...#.#.#..#.####...####.#...###.#......###
###.##....#.#.#...#.###....####..##...##.##.##.#..#...####..#..#..##...#####.####.####...##.#..###.#
..####.....##..###.#.#.###.########..#...#.##..#.#.#.......#.##.#..#...####.##.#..#.######..#.#...#.
#.#.##.#.#.##.#....##......##......#######.#..#.##...##..#.#.###...#.#..#..###...#..###.....##.....#
..#.##.#.##.#.##..##.....#.#..#.#..#...##..#..#.#....###.#####....####.####..#####.##.###...#..###.#
#....#.###..#..########.###..#.#.#.##...##.#..##.###..#..#..#.#.##..###...###.#.##..#.##.#..#.#.####
#.......#######......#...#...##.##...###.#....##.#..#....####.#.##.###...#.#####...##.###........##.
.##.####.....###.##......####.###.########..#.####..#.##.#.####.....#...#.##....#######.##..#......#
#.#.##.##....##..##.#.###..#.##.#..#..#.#..##.....###..###.##.##.####.##.#.#.##...####..#.#..##.#.#.
...##.#.#.#...###.#.......#.#.....#.#...##....##.##.##.####...#.#..#..#..#.#.##.#..#.#.#....###..#.#
....#.#.###.#####.##..###..##..#...#.##.#......##.####.#..####.#.##..####.#.#...##..#####..##.#.#...
..###.#.##..#....#..#.#.....##.#####..##....#.#...#.##..##.#.#..#...##.##..##..##....#...#..#..#..##
##.#.##.#...#.###.##.##.##.##..##.##...#..##.#..#######.#..#...#.#.##..#....##.#..####.###........#.
.##.#..#.....#####..##.#.#.#.#..###.#######.###.###....##....#.#.#.###....###.#..#.#....#.#..###...#
...###.#.#.###..#...#..###.######..##.#.#..#...####.#####.##..#..###...#..#..#..###..##.#.#...#.###.
#......#.#..#..##.##.#.##.#.###.#.##.#.#..#....#.##..#..##..##.#.#.#....##.###.###.####.#.#####...##
...#.##..#.######.......#.#.###.....#####....##.#.#.###........#.#.###.#.#########.##.##.#..##..#...
##..###..###....####.##.##..##.###....####..##...####.####..####..###.####..##.#...###.#####.##.##.#
###...##.#.#.#####..#..#####...##.#...#.#.###.#..##..###.##.#.#.....####.##.#..##.###.#...##.##...##
...#.#.##.##..##....#..#.#####.##.###..#.#.#........####.###.##....##....####..#.#....#.#.#.###..#.#
..#.#.#.#.###...#....##..######.##....#.#.##..###..#.#.###..#.##..#.#.###......#..#..#.####..#...##.
.....####.#.....###.#.##.#..##.#..###.#####.#..##...###.#..###..#..##....###.#..##.#..#.##.#..#...##

View file

@ -0,0 +1,6 @@
.#.#.#
...##.
#....#
..#...
#.#..#
####..

View file

@ -0,0 +1,8 @@
[package]
name = "day19-medicine_for_rudolph"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

@ -0,0 +1,71 @@
\--- Day 19: Medicine for Rudolph ---
----------
Rudolph the Red-Nosed Reindeer is sick! His nose isn't shining very brightly, and he needs medicine.
Red-Nosed Reindeer biology isn't similar to regular reindeer biology; Rudolph is going to need custom-made medicine. Unfortunately, Red-Nosed Reindeer chemistry isn't similar to regular reindeer chemistry, either.
The North Pole is equipped with a Red-Nosed Reindeer nuclear fusion/fission plant, capable of constructing any Red-Nosed Reindeer molecule you need. It works by starting with some input molecule and then doing a series of *replacements*, one per step, until it has the right molecule.
However, the machine has to be calibrated before it can be used. Calibration involves determining the number of molecules that can be generated in one step from a given starting point.
For example, imagine a simpler machine that supports only the following replacements:
```
H => HO
H => OH
O => HH
```
Given the replacements above and starting with `HOH`, the following molecules could be generated:
* `HOOH` (via `H => HO` on the first `H`).
* `HOHO` (via `H => HO` on the second `H`).
* `OHOH` (via `H => OH` on the first `H`).
* `HOOH` (via `H => OH` on the second `H`).
* `HHHH` (via `O => HH`).
So, in the example above, there are `4` *distinct* molecules (not five, because `HOOH` appears twice) after one replacement from `HOH`. Santa's favorite molecule, `HOHOHO`, can become `7` *distinct* molecules (over nine replacements: six from `H`, and three from `O`).
The machine replaces without regard for the surrounding characters. For example, given the string `H2O`, the transition `H => OO` would result in `OO2O`.
Your puzzle input describes all of the possible replacements and, at the bottom, the medicine molecule for which you need to calibrate the machine. *How many distinct molecules can be created* after all the different ways you can do one replacement on the medicine molecule?
Your puzzle answer was `535`.
\--- Part Two ---
----------
Now that the machine is calibrated, you're ready to begin molecule fabrication.
Molecule fabrication always begins with just a single electron, `e`, and applying replacements one at a time, just like the ones during calibration.
For example, suppose you have the following replacements:
```
e => H
e => O
H => HO
H => OH
O => HH
```
If you'd like to make `HOH`, you start with `e`, and then make the following replacements:
* `e => O` to get `O`
* `O => HH` to get `HH`
* `H => OH` (on the second `H`) to get `HOH`
So, you could make `HOH` after *`3` steps*. Santa's favorite molecule, `HOHOHO`, can be made in *`6` steps*.
How long will it take to make the medicine? Given the available *replacements* and the *medicine molecule* in your puzzle input, what is the *fewest number of steps* to go from `e` to the medicine molecule?
Your puzzle answer was `212`.
Both parts of this puzzle are complete! They provide two gold stars: \*\*
At this point, all that is left is for you to [admire your Advent calendar](/2015).
If you still want to see it, you can [get your puzzle input](19/input).

View file

@ -0,0 +1,135 @@
use std::collections::HashSet;
pub fn run(input: &str) -> (usize, usize) {
let (replacements, initial) = parse_input(input);
let first = get_replacements(&replacements, initial).len();
let second = find_reduction(&replacements, initial.to_string()).expect("Unable to construct target molecule");
// let second = a_star_search(initial, "e", &replacements, &str::len);
(first, second)
}
fn parse_input(input: &str) -> (Vec<(&str, &str)>, &str) {
let (replacements_str, initial) = input.split_once("\n\n").expect("Unable to split input by blank line");
(
replacements_str.lines()
.map(|line| line.split_once(" => ").unwrap_or_else(|| panic!("unable to split {} by \" => \"", line)))
.collect(),
initial.trim()
)
}
/*
fn a_star_search(start: &str, goal: &str, replacements: &[(&str, &str)], h: &dyn Fn(&str)->usize) -> usize {
// The set of discovered nodes. Initially only the start node is known.
let mut open_set = HashSet::from([start.to_string()]);
// A map from a node to its predecessor on its cheapest known path.
let mut came_from = HashMap::new();
// A map from a node to its lowest known costs.
let mut g_score = HashMap::from([(start.to_string(), 0)]);
// Estimated costs of each path (f = g+h)
let mut f_score = HashMap::from([(start.to_string(), h(start))]);
loop {
let current = open_set.iter()
.min_by(|&a, &b| f_score.get(a).unwrap()
.cmp(f_score.get(b).unwrap()))
.unwrap().to_owned();
if current == goal {
return reconstruct_path(came_from, &current);
}
open_set.remove(&current);
for neighbour in get_reductions(replacements, current.to_string()) {
let tentative_g_score = g_score.get(&current).unwrap() + 1;
let current_g_score = *g_score.get(&neighbour[..]).unwrap_or(&usize::MAX);
if tentative_g_score < current_g_score {
came_from.insert(neighbour.to_owned(), current.to_string());
g_score.insert(neighbour.to_owned(), tentative_g_score);
f_score.insert(neighbour.to_owned(), tentative_g_score + h(&neighbour));
open_set.insert(neighbour);
}
}
if open_set.is_empty() {
break;
}
}
panic!("Open Set is empty, but goal was never reached.")
}
fn reconstruct_path(came_from: HashMap<String, String>, goal: &str) -> usize {
let mut total_path_len = 0;
let mut current = goal;
while let Some(predecessor) = came_from.get(current) {
total_path_len += 1;
current = predecessor;
}
total_path_len
}
*/
// Always returns the first reduction it finds by trying to shorten the string as much as possible
// as early as possible. This yields the correct results for me, but more hostile inputs probably
// require a more thorough approach, such as the A* algorithm shown above.
fn find_reduction(replacements: &[(&str, &str)], target: String) -> Option<usize> {
if target == *"e" {
Some(0)
} else {
let mut next_step: Vec<_> = get_reductions(replacements, target).into_iter().collect();
next_step.sort_by_key(|a| a.len());
for next_attemt in next_step {
let this_attempt = find_reduction(replacements, next_attemt);
if let Some(score) = this_attempt {
return Some(score + 1);
}
}
None
}
}
fn get_reductions(replacements: &[(&str, &str)], target: String) -> HashSet<String> {
let mut res = HashSet::new();
for idx in 0..target.len() {
for (from, to) in replacements {
if target[idx..].find(*to) == Some(0) {
res.insert(format!("{}{}{}", &target[..idx].to_string(), from, &target[idx+to.len()..].to_string()));
}
}
}
res
}
fn get_replacements(replacements: &[(&str, &str)], initial: &str) -> HashSet<String> {
let mut res = HashSet::new();
for idx in 0..initial.len() {
for (from, to) in replacements {
if initial[idx..].find(*from) == Some(0) {
res.insert(format!("{}{}{}", &initial[..idx].to_string(), to, &initial[idx+from.len()..].to_string()));
}
}
}
res
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::read_to_string;
fn read_file(name: &str) -> String {
read_to_string(name).expect(&format!("Unable to read file: {}", name)[..])
}
#[test]
fn test_sample() {
let sample_input = read_file("tests/sample_input");
assert_eq!(run(&sample_input), (4, 3));
}
#[test]
fn test_challenge() {
let challenge_input = read_file("tests/challenge_input");
assert_eq!(run(&challenge_input), (535, 212));
}
}

View file

@ -0,0 +1,45 @@
Al => ThF
Al => ThRnFAr
B => BCa
B => TiB
B => TiRnFAr
Ca => CaCa
Ca => PB
Ca => PRnFAr
Ca => SiRnFYFAr
Ca => SiRnMgAr
Ca => SiTh
F => CaF
F => PMg
F => SiAl
H => CRnAlAr
H => CRnFYFYFAr
H => CRnFYMgAr
H => CRnMgYFAr
H => HCa
H => NRnFYFAr
H => NRnMgAr
H => NTh
H => OB
H => ORnFAr
Mg => BF
Mg => TiMg
N => CRnFAr
N => HSi
O => CRnFYFAr
O => CRnMgAr
O => HP
O => NRnFAr
O => OTi
P => CaP
P => PTi
P => SiRnFAr
Si => CaSi
Th => ThCa
Ti => BP
Ti => TiTi
e => HF
e => NAl
e => OMg
CRnCaCaCaSiRnBPTiMgArSiRnSiRnMgArSiRnCaFArTiTiBSiThFYCaFArCaCaSiThCaPBSiThSiThCaCaPTiRnPBSiThRnFArArCaCaSiThCaSiThSiRnMgArCaPTiBPRnFArSiThCaSiRnFArBCaSiRnCaPRnFArPMgYCaFArCaPTiTiTiBPBSiThCaPTiBPBSiRnFArBPBSiRnCaFArBPRnSiRnFArRnSiRnBFArCaFArCaCaCaSiThSiThCaCaPBPTiTiRnFArCaPTiBSiAlArPBCaCaCaCaCaSiRnMgArCaSiThFArThCaSiThCaSiRnCaFYCaSiRnFYFArFArCaSiRnFYFArCaSiRnBPMgArSiThPRnFArCaSiRnFArTiRnSiRnFYFArCaSiRnBFArCaSiRnTiMgArSiThCaSiThCaFArPRnFArSiRnFArTiTiTiTiBCaCaSiRnCaCaFYFArSiThCaPTiBPTiBCaSiThSiRnMgArCaF

View file

@ -0,0 +1,7 @@
e => H
e => O
H => HO
H => OH
O => HH
HOH

View file

@ -0,0 +1,8 @@
[package]
name = "day20-infinite_elves_and_infinite_houses"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

@ -0,0 +1,48 @@
\--- Day 20: Infinite Elves and Infinite Houses ---
----------
To keep the Elves busy, Santa has them deliver some presents by hand, door-to-door. He sends them down a street with infinite houses numbered sequentially: `1`, `2`, `3`, `4`, `5`, and so on.
Each Elf is assigned a number, too, and delivers presents to houses based on that number:
* The first Elf (number `1`) delivers presents to every house: `1`, `2`, `3`, `4`, `5`, ....
* The second Elf (number `2`) delivers presents to every second house: `2`, `4`, `6`, `8`, `10`, ....
* Elf number `3` delivers presents to every third house: `3`, `6`, `9`, `12`, `15`, ....
There are infinitely many Elves, numbered starting with `1`. Each Elf delivers presents equal to *ten times* his or her number at each house.
So, the first nine houses on the street end up like this:
```
House 1 got 10 presents.
House 2 got 30 presents.
House 3 got 40 presents.
House 4 got 70 presents.
House 5 got 60 presents.
House 6 got 120 presents.
House 7 got 80 presents.
House 8 got 150 presents.
House 9 got 130 presents.
```
The first house gets `10` presents: it is visited only by Elf `1`, which delivers `1 * 10 = 10` presents. The fourth house gets `70` presents, because it is visited by Elves `1`, `2`, and `4`, for a total of `10 + 20 + 40 = 70` presents.
What is the *lowest house number* of the house to get at least as many presents as the number in your puzzle input?
Your puzzle answer was `665280`.
\--- Part Two ---
----------
The Elves decide they don't want to visit an infinite number of houses. Instead, each Elf will stop after delivering presents to `50` houses. To make up for it, they decide to deliver presents equal to *eleven times* their number at each house.
With these changes, what is the new *lowest house number* of the house to get at least as many presents as the number in your puzzle input?
Your puzzle answer was `705600`.
Both parts of this puzzle are complete! They provide two gold stars: \*\*
At this point, all that is left is for you to [admire your Advent calendar](/2015).
Your puzzle input was `29000000`.

View file

@ -0,0 +1,48 @@
pub fn run(input: usize) -> (usize, usize) {
let first = presents_count_for_house(input, 10, None);
let second = presents_count_for_house(input, 11, Some(50));
(first, second)
}
fn presents_count_for_house(number: usize, multiplier: usize, max: Option<usize> ) -> usize {
let max = max.unwrap_or(number/multiplier);
let size = number/multiplier+1;
let mut counts = vec![0; size];
(1..=size).for_each(|n| {
(n..=size.min(max*n)).step_by(n).for_each(|i| {
counts[i-1] += multiplier*n;
});
});
counts.iter().position(|i| *i >= number).unwrap_or(0) + 1
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sample() {
let exptected = [
(9, (1, 1)),
(10, (1, 1)),
(11, (2, 1)),
(30, (2, 2)),
(40, (3, 3)),
(70, (4, 4)),
(60, (4, 4)),
(120, (6, 6)),
(80, (6, 6)),
(150, (8, 8)),
(130, (8, 6)),
];
for (input, output) in exptected {
assert_eq!(run(input), output);
}
}
#[test]
fn test_challenge() {
let challenge_input = 29_000_000;
assert_eq!(run(challenge_input), (665280, 705600));
}
}

Some files were not shown because too many files have changed in this diff Show more