use super::cost::min_pitch;
use super::graph::Axis;
use super::place;
use super::search::Deny;
use super::{Chain, World};
pub(crate) fn admits(
worlds: &[World],
committed: &[Option<Chain>],
candidate: &Chain,
k: usize,
clearance: f64,
) -> Option<Deny> {
let base = committed.len();
let mut all: Vec<Option<Chain>> = committed.to_vec();
all.extend(std::iter::repeat_with(|| Some(candidate.clone())).take(k.max(1)));
place::place(worlds, &mut all, clearance);
place::refresh_spans(&mut all);
let ord = |(ci, ri): (usize, usize)| {
all[ci].as_ref().expect("simulated chain").runs[ri]
.ord
.expect("simulation placed every run")
};
let of_candidate = |i: &place::Item| i.members.iter().any(|&(ci, _)| ci >= base);
let (_, by_axis) = place::collect(worlds, &all);
for (axis, mut items) in by_axis {
let axis = [Axis::H, Axis::V][axis as usize];
place::merge_fans(&mut items, &all);
for cluster in place::clusters_of(axis, items, worlds, clearance) {
let broken = (0..cluster.len()).find_map(|i| {
(i + 1..cluster.len()).find_map(|j| {
let (a, b) = (&cluster[i].0, &cluster[j].0);
let floor = place::owed(a, b, clearance, min_pitch(clearance));
let short = (ord(a.members[0]) - ord(b.members[0])).abs() + 1e-6 < floor;
short.then_some((i, j))
})
});
let Some((i, j)) = broken else { continue };
let item = [&cluster[i].0, &cluster[j].0]
.into_iter()
.find(|it| of_candidate(it))
.or_else(|| cluster.iter().map(|(it, _)| it).find(|it| of_candidate(it)));
return Some(match item {
Some(it) => (axis, it.chan, it.span),
None => {
let r = &candidate.runs[0];
(r.axis, r.chan, r.span)
}
});
}
}
None
}