use std::io; use std::io::BufRead; use std::fmt; struct Chain { left: Vec, right: Vec, } impl Chain { fn new() -> Self { Chain { left: Vec::new(), right: Vec::new() } } fn redistribute(&mut self) { // println!("redistribute: left {}, right {}", self.left.len(), self.right.len()); let large; let small; if self.left.len() > self.right.len() { large = &mut self.left; small = &mut self.right; } else { large = &mut self.right; small = &mut self.left; } if large.len() == 0 { return; } let mut temp = Vec::new(); temp.append(small); // This seems fast in my tests, for some reason let denominator = 10; let nmoved = (large.len() * (denominator - 1) + denominator - 1) / denominator; for i in 0..nmoved { small.push(large[nmoved - 1 - i]); } large.splice(..nmoved, std::iter::empty()); small.append(&mut temp); // println!(" left {}, right {}", self.left.len(), self.right.len()); } fn rot_left(&mut self) { if self.left.len() + self.right.len() == 0 { return; } if self.left.len() == 0 { self.redistribute(); } self.right.push(*self.left.last().unwrap()); self.left.pop(); } fn rot_right(&mut self) { if self.left.len() + self.right.len() == 0 { return; } if self.right.len() == 0 { self.redistribute(); } self.left.push(*self.right.last().unwrap()); self.right.pop(); } fn current(&self) -> T { if self.left.len() == 0 { *self.right.first().unwrap() } else { *self.left.last().unwrap() } } fn rotate(&mut self, amt: i32) { if amt < 0 { for _ in 0..-amt { self.rot_left(); } } else { for _ in 0..amt { self.rot_right(); } } } fn insert_after(&mut self, val: T) { self.left.push(val); } #[used] fn insert_before(&mut self, val: T) { if self.left.len() == 0 { if self.right.len() == 0 { self.left.push(val); return; } self.redistribute(); } self.left.insert(self.left.len() - 1, val); } fn remove_current(&mut self) { if self.left.len() == 0 { self.right.remove(0); } else { self.left.pop(); } } } impl fmt::Display for Chain { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.left.len() == 0 { if self.right.len() == 0 { return Ok(()); } write!(f, "({})", self.right[0])?; for i in 0..self.right.len()-1 { write!(f, " {}", self.right[self.right.len() - 1 - i])?; } } else { for val in self.left.iter().take(self.left.len() - 1) { write!(f, "{} ", val)?; } write!(f, "({})", self.left.last().unwrap())?; for i in 0..self.right.len() { write!(f, " {}", self.right[self.right.len() - 1 - i])?; } } Ok(()) } } fn simulate(nplayers: i64, lastmarble: i64) -> i64 { let mut scores = vec![0; nplayers as usize]; let mut chain: Chain = Chain::new(); chain.insert_after(0); // println!("{}", chain); for marble in 1..lastmarble+1 { if marble % 23 != 0 { chain.rotate(1); chain.insert_after(marble); } else { scores[(marble % nplayers) as usize] += marble; chain.rotate(-7); scores[(marble % nplayers) as usize] += chain.current(); chain.remove_current(); chain.rotate(1); } // println!("{}", chain); } *scores.iter().max().unwrap() } pub fn main(reader: T) -> io::Result<(String, String)> { let input = reader.lines().next().unwrap().unwrap(); let input_split: Vec<&str> = input.split(' ').collect(); let nplayers: i64 = input_split[0].parse().unwrap(); let lastmarble: i64 = input_split[6].parse().unwrap(); let part1 = simulate(nplayers, lastmarble).to_string(); let part2 = simulate(nplayers, lastmarble * 100).to_string(); Ok((part1, part2)) }