diff --git a/2020/day15_rambunctious_recitation/Cargo.toml b/2020/day15_rambunctious_recitation/Cargo.toml new file mode 100644 index 0000000..96be776 --- /dev/null +++ b/2020/day15_rambunctious_recitation/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "day15_rambunctious_recitation" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/2020/day15_rambunctious_recitation/challenge.txt b/2020/day15_rambunctious_recitation/challenge.txt new file mode 100644 index 0000000..e79b09c --- /dev/null +++ b/2020/day15_rambunctious_recitation/challenge.txt @@ -0,0 +1,63 @@ +You catch the airport shuttle and try to book a new flight to your vacation island. Due to the storm, all direct flights have been cancelled, but a route is available to get around the storm. You take it. + +While you wait for your flight, you decide to check in with the Elves back at the North Pole. They're playing a *memory game* and are ever so excited to explain the rules! + +In this game, the players take turns saying *numbers*. They begin by taking turns reading from a list of *starting numbers* (your puzzle input). Then, each turn consists of considering the *most recently spoken number*: + +* If that was the *first* time the number has been spoken, the current player says *`0`*. +* Otherwise, the number had been spoken before; the current player announces *how many turns apart* the number is from when it was previously spoken. + +So, after the starting numbers, each turn results in that player speaking aloud either *`0`* (if the last number is new) or an *age* (if the last number is a repeat). + +For example, suppose the starting numbers are `0,3,6`: + +* *Turn 1*: The `1`st number spoken is a starting number, *`0`*. +* *Turn 2*: The `2`nd number spoken is a starting number, *`3`*. +* *Turn 3*: The `3`rd number spoken is a starting number, *`6`*. +* *Turn 4*: Now, consider the last number spoken, `6`. Since that was the first time the number had been spoken, the `4`th number spoken is *`0`*. +* *Turn 5*: Next, again consider the last number spoken, `0`. Since it *had* been spoken before, the next number to speak is the difference between the turn number when it was last spoken (the previous turn, `4`) and the turn number of the time it was most recently spoken before then (turn `1`). Thus, the `5`th number spoken is `4 - 1`, *`3`*. +* *Turn 6*: The last number spoken, `3` had also been spoken before, most recently on turns `5` and `2`. So, the `6`th number spoken is `5 - 2`, *`3`*. +* *Turn 7*: Since `3` was just spoken twice in a row, and the last two turns are `1` turn apart, the `7`th number spoken is *`1`*. +* *Turn 8*: Since `1` is new, the `8`th number spoken is *`0`*. +* *Turn 9*: `0` was last spoken on turns `8` and `4`, so the `9`th number spoken is the difference between them, *`4`*. +* *Turn 10*: `4` is new, so the `10`th number spoken is *`0`*. + +(The game ends when the Elves get sick of playing or dinner is ready, whichever comes first.) + +Their question for you is: what will be the *`2020`th* number spoken? In the example above, the `2020`th number spoken will be `436`. + +Here are a few more examples: + +* Given the starting numbers `1,3,2`, the `2020`th number spoken is `1`. +* Given the starting numbers `2,1,3`, the `2020`th number spoken is `10`. +* Given the starting numbers `1,2,3`, the `2020`th number spoken is `27`. +* Given the starting numbers `2,3,1`, the `2020`th number spoken is `78`. +* Given the starting numbers `3,2,1`, the `2020`th number spoken is `438`. +* Given the starting numbers `3,1,2`, the `2020`th number spoken is `1836`. + +Given your starting numbers, *what will be the `2020`th number spoken?* + +Your puzzle answer was `959`. + +\--- Part Two --- +---------- + +Impressed, the Elves issue you a challenge: determine the `30000000`th number spoken. For example, given the same starting numbers as above: + +* Given `0,3,6`, the `30000000`th number spoken is `175594`. +* Given `1,3,2`, the `30000000`th number spoken is `2578`. +* Given `2,1,3`, the `30000000`th number spoken is `3544142`. +* Given `1,2,3`, the `30000000`th number spoken is `261214`. +* Given `2,3,1`, the `30000000`th number spoken is `6895259`. +* Given `3,2,1`, the `30000000`th number spoken is `18`. +* Given `3,1,2`, the `30000000`th number spoken is `362`. + +Given your starting numbers, *what will be the `30000000`th number spoken?* + +Your puzzle answer was `116590`. + +Both parts of this puzzle are complete! They provide two gold stars: \*\* + +At this point, you should [return to your Advent calendar](/2020) and try another puzzle. + +Your puzzle input was `18,11,9,0,5,1`. \ No newline at end of file diff --git a/2020/day15_rambunctious_recitation/src/lib.rs b/2020/day15_rambunctious_recitation/src/lib.rs new file mode 100644 index 0000000..9dec962 --- /dev/null +++ b/2020/day15_rambunctious_recitation/src/lib.rs @@ -0,0 +1,52 @@ +use std::num::ParseIntError; + +pub fn run(input: &str) -> Result<(usize, usize), ParseIntError> { + let initial: Vec<_> = input.split(',').map(|n| n.parse::()).collect::, _>>()?; + let mut said_last = vec![0; 30_000_000]; + initial.iter().enumerate().for_each(|(idx, i)| {said_last[*i] = idx+1}); + let mut last_number = initial[initial.len()-1]; + let mut next_number = initial.iter().rev().skip(1).position(|n| *n == last_number).map(|n| n+1).unwrap_or(0); + (initial.len()+1..=2020).for_each(|turn| { + last_number = next_number; + if said_last[last_number] == 0 { + next_number = 0; + } else { + next_number = turn - said_last[last_number]; + } + said_last[last_number] = turn; + }); + let first = last_number; + (2021..=30_000_000).for_each(|turn| { + last_number = next_number; + if said_last[last_number] == 0 { + next_number = 0; + } else { + next_number = turn - said_last[last_number]; + } + said_last[last_number] = turn; + }); + let second = last_number; + Ok((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}")[..]).trim().to_string() + } + + #[test] + fn test_sample() { + let sample_input = read_file("tests/sample_input"); + assert_eq!(run(&sample_input), Ok((436, 175594))); + } + + #[test] + fn test_challenge() { + let challenge_input = read_file("tests/challenge_input"); + assert_eq!(run(&challenge_input), Ok((959, 116590))); + } +} diff --git a/2020/day15_rambunctious_recitation/tests/challenge_input b/2020/day15_rambunctious_recitation/tests/challenge_input new file mode 100644 index 0000000..0f50c3c --- /dev/null +++ b/2020/day15_rambunctious_recitation/tests/challenge_input @@ -0,0 +1 @@ +18,11,9,0,5,1 diff --git a/2020/day15_rambunctious_recitation/tests/sample_input b/2020/day15_rambunctious_recitation/tests/sample_input new file mode 100644 index 0000000..c84ffe7 --- /dev/null +++ b/2020/day15_rambunctious_recitation/tests/sample_input @@ -0,0 +1 @@ +0,3,6