diff --git a/2018/inputs/14.txt b/2018/inputs/14.txt new file mode 100644 index 0000000..d19f4e4 --- /dev/null +++ b/2018/inputs/14.txt @@ -0,0 +1 @@ +637061 diff --git a/2018/src/common.rs b/2018/src/common.rs index 1e8f200..2892e8e 100644 --- a/2018/src/common.rs +++ b/2018/src/common.rs @@ -1,6 +1,8 @@ use std::collections::HashMap; use std::hash::Hash; use std::io; +use std::io::Read; +use std::str::FromStr; /// Apply Erathostenes's sieve to the supplied array /// @@ -50,6 +52,19 @@ pub fn trim_back(input: &mut Vec) { } } +/// Read the entire input as one value. +/// +/// This function loads the input into a string and then attempts to parse it. +pub fn read_single_input(input: &mut Read) -> T + where T: FromStr, + ::Err: std::fmt::Debug +{ + let mut buf = String::new(); + input.read_to_string(&mut buf).unwrap(); + + buf.trim().parse().unwrap() +} + /// An interface to count elements in particular categories. pub trait GroupingCount { diff --git a/2018/src/day14.rs b/2018/src/day14.rs index c2d5391..865ab09 100644 --- a/2018/src/day14.rs +++ b/2018/src/day14.rs @@ -1,6 +1,68 @@ use std::io::Read; use common::Solution; +use common::read_single_input; + +fn skill_after(n: usize) -> u64 { + let mut state = vec![3u8, 7]; + let mut elves = [0, 1]; + + while state.len() < n + 10 { + let result: u8 = elves.iter().map(|x| state[*x]).sum(); + if result >= 10 { + state.push(result / 10); + } + state.push(result % 10); + + for elf in elves.iter_mut() { + *elf = (*elf + state[*elf] as usize + 1) % state.len(); + } + } + + let mut skill = 0; + for d in state.into_iter().skip(n).take(10) { + skill *= 10; + skill += d as u64; + } + + skill +} + +fn update_current(mut current: usize, by: usize, base: usize) -> usize { + current *= 10; + current %= base; + current += by; + current +} + +fn find_first(n: usize, len: usize) -> usize { + println!("{} {}", n, len); + let mut state = vec![3u8, 7]; + let mut elves = [0, 1]; + let mut current = 37; + let mod_base = 10usize.pow(len as u32); + + loop { + let result: u8 = elves.iter().map(|x| state[*x]).sum(); + if result >= 10 { + current = update_current(current, result as usize / 10, mod_base); + if current == n { + return state.len() - 5; + } + state.push(result / 10); + } + current = update_current(current, result as usize % 10, mod_base); + if current == n { + return state.len() - 5 + 1; + } + state.push(result % 10); + + for elf in elves.iter_mut() { + *elf = (*elf + state[*elf] as usize + 1) % state.len(); + } + } +} + #[derive(Default)] pub struct Day14 {} @@ -12,14 +74,37 @@ impl Day14 { } impl Solution for Day14 { - fn part1(&mut self, _input: &mut Read) -> String { - unimplemented!() + fn part1(&mut self, input: &mut Read) -> String { + let input = read_single_input(input); + format!("{:010}", skill_after(input)) } - fn part2(&mut self, _input: &mut Read) -> String { - unimplemented!() + fn part2(&mut self, input: &mut Read) -> String { + let mut buf = String::new(); + input.read_to_string(&mut buf).unwrap(); + + let input = buf.trim().parse().unwrap(); + format!("{}", find_first(input, buf.trim().len())) } } #[cfg(test)] -mod tests {} +mod tests { + use super::*; + + #[test] + fn test_skill_after() { + assert_eq!(5158916779, skill_after(9)); + assert_eq!(124515891, skill_after(5)); + assert_eq!(9251071085, skill_after(18)); + assert_eq!(5941429882, skill_after(2018)); + } + + #[test] + fn test_find_first() { + assert_eq!(9, find_first(51589, 5)); + assert_eq!(5, find_first(1245, 5)); + assert_eq!(18, find_first(92510, 5)); + assert_eq!(2018, find_first(59414, 5)); + } +}