use std::env; use std::io::BufReader; use std::io::BufRead; use std::fs::File; use std::process; // extern crate flame; #[macro_use] extern crate text_io; type Marble = u32; struct Circle { marbles: Vec, current_i: i32, n: i32 } impl Circle { fn get(&self, pos: i32) -> (i32, Marble) { // let _guard = flame::start_guard("get"); let n = self.marbles.len() as i32; let i = (pos % n + n) % n; (i, self.marbles[i as usize]) } fn set_current(&mut self, pos: i32) { // let _guard = flame::start_guard("set_current"); let i = (pos % self.n + self.n) % self.n; self.current_i = i; } fn get_current(&self) -> (i32, Marble) { // let _guard = flame::start_guard("get_current"); let cur = self.marbles[self.current_i as usize]; (self.current_i, cur) } fn go_around(&self, delta: i32) -> (i32, Marble) { // let _guard = flame::start_guard("go_around"); self.get(self.current_i as i32 + delta) } fn clockwise(&mut self, delta: i32) -> (i32, Marble) { // let _guard = flame::start_guard("clockwise"); self.go_around(delta) } fn counterclockwise(&mut self, delta: i32) -> (i32, Marble) { // let _guard = flame::start_guard("counterclockwise"); self.go_around(-delta) } fn insert(&mut self, pos: i32, marble: Marble) { // let _guard = flame::start_guard("insert"); let i = (pos % self.n + self.n) % self.n + 1; self.marbles.insert(i as usize, marble); self.n += 1; } fn remove(&mut self, pos: i32) { // let _guard = flame::start_guard("remove"); let (i, m) = self.get(pos); let (_cur_i, cur) = self.get_current(); if m == cur { panic!("Removed current marble!"); } self.marbles.remove(i as usize); self.n -= 1; } } fn build_circle() -> Circle { // let _guard = flame::start_guard("build_circle"); let init_marbles: Vec = vec![0; 1]; let circle = Circle { marbles: init_marbles, current_i: 0, n: 1 }; circle } fn print_state(circle: &Circle, turn: usize) { print!("[{}] ", turn); for marble in &circle.marbles { let (_cur_i, cur) = circle.get_current(); if &cur == marble { print!(" ({}) ", marble); } else { print!(" {} ", marble); } } print!("\n") } fn main() { let args: Vec = env::args().collect(); if args.len() != 2 { println!("Wrong number of arguments. Provide a file name and worker count."); process::exit(1); } let filename = &args[1]; println!("Using file {} as input.", filename); let f = match File::open(filename) { Ok(file) => file, Err(e) => { println!("Failed to open file {}. {:?}", filename, e); process::exit(1); } }; let file = BufReader::new(&f); let lines: Vec = file.lines() .map(|line| line.expect("Could not parse line.")) .collect(); assert_eq!(lines.len(), 1); let line = &lines[0]; let (player_count, marble_count): (usize, usize); scan!(line.bytes() => "{} players; last marble is worth {} points", player_count, marble_count); let mut scores: Vec = vec![0; player_count]; let mut circle = build_circle(); let mut turn: usize = 0; for marble in 1..(marble_count + 1) as Marble { if marble % 23 == 0 { scores[turn] += marble; let (rem_i, rem_m): (i32, Marble) = circle.counterclockwise(7); circle.remove(rem_i); scores[turn] += rem_m; let (new_cur_i, _new_cur) = circle.get(rem_i as i32); circle.set_current(new_cur_i); } else { let (clockwise_i, _clockwise_m) = circle.clockwise(1); circle.insert(clockwise_i, marble); circle.set_current(clockwise_i + 1); } // print_state(&circle, turn + 1); if marble % 1000 == 0 { let progress = 100.0 * (marble as f32) / marble_count as f32; println!("Debug: Progress: {} %, Processed {} / {}", progress, marble, marble_count); } turn = (turn + 1) % player_count; } let max_score: &u32 = scores.iter().max().expect("No scores in vector"); println!("Max score: {}", max_score); // flame::dump_html(&mut File::create("flame-graph.html").unwrap()).unwrap(); }