use crate::pins::PinSet;
#[derive(Debug, Clone)]
pub struct PinGeometry {
pin_count: u8,
adjacency: &'static [(u8, u8)],
}
impl PinGeometry {
pub const fn new(pin_count: u8, adjacency: &'static [(u8, u8)]) -> Self {
Self {
pin_count,
adjacency,
}
}
#[inline]
pub const fn pin_count(&self) -> u8 {
self.pin_count
}
pub fn is_split(&self, standing: PinSet) -> bool {
if standing.contains(0) {
return false;
}
if standing.count() < 2 {
return false;
}
let mut visited = PinSet::EMPTY;
let Some(start) = standing.iter().next() else {
return false;
};
let mut queue = PinSet::EMPTY.insert(start);
visited = visited.insert(start);
while let Some(current) = queue.iter().next() {
queue = queue.remove(current);
for &(a, b) in self.adjacency {
let neighbor = if a == current {
b
} else if b == current {
a
} else {
continue;
};
if standing.contains(neighbor) && !visited.contains(neighbor) {
visited = visited.insert(neighbor);
queue = queue.insert(neighbor);
}
}
}
(standing - visited).count() > 0
}
}
pub static TEN_PIN_GEOMETRY: PinGeometry = PinGeometry::new(
10,
&[
(0, 1),
(0, 2),
(1, 2),
(1, 3),
(1, 4),
(2, 4),
(2, 5),
(3, 4),
(4, 5),
(3, 6),
(3, 7),
(4, 7),
(4, 8),
(5, 8),
(5, 9),
(6, 7),
(7, 8),
(8, 9),
],
);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn classic_7_10_split() {
let standing = PinSet::of([6, 9]);
assert!(TEN_PIN_GEOMETRY.is_split(standing));
}
#[test]
fn adjacent_pins_not_a_split() {
let standing = PinSet::of([3, 4]);
assert!(!TEN_PIN_GEOMETRY.is_split(standing));
}
#[test]
fn head_pin_standing_never_split() {
let standing = PinSet::of([0, 6, 9]);
assert!(!TEN_PIN_GEOMETRY.is_split(standing));
}
#[test]
fn single_pin_not_a_split() {
let standing = PinSet::of([6]);
assert!(!TEN_PIN_GEOMETRY.is_split(standing));
}
#[test]
fn four_six_seven_ten_split() {
let standing = PinSet::of([3, 5, 6, 9]);
assert!(TEN_PIN_GEOMETRY.is_split(standing));
}
}