diff --git a/inputs/14.txt b/inputs/14.txt new file mode 100644 index 0000000..4890eb7 --- /dev/null +++ b/inputs/14.txt @@ -0,0 +1 @@ +236021 diff --git a/src/day13.rs b/src/day13.rs index e4ad8f1..0d47b84 100644 --- a/src/day13.rs +++ b/src/day13.rs @@ -1,5 +1,3 @@ -extern crate regex; - use std::collections::{HashMap, HashSet}; use std::error::Error; use std::fs; diff --git a/src/day14.rs b/src/day14.rs new file mode 100644 index 0000000..7142cbf --- /dev/null +++ b/src/day14.rs @@ -0,0 +1,249 @@ +use std::error::Error; +use std::fmt; +use std::fs; +use std::result; + +type Result = result::Result>; + +const INPUT: &str = "inputs/14.txt"; + +#[derive(Debug, PartialEq)] +struct Recipes { + scores: Vec, + elf1_index: usize, + elf2_index: usize, +} + +impl fmt::Display for Recipes { + #[allow(clippy::write_with_newline)] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for (index, score) in self.scores.iter().enumerate() { + if index == self.elf1_index { + write!(f, "({})", score)?; + } else if index == self.elf2_index { + write!(f, "[{}]", score)?; + } else { + write!(f, " {} ", score)?; + } + } + write!(f, "\n")?; + Ok(()) + } +} + +impl Recipes { + fn new() -> Recipes { + Recipes { + scores: vec![3, 7], + elf1_index: 0, + elf2_index: 1, + } + } + + fn new_recipes(&mut self) { + let elf1_score = self.scores[self.elf1_index]; + let elf2_score = self.scores[self.elf2_index]; + let sum = elf1_score + elf2_score; + fn push_digits(n: u8, digits: &mut Vec) { + if n >= 10 { + push_digits(n / 10, digits); + } + digits.push(n % 10); + } + push_digits(sum, &mut self.scores); + } + + fn pick_recipes(&mut self) { + let elf1_score = self.scores[self.elf1_index]; + let elf2_score = self.scores[self.elf2_index]; + self.elf1_index = (self.elf1_index + (1 + elf1_score as usize)) % self.scores.len(); + self.elf2_index = (self.elf2_index + (1 + elf2_score as usize)) % self.scores.len(); + } + + fn scores_after_n_recipes(&mut self, n: usize, num_scores: usize) -> String { + while self.scores.len() < n + num_scores { + self.new_recipes(); + self.pick_recipes(); + } + self.scores[n..n + num_scores].iter().map(|score| format!("{}", score)).collect() + } + + fn find_index_of_sequence(&mut self, seq: &[u8]) -> usize { + let seq_len = seq.len(); + loop { + let scores_len = self.scores.len(); + self.new_recipes(); + self.pick_recipes(); + let new_scores_len = self.scores.len(); + let diff = new_scores_len - scores_len; + if scores_len >= seq_len { + for i in 0..diff { + let seq_index = scores_len + i - seq_len; + if &self.scores[seq_index..(seq_index + seq_len)] == seq { + return seq_index; + } + } + } + } + } +} + +fn digit_seq(n: &str) -> Vec { + let mut digits: Vec = vec![]; + for digit in n.chars() { + digits.push(digit.to_digit(10).unwrap() as u8); + } + digits +} + +fn read_input_file(filename: &str) -> Result { + let input = fs::read_to_string(filename)?; + Ok(input.trim().parse()?) +} + +pub fn solve_part1() -> Result { + let input = read_input_file(INPUT)?; + let mut recipes = Recipes::new(); + Ok(recipes.scores_after_n_recipes(input, 10)) +} + +pub fn solve_part2() -> Result { + let input = fs::read_to_string(INPUT)?; + let mut recipes = Recipes::new(); + let seq = digit_seq(&input.trim()); + Ok(recipes.find_index_of_sequence(&seq[..])) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn creates_new_recipes_struct() { + let recipes = Recipes::new(); + assert_eq!(recipes.scores, vec![3, 7]); + assert_eq!(recipes.elf1_index, 0); + assert_eq!(recipes.elf2_index, 1); + } + + #[test] + fn adds_new_recipes() { + let mut recipes = Recipes::new(); + recipes.new_recipes(); + assert_eq!(recipes.scores, vec![3, 7, 1, 0]); + } + + #[test] + fn picks_new_recipes() { + let mut recipes = Recipes::new(); + recipes.new_recipes(); + recipes.pick_recipes(); + assert_eq!(recipes.elf1_index, 0); + assert_eq!(recipes.elf2_index, 1); + } + + #[test] + fn iterates_15_times() { + let mut recipes = Recipes::new(); + for _ in 0..15 { + recipes.new_recipes(); + recipes.pick_recipes(); + } + assert_eq!( + format!("{}", recipes), + " 3 7 1 0 [1] 0 1 2 (4) 5 1 5 8 9 1 6 7 7 9 2 \n", + ); + } + + #[test] + fn scores_after_5_recipes() { + let mut recipes = Recipes::new(); + assert_eq!( + recipes.scores_after_n_recipes(5, 10), + "0124515891", + ); + } + + #[test] + fn scores_after_9_recipes() { + let mut recipes = Recipes::new(); + assert_eq!( + recipes.scores_after_n_recipes(9, 10), + "5158916779", + ); + } + + #[test] + fn scores_after_18_recipes() { + let mut recipes = Recipes::new(); + assert_eq!( + recipes.scores_after_n_recipes(18, 10), + "9251071085", + ); + } + + #[test] + fn scores_after_2018_recipes() { + let mut recipes = Recipes::new(); + assert_eq!( + recipes.scores_after_n_recipes(2018, 10), + "5941429882", + ); + } + + #[test] + fn finds_index_of_sequence_1() { + let mut recipes = Recipes::new(); + let seq = vec![5, 1, 5, 8, 9]; + assert_eq!( + recipes.find_index_of_sequence(&seq[..]), + 9, + ); + } + + #[test] + fn finds_index_of_sequence_2() { + let mut recipes = Recipes::new(); + let seq = vec![0, 1, 2, 4, 5]; + assert_eq!( + recipes.find_index_of_sequence(&seq[..]), + 5, + ); + } + + #[test] + fn finds_index_of_sequence_3() { + let mut recipes = Recipes::new(); + let seq = vec![9, 2, 5, 1, 0]; + assert_eq!( + recipes.find_index_of_sequence(&seq[..]), + 18, + ); + } + + #[test] + fn finds_index_of_sequence_4() { + let mut recipes = Recipes::new(); + let seq = vec![5, 9, 4, 1, 4]; + assert_eq!( + recipes.find_index_of_sequence(&seq[..]), + 2018, + ); + } + + #[test] + fn gets_digit_seq_1() { + assert_eq!( + digit_seq("51589"), + vec![5, 1, 5, 8, 9], + ); + } + + #[test] + fn gets_digit_seq_2() { + assert_eq!( + digit_seq("01245"), + vec![0, 1, 2, 4, 5], + ); + } +} diff --git a/src/main.rs b/src/main.rs index 0f57f7f..f1c97da 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,6 +16,7 @@ mod day10; mod day11; mod day12; mod day13; +mod day14; fn main() { // println!("Day 1:"); @@ -57,9 +58,12 @@ fn main() { // println!("Day 12:"); // println!("{}", day12::solve_part1().unwrap()); // println!("{}", day12::solve_part2().unwrap()); - println!("Day 13"); - let part1 = day13::solve_part1().unwrap(); - println!("{},{}", part1.x, part1.y); - let part2 = day13::solve_part2().unwrap(); - println!("{},{}", part2.x, part2.y); + // println!("Day 13"); + // let part1 = day13::solve_part1().unwrap(); + // println!("{},{}", part1.x, part1.y); + // println!("{},{}", part2.x, part2.y); + // let part2 = day13::solve_part2().unwrap(); + println!("Day 14"); + println!("{}", day14::solve_part1().unwrap()); + println!("{}", day14::solve_part2().unwrap()); }