Advent of Code solutions in Rust

feat: day 15 of AoC 2020

Brute-forcing part 2 sometimes works...

+101 -2
+99
aoc_2020/src/day15.rs
··· 1 + use std::{collections::HashMap, num::ParseIntError}; 2 + 3 + use aoc_companion::prelude::*; 4 + use itertools::Itertools as _; 5 + 6 + pub(crate) struct Door { 7 + starting_numbers: Vec<usize>, 8 + } 9 + 10 + impl<'input> Solution<'input> for Door { 11 + fn parse(input: &'input str) -> Result<Self, ParseIntError> { 12 + input 13 + .split(',') 14 + .map(str::parse) 15 + .try_collect() 16 + .map(|starting_numbers| Door { starting_numbers }) 17 + } 18 + 19 + fn part1(&self) -> usize { 20 + Game::from(self.starting_numbers.iter().copied()) 21 + .nth(2019) 22 + .unwrap() 23 + } 24 + 25 + fn part2(&self) -> usize { 26 + Game::from(self.starting_numbers.iter().copied()) 27 + .nth(29_999_999) 28 + .unwrap() 29 + } 30 + } 31 + 32 + struct Game<I: Iterator<Item = usize>> { 33 + starting_numbers: I, 34 + next: Option<usize>, 35 + n: usize, 36 + last_seen: HashMap<usize, usize>, 37 + } 38 + 39 + impl<I: Iterator<Item = usize>> Game<I> { 40 + fn from(starting_numbers: impl IntoIterator<Item = usize, IntoIter = I>) -> Self { 41 + Self { 42 + starting_numbers: starting_numbers.into_iter(), 43 + next: None, 44 + n: 0, 45 + last_seen: HashMap::new(), 46 + } 47 + } 48 + } 49 + 50 + impl<I: Iterator<Item = usize>> Iterator for Game<I> { 51 + type Item = usize; 52 + 53 + fn next(&mut self) -> Option<Self::Item> { 54 + let current = self.starting_numbers.next().or_else(|| self.next.take())?; 55 + self.n += 1; 56 + if let Some(before) = self.last_seen.insert(current, self.n) { 57 + self.next = Some(self.n - before); 58 + } else { 59 + self.next = Some(0); 60 + } 61 + Some(current) 62 + } 63 + } 64 + 65 + #[cfg(test)] 66 + mod tests { 67 + use super::*; 68 + 69 + #[test] 70 + fn example_game_number_sequence() { 71 + itertools::assert_equal( 72 + Game::from([0, 3, 6]).take(10), 73 + [0, 3, 6, 0, 3, 3, 1, 0, 4, 0], 74 + ); 75 + } 76 + 77 + #[test] 78 + fn correct_2020th_number() { 79 + assert_eq!(Game::from([0, 3, 6]).nth(2019), Some(436)); 80 + assert_eq!(Game::from([1, 3, 2]).nth(2019), Some(1)); 81 + assert_eq!(Game::from([2, 1, 3]).nth(2019), Some(10)); 82 + assert_eq!(Game::from([1, 2, 3]).nth(2019), Some(27)); 83 + assert_eq!(Game::from([2, 3, 1]).nth(2019), Some(78)); 84 + assert_eq!(Game::from([3, 2, 1]).nth(2019), Some(438)); 85 + assert_eq!(Game::from([3, 1, 2]).nth(2019), Some(1836)); 86 + } 87 + 88 + #[test] 89 + #[ignore = "slow"] 90 + fn correct_30_000_000th_number() { 91 + assert_eq!(Game::from([0, 3, 6]).nth(29_999_999), Some(175594)); 92 + assert_eq!(Game::from([1, 3, 2]).nth(29_999_999), Some(2578)); 93 + assert_eq!(Game::from([2, 1, 3]).nth(29_999_999), Some(3544142)); 94 + assert_eq!(Game::from([1, 2, 3]).nth(29_999_999), Some(261214)); 95 + assert_eq!(Game::from([2, 3, 1]).nth(29_999_999), Some(6895259)); 96 + assert_eq!(Game::from([3, 2, 1]).nth(29_999_999), Some(18)); 97 + assert_eq!(Game::from([3, 1, 2]).nth(29_999_999), Some(362)); 98 + } 99 + }
+2 -2
aoc_2020/src/main.rs
··· 14 14 mod day12; 15 15 mod day13; 16 16 mod day14; 17 - // mod day15; 17 + mod day15; 18 18 // mod day16; 19 19 // mod day17; 20 20 // mod day18; ··· 45 45 door!(2020-12-12 ~> day12), 46 46 door!(2020-12-13 ~> day13), 47 47 door!(2020-12-14 ~> day14), 48 - // door!(2020-12-15 ~> day15), 48 + door!(2020-12-15 ~> day15), 49 49 // door!(2020-12-16 ~> day16), 50 50 // door!(2020-12-17 ~> day17), 51 51 // door!(2020-12-18 ~> day18),