From ebe061adc0516b43745a402fabc5f6d2bde0b029 Mon Sep 17 00:00:00 2001 From: Adam Wick Date: Wed, 23 Dec 2020 20:35:04 -0800 Subject: [PATCH] Day 23; implementing a linked list on top of an array. --- src/bin/crab_cups.rs | 191 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 src/bin/crab_cups.rs diff --git a/src/bin/crab_cups.rs b/src/bin/crab_cups.rs new file mode 100644 index 0000000..feee24a --- /dev/null +++ b/src/bin/crab_cups.rs @@ -0,0 +1,191 @@ +use advent2020::errors::TopLevelError; +use std::fmt; +use std::time::SystemTime; + +#[derive(Clone)] +struct CupSlot { + value: usize, + next: usize, +} + +impl CupSlot { + fn blank() -> CupSlot { + CupSlot { value: 0, next: 0 } + } +} + +struct CupGame { + // this is a slightly wacky encoding; element 0 tells you which number + // comes first, the rest of the elements tell you which number comes + // after the indexed one. So mappings[1] tells you which number comes + // after the element 1 in the list. + nodes: Vec, + value_indices: Vec, + round: usize, + current_cup: usize, + maximum_value: usize, +} + +impl CupGame { + fn new(problem_size: usize, initial_cups: &[usize]) -> CupGame { + let mut nodes = vec![CupSlot::blank(); problem_size + 1]; + let mut value_indices = vec![0; problem_size + 1]; + let mut previous = 0; + let mut current = 1; + let mut maximum_value = 0; + + for value in initial_cups.iter() { + nodes[current].value = *value; + value_indices[*value] = current; + nodes[previous].next = current; + if value > &maximum_value { + maximum_value = *value; + } + previous = current; + current += 1; + } + + while current <= problem_size { + maximum_value += 1; + value_indices[maximum_value] = current; + nodes[previous].next = current; + nodes[current].value = maximum_value; + previous = current; + current += 1; + } + + nodes[previous].next = 1; + + CupGame { + nodes, + value_indices, + maximum_value, + round: 1, + current_cup: 1, + } + } + + fn pull_next(&mut self) -> (usize, usize, usize) { + let a_idx = self.nodes[self.current_cup].next; + let b_idx = self.nodes[a_idx].next; + let c_idx = self.nodes[b_idx].next; + + self.nodes[self.current_cup].next = self.nodes[c_idx].next; + + (a_idx, b_idx, c_idx) + } + + fn destination_cup(&self, pulled: &(usize, usize, usize)) -> usize { + let mut proposed_value = self.nodes[self.current_cup].value; + let (a_idx, b_idx, c_idx) = pulled; + let a = self.nodes[*a_idx].value; + let b = self.nodes[*b_idx].value; + let c = self.nodes[*c_idx].value; + + loop { + if proposed_value == 1 { + proposed_value = self.maximum_value; + } else { + proposed_value -= 1; + } + + if (proposed_value != a) && (proposed_value != b) && (proposed_value != c) { + return proposed_value; + } + } + } + + fn reinject(&mut self, at_value: usize, pulled: (usize, usize, usize)) { + let (a_idx, b_idx, c_idx) = pulled; + let idx = self.value_indices[at_value]; + + self.nodes[a_idx].next = b_idx; + self.nodes[b_idx].next = c_idx; + self.nodes[c_idx].next = self.nodes[idx].next; + self.nodes[idx].next = a_idx; + } + + fn run_round(&mut self) { + let pull = self.pull_next(); + let destination_cup = self.destination_cup(&pull); + self.reinject(destination_cup, pull); + self.current_cup = self.nodes[self.current_cup].next; + self.round += 1; + } + + fn part1_answer(&self) -> String { + let idx = self.value_indices[1]; + let mut retval = String::new(); + let mut work = self.nodes[idx].next; + + while self.nodes[work].value != 1 { + retval.push_str(format!("{}", self.nodes[work].value).as_str()); + work = self.nodes[work].next; + } + + retval + } + + fn part2_answer(&self) -> usize { + let idx = self.value_indices[1]; + let a_idx = self.nodes[idx].next; + let b_idx = self.nodes[a_idx].next; + let a = self.nodes[a_idx].value; + let b = self.nodes[b_idx].value; + println!("{} * {} = {}", a, b, a * b); + a * b + } +} + +impl fmt::Display for CupGame { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Round {}: ", self.round)?; + let mut idx = self.current_cup; + let first_value = self.nodes[idx].value; + + write!(f, "({}) ", first_value)?; + idx = self.nodes[idx].next; + while self.nodes[idx].value != first_value { + write!(f, "{} ", self.nodes[idx].value)?; + idx = self.nodes[idx].next; + } + + Ok(()) + } +} + +fn main() -> Result<(), TopLevelError> { + let initial_cups = &[3, 6, 8, 1, 9, 5, 7, 4, 2]; + let mut game = CupGame::new(9, initial_cups); + + for _ in 0..100 { + println!("{}", game); + game.run_round(); + } + println!("Part 1 answer: {:?}", game.part1_answer()); + + let start_time = SystemTime::now(); + let mut last_chunk = start_time; + let mut game2 = CupGame::new(1_000_000, initial_cups); + for i in 0..10_000_000 - 100 { + if i % 1_000_000 == 0 { + let now = SystemTime::now(); + let since_start = now.duration_since(start_time).unwrap().as_secs(); + let since_last = now.duration_since(last_chunk).unwrap().as_secs(); + + println!( + "Round {}: {}m{}s since start, {}m{}s for this chunk", + i, + since_start / 60, + since_start % 60, + since_last / 60, + since_last % 60 + ); + last_chunk = now; + } + game2.run_round(); + } + println!("Part 2 answer: {}", game2.part2_answer()); + + Ok(()) +}