134 lines
4.2 KiB
Rust
134 lines
4.2 KiB
Rust
---cargo
|
|
[profile.dev]
|
|
opt-level = 3
|
|
---
|
|
|
|
use std::collections::{HashMap, hash_map::Entry};
|
|
|
|
static CONTENT: &'static str = include_str!("./inputs/10_1.txt");
|
|
|
|
#[derive(Debug)]
|
|
struct Machine {
|
|
desired_lights: u64,
|
|
buttons: Vec<u64>,
|
|
}
|
|
|
|
fn main() {
|
|
let machines: Vec<Machine> = CONTENT.lines()
|
|
.map(|l| l.trim())
|
|
.map(|l| {
|
|
let (lights, rest) = l.split_once(' ').unwrap();
|
|
let buttons: Vec<_> = rest.split(' ').take_while(|p| p.contains('(')).collect();
|
|
let joltage = rest.split(' ').skip_while(|p| p.contains('(')).next().unwrap();
|
|
|
|
(lights, buttons, joltage)
|
|
})
|
|
.map(|(raw_lights, raw_buttons, raw_joltage)| {
|
|
let raw_lights = raw_lights.strip_prefix('[').unwrap().strip_suffix(']').unwrap();
|
|
|
|
let lights = raw_lights.chars().enumerate().map(|(idx, c)| {
|
|
let v = match c {
|
|
'.' => 0,
|
|
'#' => 1,
|
|
c => unreachable!("{:?}", c),
|
|
};
|
|
(idx, v)
|
|
}).fold(0u64, |acc, (idx, v)| {
|
|
acc + (v << idx)
|
|
});
|
|
|
|
(lights, raw_buttons, raw_joltage)
|
|
})
|
|
.map(|(lights, raw_buttons, raw_joltage)| {
|
|
let buttons: Vec<_> = raw_buttons.iter().map(|button| {
|
|
let button = button.strip_prefix('(').unwrap().strip_suffix(')').unwrap();
|
|
|
|
let switch: u64 = button.split(',').map(|c| {
|
|
let v: u64 = c.parse().unwrap();
|
|
1 << v
|
|
}).fold(0u64, |acc, v| {
|
|
acc + v
|
|
});
|
|
|
|
switch
|
|
}).collect();
|
|
|
|
(lights, buttons, raw_joltage)
|
|
})
|
|
.map(|(lights, buttons, _)| {
|
|
Machine {
|
|
desired_lights: lights,
|
|
buttons,
|
|
}
|
|
})
|
|
.collect();
|
|
|
|
println!("{:#?}", machines);
|
|
|
|
let machine_states: Vec<_> = machines.iter().map(|machine| {
|
|
let mut states: HashMap<u64, Vec<u64>> = HashMap::new();
|
|
let mut queue = vec![0u64];
|
|
while let Some(state) = queue.pop() {
|
|
let new_states: Vec<_> = machine.buttons.iter()
|
|
.map(|button| {
|
|
state ^ button
|
|
}).collect();
|
|
|
|
match states.entry(state) {
|
|
Entry::Occupied(_) => {}
|
|
Entry::Vacant(ventry) => {
|
|
let new_states = ventry.insert(new_states);
|
|
queue.extend(new_states.iter().map(|v| *v));
|
|
}
|
|
};
|
|
}
|
|
|
|
states
|
|
}).collect();
|
|
|
|
let distances: Vec<_> = machine_states.iter().map(|states| {
|
|
let mut distances: HashMap<u64, (Option<u64>, usize)> = states.keys().map(|node| {
|
|
(*node, (None, usize::MAX))
|
|
}).collect();
|
|
let mut q: Vec<u64> = states.keys().copied().collect();
|
|
distances.insert(0, (None, 0));
|
|
|
|
while !q.is_empty() {
|
|
q.sort_by_key(|n| core::cmp::Reverse(distances.get(n).map(|(_, d)| d).unwrap()));
|
|
let u = q.pop().unwrap();
|
|
|
|
let (_, u_distance) = distances.get(&u).copied().unwrap();
|
|
|
|
for neighbour in states.get(&u).unwrap() {
|
|
if !q.contains(neighbour) {
|
|
continue;
|
|
}
|
|
|
|
let new_distance = u_distance.saturating_add(1);
|
|
let (neighbour_prev, neighbour_distance) = distances.get_mut(&neighbour).unwrap();
|
|
|
|
if new_distance < *neighbour_distance {
|
|
*neighbour_prev = Some(u);
|
|
*neighbour_distance = new_distance;
|
|
}
|
|
}
|
|
}
|
|
|
|
distances
|
|
}).collect();
|
|
|
|
let mut total_steps = 0;
|
|
for ((machine, states), distances) in machines.iter().zip(machine_states.iter()).zip(distances.iter()) {
|
|
println!("{:#?}", machine);
|
|
//println!("States:\n{:#?}", states);
|
|
//println!("Distances: {:#?}", distances);
|
|
|
|
let (_, steps) = distances.get(&machine.desired_lights).unwrap();
|
|
println!("Required Steps: {}", steps);
|
|
|
|
total_steps += steps;
|
|
}
|
|
|
|
println!("Required Total Steps: {}", total_steps);
|
|
}
|