From 12c01293dae917862ae453fcff28668f9610d403 Mon Sep 17 00:00:00 2001 From: timeshifter Date: Sat, 4 Jul 2026 21:39:09 +0200 Subject: [PATCH] refactor day 11, large speedup --- day11/src/main.rs | 168 ++++++++++++++-------------------------------- 1 file changed, 50 insertions(+), 118 deletions(-) diff --git a/day11/src/main.rs b/day11/src/main.rs index ef156be..e7a8663 100644 --- a/day11/src/main.rs +++ b/day11/src/main.rs @@ -1,7 +1,4 @@ -use std::{ - cmp::Reverse, - collections::{BTreeSet, BinaryHeap, HashSet, VecDeque}, -}; +use std::collections::{HashSet, VecDeque}; use itertools::Itertools; @@ -24,37 +21,43 @@ fn part_1() { #[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] struct State { - floors: [BTreeSet; 4], + sorted_vec_of_pairs: Vec<(usize, usize)>, elevator: usize, } -#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -enum Item { - Generator(String), - Chip(String), -} - impl State { fn is_valid(&self) -> bool { - self.floors.iter().all(floor_is_valid) + self.sorted_vec_of_pairs + .iter() + .all(|(c, g)| c == g || self.sorted_vec_of_pairs.iter().all(|(_, g2)| c != g2)) } fn is_goal_state(&self) -> bool { self.elevator == 3 // fourth floor, off by one - && self.floors[0..=2].iter().all(|floor| floor.is_empty()) + && self.sorted_vec_of_pairs.iter().all(|pair| *pair == (3, 3)) } - fn move_candidates(&self) -> &BTreeSet { - &self.floors[self.elevator] + fn move_candidates(&self) -> Vec<(usize, bool)> { + let mut result = vec![]; + for (idx, (c, g)) in self.sorted_vec_of_pairs.iter().enumerate() { + if *c == self.elevator { + result.push((idx, true)) + }; + if *g == self.elevator { + result.push((idx, false)) + }; + } + result } - fn possible_moves(&self) -> impl Iterator> { + fn possible_moves(&self) -> impl Iterator> { let candidates = self.move_candidates(); candidates - .iter() + .clone() + .into_iter() .combinations(1) - .chain(candidates.iter().combinations(2)) + .chain(candidates.into_iter().combinations(2)) } fn possible_move_to_floors(&self) -> Vec { @@ -65,19 +68,21 @@ impl State { } } - fn apply_move(&self, movers: &[&Item], destination: usize) -> State { + fn apply_move(&self, movers: &[(usize, bool)], destination: usize) -> State { let mut result = self.clone(); - for mover in movers { - result.floors[result.elevator].remove(*mover); + for (idx, is_chip) in movers { + if *is_chip { + result.sorted_vec_of_pairs[*idx].0 = destination; + } else { + result.sorted_vec_of_pairs[*idx].1 = destination; + } } + result.sorted_vec_of_pairs.sort(); + result.elevator = destination; - for mover in movers { - result.floors[result.elevator].insert((*mover).clone()); - } - result } @@ -91,16 +96,14 @@ impl State { #[cfg(debug_assertions)] fn generate_start_state_1() -> Self { let mut result = Self { - floors: [const { BTreeSet::new() }; 4], + sorted_vec_of_pairs: vec![], elevator: 0, }; - result.floors[0].insert(Item::Chip("hydrogen".to_string())); - result.floors[0].insert(Item::Chip("lithium".to_string())); + result.sorted_vec_of_pairs.push((0, 1)); + result.sorted_vec_of_pairs.push((0, 2)); - result.floors[1].insert(Item::Generator("hydrogen".to_string())); - - result.floors[2].insert(Item::Generator("lithium".to_string())); + result.sorted_vec_of_pairs.sort(); result } @@ -108,78 +111,41 @@ impl State { #[cfg(not(debug_assertions))] fn generate_start_state_1() -> Self { let mut result = Self { - floors: [const { BTreeSet::new() }; 4], + sorted_vec_of_pairs: vec![], elevator: 0, }; - result.floors[0].insert(Item::Generator("promethium".to_string())); - result.floors[0].insert(Item::Chip("promethium".to_string())); + result.sorted_vec_of_pairs.push((0, 0)); - result.floors[1].insert(Item::Generator("cobalt".to_string())); - result.floors[1].insert(Item::Generator("curium".to_string())); - result.floors[1].insert(Item::Generator("ruthenium".to_string())); - result.floors[1].insert(Item::Generator("plutonium".to_string())); + result.sorted_vec_of_pairs.push((2, 1)); + result.sorted_vec_of_pairs.push((2, 1)); + result.sorted_vec_of_pairs.push((2, 1)); + result.sorted_vec_of_pairs.push((2, 1)); - result.floors[2].insert(Item::Chip("cobalt".to_string())); - result.floors[2].insert(Item::Chip("curium".to_string())); - result.floors[2].insert(Item::Chip("ruthenium".to_string())); - result.floors[2].insert(Item::Chip("plutonium".to_string())); + result.sorted_vec_of_pairs.sort(); result } fn generate_start_state_2() -> State { let mut result = Self { - floors: [const { BTreeSet::new() }; 4], + sorted_vec_of_pairs: vec![], elevator: 0, }; - result.floors[0].insert(Item::Generator("promethium".to_string())); - result.floors[0].insert(Item::Chip("promethium".to_string())); - result.floors[0].insert(Item::Generator("elerium".to_string())); - result.floors[0].insert(Item::Chip("elerium".to_string())); - result.floors[0].insert(Item::Generator("dilithium".to_string())); - result.floors[0].insert(Item::Chip("dilithium".to_string())); + result.sorted_vec_of_pairs.push((0, 0)); + result.sorted_vec_of_pairs.push((0, 0)); + result.sorted_vec_of_pairs.push((0, 0)); - result.floors[1].insert(Item::Generator("cobalt".to_string())); - result.floors[1].insert(Item::Generator("curium".to_string())); - result.floors[1].insert(Item::Generator("ruthenium".to_string())); - result.floors[1].insert(Item::Generator("plutonium".to_string())); + result.sorted_vec_of_pairs.push((2, 1)); + result.sorted_vec_of_pairs.push((2, 1)); + result.sorted_vec_of_pairs.push((2, 1)); + result.sorted_vec_of_pairs.push((2, 1)); - result.floors[2].insert(Item::Chip("cobalt".to_string())); - result.floors[2].insert(Item::Chip("curium".to_string())); - result.floors[2].insert(Item::Chip("ruthenium".to_string())); - result.floors[2].insert(Item::Chip("plutonium".to_string())); + result.sorted_vec_of_pairs.sort(); result } - - fn heuristic(&self) -> usize { - self.floors - .iter() - .take(3) - .rev() - .zip(1..=3) - .map(|(set, distance)| set.len() * distance) - .sum::() - / 2 - } -} - -fn floor_is_valid(floor: &BTreeSet) -> bool { - let mut generators = HashSet::new(); - let mut chips = HashSet::new(); - - for item in floor { - match item { - Item::Generator(name) => generators.insert(name.as_str()), - Item::Chip(name) => chips.insert(name.as_str()), - }; - } - - chips - .into_iter() - .all(|chip| generators.contains(chip) || generators.is_empty()) } fn bfs(start: State) -> usize { @@ -204,37 +170,3 @@ fn bfs(start: State) -> usize { } panic!("goal state unreachable"); } - -#[allow(dead_code)] -fn a_star(start: State) -> usize { - let mut heap: BinaryHeap<_> = BinaryHeap::new(); - - let mut visited = HashSet::new(); - - heap.push(Reverse((start.heuristic(), 0_usize, start))); - - while let Some(Reverse((_, distance, current_state))) = heap.pop() { - if visited.contains(¤t_state) { - continue; - } else { - visited.insert(current_state.clone()); - } - - if current_state.is_goal_state() { - return distance; - } - - for state in current_state.neighbors() { - if visited.contains(&state) { - continue; - } - - let heuristic = state.heuristic(); - let new_distance = distance + 1; - // f_score = g_score + h_score - // = distance + heuristic; - heap.push(Reverse((distance + heuristic, new_distance, state))); - } - } - panic!("goal state unreachable"); -}