diff --git a/brood/src/commands/path.rs b/brood/src/commands/path.rs index d21ba95..4f58bb6 100644 --- a/brood/src/commands/path.rs +++ b/brood/src/commands/path.rs @@ -3,6 +3,7 @@ use std::io; use crate::{ algo::Dijkstra, data::Data, + graph::NodeIdx, util::{self, TitleNormalizer}, }; @@ -11,6 +12,46 @@ use crate::{ pub struct Cmd { start: String, goal: String, + + // Search for a path in both directions. + #[arg(long, short)] + bidi: bool, +} + +fn search_path(data: &Data, start: NodeIdx, goal: NodeIdx) -> Option<(u32, Vec)> { + println!("> Preparing dijkstra"); + let mut dijkstra = Dijkstra::new(&data.graph); + println!("> Running dijkstra"); + dijkstra.run( + start, + |node| node == goal, + |source, _edge, _target| !data.pages[source.usize()].redirect as u32, + ); + + if dijkstra.cost(goal) == u32::MAX { + return None; + } + + println!("> Collecting path"); + let cost = dijkstra.cost(goal); + let path = dijkstra.path(goal); + Some((cost, path)) +} + +fn print_path(data: &Data, start: NodeIdx, goal: NodeIdx, path: Option<(u32, Vec)>) { + let start = &data.pages[start.usize()].title; + let goal = &data.pages[goal.usize()].title; + + let Some((cost, path)) = path else { + println!("No path found from {start} to {goal}"); + return; + }; + + println!("Path found (cost {cost}, length {}):", path.len()); + + for page in path { + println!("{}", util::fmt_page(&data.pages[page.usize()])); + } } impl Cmd { @@ -23,29 +64,22 @@ impl Cmd { println!("Start: {}", data.pages[start.usize()].title); println!("Goal: {}", data.pages[goal.usize()].title); - println!(">> Find path"); - println!("> Preparing dijkstra"); - let mut dijkstra = Dijkstra::new(&data.graph); - println!("> Running dijkstra"); - dijkstra.run( - start, - |node| node == goal, - |source, _edge, _target| !data.pages[source.usize()].redirect as u32, - ); + if self.bidi { + println!(">> Find path forward"); + let forward = search_path(&data, start, goal); + println!(">> Find path backward"); + let backward = search_path(&data, goal, start); - if dijkstra.cost(goal) == u32::MAX { - println!("No path found"); - return Ok(()); - } + println!(); + print_path(&data, start, goal, forward); + println!(); + print_path(&data, goal, start, backward); + } else { + println!(">> Find path"); + let path = search_path(&data, start, goal); - println!("> Collecting path"); - let path = dijkstra.path(goal); - let cost = dijkstra.cost(goal); - - println!(); - println!("Path found (cost {cost}, length {}):", path.len()); - for page in path { - println!("{}", util::fmt_page(&data.pages[page.usize()])); + println!(); + print_path(&data, start, goal, path); } Ok(())