diff --git a/2017/rust/src/day_16.rs b/2017/rust/src/day_16.rs index 5bd0feb..14d0112 100644 --- a/2017/rust/src/day_16.rs +++ b/2017/rust/src/day_16.rs @@ -1,45 +1,82 @@ +use std::collections::HashMap; use std::convert::TryFrom; use failure::*; use regex::Regex; pub fn solve(input: &str) -> Result { // let input = "s1,x3/4,pe/b"; - let moves: Vec<_> = input + let moves = input .split(',') .map(Move::try_from) .collect::>()?; - let mut programs = (b'a'..=b'p').map(|c| c as char).collect::>(); - dance(&moves, &mut programs); - Ok(programs.iter().collect()) -} + let programs = (b'a'..=b'p').map(|c| c as char).collect(); + let dance = Dance { moves, programs }; -fn dance(moves: &[Move], programs: &mut [char]) { - for m in moves { - match m { - Move::Spin(size) => { - let len = programs.len(); - programs.rotate(len - size); - } - Move::Exchange(a, b) => { - programs.swap(*a, *b); + // dance.next(); + // Ok(dance.next().unwrap().iter().collect::()) + + let history = dance + .enumerate() + .scan(HashMap::new(), |state, (i, programs)| { + if state.contains_key(&programs) { + None + } else { + state.insert(programs, i); + Some(state.clone()) } - Move::Partner(a, b) => { - let a = programs.iter().position(|x| x == a).unwrap(); - let b = programs.iter().position(|x| x == b).unwrap(); - programs.swap(a, b); + }) + .last() + .unwrap(); + let index = 1_000_000_000 % history.len(); + Ok(history + .iter() + .find(|(_, &v)| v == &index) + .map(|(k, _)| k) + .unwrap() + .iter() + .collect()) +} + +struct Dance { + moves: Vec, + programs: Vec, +} + +impl Iterator for Dance { + type Item = Vec; + + fn next(&mut self) -> Option { + let item = self.programs.clone(); + + for m in &self.moves { + match m { + Move::Spin(size) => { + let len = self.programs.len(); + self.programs.rotate(len - size); + } + Move::Exchange(a, b) => { + self.programs.swap(*a, *b); + } + Move::Partner(a, b) => { + let a = self.programs.iter().position(|x| x == a).unwrap(); + let b = self.programs.iter().position(|x| x == b).unwrap(); + self.programs.swap(a, b); + } } } + + Some(item) } } #[test] fn test_dance() { let moves = vec![Move::Spin(1), Move::Exchange(3, 4), Move::Partner('e', 'b')]; - let mut programs: Vec<_> = (b'a'..=b'e').map(|c| c as char).collect(); - - dance(&moves, &mut programs); + let programs = (b'a'..=b'e').map(|c| c as char).collect(); + let mut dance = Dance { moves, programs }; - assert_eq!(programs, vec!['b', 'a', 'e', 'd', 'c']); + assert_eq!(dance.next().unwrap(), vec!['a', 'b', 'c', 'd', 'e']); + assert_eq!(dance.next().unwrap(), vec!['b', 'a', 'e', 'd', 'c']); } #[derive(Debug, Eq, PartialEq)]