use std::collections::VecDeque;
type Expanded<T> = Vec<T>;
pub struct BFTIterator<T: PartialEq + Copy, F: Fn(T) -> Expanded<T>> {
to_visit: VecDeque<T>,
visited: Vec<T>,
expand_f: F,
}
impl<T: PartialEq + Copy, F: Fn(T) -> Expanded<T>> BFTIterator<T, F> {
pub fn new(start: impl Iterator<Item = T>, expand_f: F) -> Self {
BFTIterator {
to_visit: start.collect(),
visited: Vec::new(),
expand_f,
}
}
}
impl<T: PartialEq + Copy, F: Fn(T) -> Expanded<T>> Iterator for BFTIterator<T, F> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
let next = self.to_visit.pop_front()?;
self.visited.push(next);
for to_append in (self.expand_f)(next) {
if !(self.visited.contains(&to_append) || self.to_visit.contains(&to_append)) {
self.to_visit.push_back(to_append);
}
}
Some(next)
}
}
#[cfg(test)]
mod tests {
use crate::show;
use super::*;
#[test]
fn test() {
let iter = BFTIterator::new(
[10].into_iter(),
Box::new(|u| {
match u {
0 => vec![],
n => vec![n - 1],
}
}),
);
assert_eq!(
show!(iter.collect::<Vec<usize>>()),
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
);
let iter = BFTIterator::new(
[10, 9, 8].into_iter(),
Box::new(|u| {
match u {
0 => vec![],
1 => vec![0],
n => vec![n - 1, n - 2],
}
}),
);
assert_eq!(
show!(iter.collect::<Vec<usize>>()),
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
);
let iter = BFTIterator::new(
[10, 9, 8].into_iter(),
Box::new(|u| {
match u {
1 => vec![],
n if n & 1 == 0 => vec![u >> 1],
n => vec![3 * n + 1],
}
}),
);
show!(iter.collect::<Vec<usize>>());
}
}