day 8 part 2 dp
This commit is contained in:
parent
40b252e393
commit
094d48df84
1 changed files with 112 additions and 88 deletions
200
src/bin/day8.rs
200
src/bin/day8.rs
|
@ -1,18 +1,9 @@
|
||||||
#![forbid(elided_lifetimes_in_paths)]
|
#![forbid(elided_lifetimes_in_paths, unsafe_code)]
|
||||||
|
|
||||||
use aoc23::read;
|
use aoc23::read;
|
||||||
use chumsky::prelude::*;
|
use chumsky::prelude::*;
|
||||||
use std::{
|
use std::collections::{HashMap, HashSet, VecDeque};
|
||||||
collections::{HashMap, HashSet},
|
|
||||||
sync::{
|
|
||||||
atomic::{AtomicBool, Ordering},
|
|
||||||
Mutex
|
|
||||||
},
|
|
||||||
thread,
|
|
||||||
time::Duration
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
enum Instruction {
|
enum Instruction {
|
||||||
Left,
|
Left,
|
||||||
Right
|
Right
|
||||||
|
@ -27,7 +18,7 @@ impl Instruction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Debug)]
|
||||||
struct Node {
|
struct Node {
|
||||||
left: String,
|
left: String,
|
||||||
right: String
|
right: String
|
||||||
|
@ -51,7 +42,7 @@ impl Node {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Debug)]
|
||||||
struct Network {
|
struct Network {
|
||||||
nodes: HashMap<String, Node>
|
nodes: HashMap<String, Node>
|
||||||
}
|
}
|
||||||
|
@ -92,15 +83,93 @@ fn parser() -> impl Parser<char, (Vec<Instruction>, Network), Error = Simple<cha
|
||||||
.then_ignore(end())
|
.then_ignore(end())
|
||||||
}
|
}
|
||||||
|
|
||||||
static STOP: AtomicBool = AtomicBool::new(false);
|
#[derive(Copy, Clone, Debug)]
|
||||||
static mut RESULTS: Vec<Mutex<Vec<usize>>> = Vec::new();
|
struct Ghost<'a> {
|
||||||
|
node: &'a str,
|
||||||
|
i: usize,
|
||||||
|
steps: u128
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Ghost<'a> {
|
||||||
|
fn new(node: &'a str) -> Self {
|
||||||
|
Self {
|
||||||
|
node,
|
||||||
|
i: 0,
|
||||||
|
steps: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn advance(&mut self, ghost: Ghost<'a>) {
|
||||||
|
self.node = ghost.node;
|
||||||
|
self.i = ghost.i;
|
||||||
|
self.steps += ghost.steps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
let (instructions, network) = read("inputs/day8.txt", parser())?;
|
let (instructions, network) = read("inputs/day8.txt", parser())?;
|
||||||
|
|
||||||
|
// build a lookup map of left/right predecessors
|
||||||
|
let mut left_pred: HashMap<&str, Vec<&str>> = HashMap::new();
|
||||||
|
let mut right_pred: HashMap<&str, Vec<&str>> = HashMap::new();
|
||||||
|
for (node, next) in &network.nodes {
|
||||||
|
left_pred.entry(&next.left).or_default().push(node);
|
||||||
|
right_pred.entry(&next.right).or_default().push(node);
|
||||||
|
}
|
||||||
|
eprintln!("Built pred lookup map");
|
||||||
|
|
||||||
|
// build a lookup map from instruction position and node with the length to the next
|
||||||
|
// finish node
|
||||||
|
let mut dp: HashMap<(&str, usize), Ghost<'_>> = HashMap::new();
|
||||||
|
let mut q: VecDeque<(&str, usize)> = VecDeque::new();
|
||||||
|
for node in network
|
||||||
|
.nodes
|
||||||
|
.keys()
|
||||||
|
.map(|node| node.as_str())
|
||||||
|
.filter(|node| node.ends_with('Z'))
|
||||||
|
{
|
||||||
|
for i in 0 .. instructions.len() {
|
||||||
|
dp.insert((node, i), Ghost { node, i, steps: 0 });
|
||||||
|
q.push_back((node, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while let Some((node, i)) = q.pop_front() {
|
||||||
|
let ghost = dp[&(node, i)];
|
||||||
|
let i_pred = match i {
|
||||||
|
0 => instructions.len() - 1,
|
||||||
|
i => i - 1
|
||||||
|
};
|
||||||
|
let pred = match instructions[i_pred] {
|
||||||
|
Instruction::Left => left_pred.get(node),
|
||||||
|
Instruction::Right => right_pred.get(node)
|
||||||
|
};
|
||||||
|
for node_pred in pred.into_iter().flatten() {
|
||||||
|
let new = (*node_pred, i_pred);
|
||||||
|
#[allow(clippy::map_entry)] // lint is opinionated garbage
|
||||||
|
if !dp.contains_key(&new) {
|
||||||
|
dp.insert(new, Ghost {
|
||||||
|
node: ghost.node,
|
||||||
|
i: ghost.i,
|
||||||
|
steps: ghost.steps + 1
|
||||||
|
});
|
||||||
|
q.push_back(new);
|
||||||
|
if dp.len() % 1_000_000 == 0 {
|
||||||
|
dbg!(dp.len());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ghost.steps == 0 {
|
||||||
|
dp.remove(&(node, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eprintln!("Built ghost lookup map");
|
||||||
|
// for (key, value) in &dp {
|
||||||
|
// eprintln!("\t{key:?}\t = \t{value:?}");
|
||||||
|
// }
|
||||||
|
|
||||||
// let mut curr_node = "AAA";
|
// let mut curr_node = "AAA";
|
||||||
// let mut i = 0;
|
// let mut i = 0;
|
||||||
// let mut steps = 0;
|
// let mut steps = 0_u128;
|
||||||
// while curr_node != "ZZZ" {
|
// while curr_node != "ZZZ" {
|
||||||
// curr_node = match instructions[i] {
|
// curr_node = match instructions[i] {
|
||||||
// Instruction::Left => network.left(curr_node),
|
// Instruction::Left => network.left(curr_node),
|
||||||
|
@ -111,84 +180,39 @@ fn main() -> anyhow::Result<()> {
|
||||||
// }
|
// }
|
||||||
// println!("{steps}");
|
// println!("{steps}");
|
||||||
|
|
||||||
let curr_nodes: HashSet<&str> = network
|
let mut ghosts: Vec<Ghost<'_>> = network
|
||||||
.nodes
|
.nodes
|
||||||
.keys()
|
.keys()
|
||||||
.map(|node| node.as_str())
|
|
||||||
.filter(|node| node.ends_with('A'))
|
.filter(|node| node.ends_with('A'))
|
||||||
|
.map(|node| Ghost::new(node))
|
||||||
.collect();
|
.collect();
|
||||||
dbg!(curr_nodes.len());
|
let mut progress = 0;
|
||||||
|
loop {
|
||||||
for (thread_index, node) in curr_nodes
|
if ghosts[0].steps > 0
|
||||||
.iter()
|
&& ghosts
|
||||||
.map(|node| String::from(*node))
|
.iter()
|
||||||
.enumerate()
|
.skip(1)
|
||||||
{
|
.all(|ghost| ghost.steps == ghosts[0].steps)
|
||||||
unsafe {
|
{
|
||||||
RESULTS.push(Mutex::new(Vec::new()));
|
println!("{}", ghosts[0].steps);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
let network = network.clone();
|
|
||||||
let instructions = instructions.clone();
|
|
||||||
thread::spawn(move || {
|
|
||||||
let mut curr_node = node.as_str();
|
|
||||||
let mut i = 0;
|
|
||||||
let mut steps = 0;
|
|
||||||
while !STOP.load(Ordering::Relaxed) {
|
|
||||||
curr_node = match instructions[i] {
|
|
||||||
Instruction::Left => network.left(curr_node),
|
|
||||||
Instruction::Right => network.right(curr_node)
|
|
||||||
};
|
|
||||||
i = (i + 1) % instructions.len();
|
|
||||||
steps += 1;
|
|
||||||
if steps % 1_000_000 == 0 {
|
|
||||||
dbg!(steps);
|
|
||||||
}
|
|
||||||
if curr_node.ends_with('Z') {
|
|
||||||
unsafe {
|
|
||||||
RESULTS[thread_index].lock().unwrap().push(steps);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
'outer: loop {
|
|
||||||
thread::sleep(Duration::from_secs(1));
|
|
||||||
unsafe {
|
|
||||||
let res0 = RESULTS[0].lock().unwrap();
|
|
||||||
'i: for i in 0 .. res0.len() {
|
|
||||||
't: for t in 1 .. RESULTS.len() {
|
|
||||||
let rest = RESULTS[t].lock().unwrap();
|
|
||||||
for j in 0 .. rest.len() {
|
|
||||||
if res0[i] == rest[j] {
|
|
||||||
continue 't;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue 'i;
|
|
||||||
}
|
|
||||||
println!("{}", res0[i]);
|
|
||||||
STOP.store(true, Ordering::Relaxed);
|
|
||||||
break 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// let mut i = 0;
|
let (ghost_index, ghost) = ghosts
|
||||||
// let mut steps = 0;
|
.iter()
|
||||||
// while curr_nodes.iter().any(|node| !node.ends_with('Z')) {
|
.enumerate()
|
||||||
// curr_nodes = curr_nodes
|
.min_by_key(|(_, ghost)| ghost.steps)
|
||||||
// .into_iter()
|
.unwrap();
|
||||||
// .map(|node| match instructions[i] {
|
if ghost.steps - progress >= 1_000_000_000_000 {
|
||||||
// Instruction::Left => network.left(node),
|
progress = ghost.steps;
|
||||||
// Instruction::Right => network.right(node)
|
eprintln!("progress: {progress}");
|
||||||
// })
|
}
|
||||||
// .collect();
|
|
||||||
// i = (i + 1) % instructions.len();
|
// eprint!("{ghost:?}\t -> \t");
|
||||||
// steps += 1;
|
let ghost = dp[&(ghost.node, ghost.i)];
|
||||||
// if steps % 10000 == 0 {
|
// eprintln!("{ghost:?}");
|
||||||
// dbg!(steps);
|
ghosts[ghost_index].advance(ghost);
|
||||||
// }
|
}
|
||||||
// }
|
|
||||||
// println!("{steps}");
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue